算法题解(Leetcode 48、49、53、55、56:旋转图像、字母异位词分组、最大子序和、跳跃游戏、合并区间 )

48. 旋转图像 - 中等 - 9/26

48. 旋转图像 - 中等 - 9/26

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解析:找规律,先按对角线交换,再按对称轴交换即可。

在这里插入图片描述

class Solution {
    public void rotate(int[][] matrix) {
        int l_len = matrix.length;

        //对角线交换
        for(int i=0; i<l_len; i++){
            for(int j=0; j<=i; j++){
                if(i==j) continue; //对角线值,跳过
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }

        //对称轴交换
        for(int i=0,j=l_len-1; i<l_len/2; i++,j--){
            for(int k=0; k<l_len; k++){
                int temp = matrix[k][i];
                matrix[k][i] = matrix[k][j];
                matrix[k][j] = temp;
            }
        }  
    
    }
}

在这里插入图片描述
时间复杂度:O(n²)。

空间复杂度:O(1)。

也可以先以横向的中轴线为轴,对称的行进行交换,然后再以对角线交换。


49. 字母异位词分组 - 中等 - 9/27

49. 字母异位词分组 - 中等

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母都恰好只用一次。

在这里插入图片描述
在这里插入图片描述


解析:排序

由于互为字母异位词的两个字符串包含的字母相同,因此对两个字符串分别进行排序之后得到的字符串一定是相同的,故可以将排序之后的字符串作为哈希表的键。

在这里插入图片描述

形式一:

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        //创建HashMap存储
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        //遍历
        for(String str: strs){
            //将字符串转为字符数组
            char[] array = str.toCharArray();
            //排序
            Arrays.sort(array);
            //存为键
            String key = new String(array);
            //当Map集合中存在这个key时,就使用这个key值,如果没有就使用默认值defaultValue(第二个参数)
            List<String> list = map.getOrDefault(key, new ArrayList<String>());
            //归类 同类的添加在一起
            list.add(str);
            //加入map中
            map.put(key, list);
        }
        //返回map中所有的values
        return new ArrayList<List<String>>(map.values());
    }
}

形式二:

public List<List<String>> groupAnagrams(String[] strs) {
    HashMap<String, List<String>> hash = new HashMap<>();
    for (int i = 0; i < strs.length; i++) {
        char[] s_arr = strs[i].toCharArray();
        //排序
        Arrays.sort(s_arr);
        //映射到 key
        String key = String.valueOf(s_arr); 
        //添加到对应的类中
        if (hash.containsKey(key)) {
            hash.get(key).add(strs[i]);
        } else {
            List<String> temp = new ArrayList<String>();
            temp.add(strs[i]);
            hash.put(key, temp);
        }

    }
    return new ArrayList<List<String>>(hash.values()); 
}

在这里插入图片描述
时间复杂度:O(nklogk),其中n是strs中的字符串的数量,k是strs中的字符串的的最大长度。需要遍历n个字符串,对于每个字符串,需要O(klogk)的时间进行排序以及O(1)的时间更新哈希表,因此总时间复杂度是O(nklogk)。

空间复杂度:O(nk),其中n是strs中的字符串的数量,k是strs中的字符串的的最大长度。需要用哈希表存储全部字符串。


53. 最大子序和 - 简单 - 9/28

53. 最大子序和 - 简单

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
在这里插入图片描述
在这里插入图片描述


解析: 动态规划

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int dp = nums[0];
        int max = nums[0];
        for(int i=1; i < n; i++){
            //取 当前累加后一个数 与 后一个数 的较大值
            dp= Math.max(dp + nums[i],nums[i]);
            //更新最大值
            max = Math.max(max,dp);
        }
        return max;
    }
}

在这里插入图片描述
时间复杂度:O(n),其中n为nums数组的长度。我们只需要遍历一遍数组即可求得答案。

空间复杂度:O(1)。我们只需要常数空间存放若干变量。

55. 跳跃游戏 - 中等 - 9/29

55. 跳跃游戏 - 中等

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

在这里插入图片描述


解析:

每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。

贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点。

局部最优推出全局最优,找不出反例,试试贪心!

在这里插入图片描述

i每次移动只能在cover的范围内移动,每移动一个元素,cover得到该元素数值(新的覆盖范围)的补充,让i继续移动下去。

而cover每次只取 max(该元素数值补充后的范围, cover本身范围)。

如果cover大于等于了终点下标,直接return true就可以了。


class Solution {
    public boolean canJump(int[] nums) {
        if(nums.length == 1) return true;
        //覆盖范围
        int coverRange = nums[0];
        //在覆盖范围内更新最大的覆盖范围
        for(int i=0; i<=coverRange; i++){
            coverRange = Math.max(coverRange, i+nums[i]); //更新最大的覆盖范围
            if(coverRange >= nums.length - 1){ //如果覆盖到最后一个,就返回true
                return true;
            }
        }
        //没有覆盖到,就返回false
        return false;
    }
}

在这里插入图片描述


56. 合并区间 - 中等 - 9/30

56. 合并区间 - 中等

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

在这里插入图片描述


解析:

用合并区间后左边界和右边界,作为一个新的区间,加入到result数组里就可以了。如果没有合并就把原区间加入到result数组。

class Solution {
    public int[][] merge(int[][] intervals) {
        List<int[]> res = new LinkedList<>(); //存储结果
        //按照数组第一个元素排序
        Arrays.sort(intervals, (o1,o2) -> Integer.compare(o1[0],o2[0]));
        //定义开始
        int start = intervals[0][0];
        //遍历
        for(int i=0; i<intervals.length-1; i++){
            //如果当前数组的尾元素 小于 后一个数组的头元素,则直接把当前数组添加进入
            if(intervals[i][1] < intervals[i+1][0]){
                res.add(new int[]{start,intervals[i][1]});
                start = intervals[i+1][0]; //更新开始位置为 后一个数组头元素
            } else {
                //更新后一个数组的尾元素
                intervals[i+1][1] = Math.max(intervals[i+1][1],intervals[i][1]);
            }
        }
        res.add(new int[]{start,intervals[intervals.length-1][1]});
        return res.toArray(new int[res.size()][]);
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值