leetcode 随笔23

9.3

581. 最短无序连续子数组

难度简单

自己原来的想法一直有问题。之后用了新的做法。开辟了一个新的数组,值与给定数组一致,之后对它进行排序。然后对比两个数组不匹配的位置,得到无序部分的开始和结束位置。最后返回结果。

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        // if(nums.length <= 1){
        //     return 0;
        // }
        // int end = nums.length - 1;

        // int begin = 0;
        // while(begin < nums.length - 1 && nums[begin + 1] >= nums[begin]){
        //     begin++;
        // }
        
        
        // //全部有序
        // if(begin == nums.length - 1){
        //     return 0;
        // }
        
        // int min = nums[begin];
        // int max = nums[begin];

        // //找到无序数组的结束,或者说找到下一个有序数组的开始
        // for(int i = begin + 1;i < nums.length;i++){
        //     if(nums[i] < nums[i - 1] || (nums[i] >= min && nums[i] < max) || nums[i] < min){
        //         min = Math.min(min, nums[i]);
        //         max = Math.max(max, nums[i]);
        //         end = i;
        //     }
        // }

        // while(begin >= 1 && nums[begin] == nums[begin - 1]){
        //     begin--;
        // }

        // System.out.println(begin + " - " + end);
        // return end - begin + 1;



        int[] arr = new int[nums.length];
        System.arraycopy(nums, 0, arr, 0, arr.length);
        Arrays.sort(arr);
        int begin = 0;
        int end = -1;//注意本身就满足条件的情况,也就是本身就有序
        boolean flag = true;//找到了开头
        for(int i = 0;i < arr.length;i++){
            if(arr[i] != nums[i]){//不匹配的部分
                if(flag){
                    begin = i;
                    flag = false;
                }else{
                    end = i;
                }
            }
        }

        return end - begin + 1;
    }
}

594. 最长和谐子序列

难度简单

借助一个内部类和treeMap,来统计出现的数字及频次。根据他们的值进行处理。

class Solution {
    class Num{
        int val;
        int count;
        Num(int val, int count){
            this.val = val;
            this.count = count;
        }
    }
    
    public int findLHS(int[] nums) {
        if(nums.length < 2){//长度为0或1的情况
            return 0;
        }

        Map<Integer, Integer> map = new TreeMap<>();
        for(int num : nums){
            if(map.containsKey(num)){
                map.put(num, map.get(num) + 1);
            }else{
                map.put(num, 1);
            }
        }

        int max = 0;
        int index = 0;
        Num[] arr = new Num[map.size()];

        
        for(Map.Entry<Integer, Integer> entry : map.entrySet()){
            arr[index++] = new Num(entry.getKey(), entry.getValue());
        }

        for(int i = 0;i < arr.length - 1;i++){
            Num cur = arr[i];
            Num next = arr[i + 1];
            if(next.val - cur.val == 1){//相邻
                max = Math.max(max, cur.count + next.count);
            }
        }

        return max;
    }
}

不过可以优化。我也觉得我的做法太复杂了。看了题解之后发现,其实可以借助哈希表,一次遍历就达到要求。

class Solution {
    public int findLHS(int[] nums) {
        if(nums.length < 2){//长度为0或1的情况
            return 0;
        }

        Map<Integer, Integer> map = new HashMap<>();
        int res = 0;
        for(int num : nums){
            map.put(num, map.getOrDefault(num, 0) + 1);
            if(map.containsKey(num - 1)){
                res = Math.max(res, map.get(num) + map.get(num - 1));
            }

            if(map.containsKey(num + 1)){
                res = Math.max(res, map.get(num) + map.get(num + 1));
            }
        }

        return res;
    }
}

598. 范围求和 II

难度简单

其实就是算ops中最小的公共区域。

class Solution {
    public int maxCount(int m, int n, int[][] ops) {
        int minRow = m;
        int minColumn = n;
        for(int[] arr : ops){
            minColumn = Math.min(arr[1], minColumn);
            minRow = Math.min(arr[0], minRow);
        }
        return minColumn * minRow;
    }
}

599. 两个列表的最小索引总和

难度简单

两重循环。

class Solution {
    public String[] findRestaurant(String[] list1, String[] list2) {
        int index = Integer.MAX_VALUE;
        List<String> res = new ArrayList<>();

        for(int i = 0;i < list1.length;i++){
            for(int j = 0;j < list2.length;j++){
                if(list1[i].equals(list2[j])){
                    if(i + j < index){
                        index = i + j;
                        res.clear();
                        res.add(list1[i]);
                        break;
                    }else if(i + j == index){
                        res.add(list1[i]);
                        break;
                    }
                }
            }
        }

        return res.toArray(new String[res.size()]);
    }
}

605. 种花问题

难度简单

遍历数组,一边遍历,一边修改。其中需要注意输入数组长度为1的特殊情况。

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        if(flowerbed.length == 0){
            return n == 0;
        }

        if(flowerbed.length == 1){
            if(flowerbed[0] == 0){
                return n <= 1;
            }else{
                return n <= 0;
            }
        }

        for(int i = 0;i < flowerbed.length;i++){
            if(i == 0){//开始
                if(flowerbed[0] == 0 && flowerbed[1] == 0){
                    n--;
                    flowerbed[0] = 1;
                }
            }else if(i == flowerbed.length - 1){//结束
                if(flowerbed[i] == 0 && flowerbed[i - 1] == 0){
                    n--;
                    flowerbed[i] = 1;
                }
            }else{//中间
                if(flowerbed[i] == 0 && flowerbed[i - 1] == 0 && flowerbed[i + 1] == 0){
                    n--;
                    flowerbed[i] = 1;
                }
            }
        }
        return n <= 0;
    }
}

9.10

554. 砖墙

难度中等

想过用暴力法,沿着每一个位置都进行一次切割,取出其中分割砖块的最小数量。但是觉得这样的做法可能会超时。又在想别的办法。想了半天还是没有头绪。之后参照了题解才做出来。

其中需要注意的是sum是不加每个list的最后一个元素的。因为砖墙的宽度是一样的,所以加上list的最后一个元素之后,他们的总和一定等于砖墙的宽度。我就是在这里踩了坑。

class Solution {
    public int leastBricks(List<List<Integer>> wall) {
        Map<Integer, Integer> map = new HashMap<>();
        for(List<Integer> list : wall){
            int sum = 0;
            for(int i = 0;i < list.size() - 1;i++){
                sum += list.get(i);
                map.put(sum, map.getOrDefault(sum, 0) + 1);
            }
        }
        
        int ans = wall.size();
        for(int key : map.keySet()){
            ans = Math.min(ans, wall.size() - map.get(key));
        }
        return ans;
    }
}

645. 错误的集合

难度简单

借助一个数组来帮助实现

class Solution {
    public int[] findErrorNums(int[] nums) {
        int[] ans = new int[2];
        

        int[] count = new int[nums.length];
        for(int num : nums){
            count[num - 1]++;
        }

        for(int i = 0;i < count.length;i++){
            if(count[i] == 2){
                ans[0] = i + 1;
            }
            
            if(count[i] == 0){
                ans[1] = i + 1;
            }
        }
        return ans;
    }
}

646. 最长数对链

难度中等

动态规划的题,看不出来。最开始用了暴力的思想去做,但是发现很难实现。参照了题解才知道应该是动态规划的做法。

class Solution {
    public int findLongestChain(int[][] pairs) {
        
        Arrays.sort(pairs, new Comparator<int[]>(){//先排序。先按照a从小到大排序,如果a相等,则按照b从小到大排序
            public int compare(int[] a, int[] b){
                if(a[0] == b[0]){
                    return a[1] - b[1];
                }
                return a[0] - b[0];
            }
        });

        int n = pairs.length;
        int[] dp = new int[n];

        for(int i = 1;i < n;i++){//以第i个作为结尾
            for(int j = 0;j < i;j++){
                if(pairs[i][0] > pairs[j][1]){//满足条件的都尝试去更新dp数组
                    dp[i] = Math.max(dp[j] + 1, dp[i]);//以第i个作为尾节点的最长链表长度
                } 
            }
        }

        int ans = 0;
        for(int num : dp){//取出其中的最大值
            ans = Math.max(num, ans);
        }
        return ans + 1;
    }
}

9.11

216. 组合总和 III

难度中等

感觉这个题和全排列差不多的思想。不过我每次做这类问题的时候,那个递归指针总是用错,分不清楚。这个题在做的时候最开始也用错了递归指针。

class Solution {
    public List<List<Integer>> combinationSum3(int k, int n) {
        List<List<Integer>> list = new LinkedList<>();

        handle(list, k, n, 0, new LinkedList<Integer>(), 1);
        return list;
    }

    public void handle(List<List<Integer>> list, int k, int n, int sum, List<Integer> path, int begin){
        if(path.size() == k && sum == n){
            list.add(new ArrayList<>(path));
            return ;
        }

        for(int i = begin;i <= 9;i++){
            sum += i;
            path.add(i);
            handle(list, k, n, sum, path, i + 1);
            path.remove(path.size() - 1);
            sum -= i;
        }
    }
}

9.13

91. 解码方法

难度中等

是一个动态规划的问题,但是我一直没找对状态转移方程,花了好多时间都没做出来。之后看了题解才知道,原来应该加上的是dp[i - 2],我一直都是用i - 1来处理。

class Solution {
    public int numDecodings(String s) {
        int len = s.length();
        if (len == 0) {
            return 0;
        }
        
        int[] dp = new int[len];

        char[] charArray = s.toCharArray();
        if (charArray[0] == '0') {
            return 0;
        }
        dp[0] = 1;

        for (int i = 1; i < len; i++) {
            if (charArray[i] != '0') {
                dp[i] = dp[i - 1];
            }

            int num = 10 * (charArray[i - 1] - '0') + (charArray[i] - '0');
            if (num >= 10 && num <= 26) {
                if (i == 1) {
                    dp[i]++;
                } else {
                    dp[i] += dp[i - 2];
                }
            }
        }
        return dp[len - 1];
    }
}

152. 乘积最大子数组

难度中等

最简单的做法就是暴力解决。

class Solution {
    public int maxProduct(int[] nums) {
        if(nums.length == 0){
            return 0;
        }

        //最简单的方法就是暴力
        int ans = Integer.MIN_VALUE;
        int temp = 1;
        //从i开始,到j结束
        for(int i = 0;i < nums.length;i++){
            temp = 1;
            for(int j = i;j < nums.length;j++){
                temp *= nums[j];
                ans = Math.max(temp, ans);
            }
        }
        return ans;
    }
}

用动态规划优化的方法,看不懂。。。

279. 完全平方数

难度中等

这个题做了好久,尝试了好多想法都没做出来。最后还是看了题解才做出来。

class Solution {
    public int numSquares(int n) {
        int[] dp = new int[n + 1]; // 默认初始化值都为0
        for (int i = 1; i <= n; i++) {
            dp[i] = i; // 最坏的情况就是每次+1
            for (int j = 1; i - j * j >= 0; j++) { 
                dp[i] = Math.min(dp[i], dp[i - j * j] + 1); // 动态转移方程
            }
        }
        return dp[n];
    }
}

300. 最长上升子序列

难度中等

注意其中的特殊条件,比如长度为0、长度为1,分别进行处理。

class Solution {
    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        if(len == 0){
            return 0;
        }
        int[] dp = new int[len];//以i结尾的最长上升子序列
        Arrays.fill(dp, 1);
        int max = 1;
        for(int i = 1;i < len;i++){
            for(int j = i - 1;j >= 0;j--){
                if(nums[i] > nums[j]){
                    dp[i] = Math.max(dp[j] + 1, dp[i]);
                }
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值