随想录训练营Day36 | 贪心 - - 435. 无重叠区间, 763.划分字母区间, 56. 合并区间, 738.单调递增的数字

81 阅读3分钟

随想录训练营Day36 | 贪心 - - 435. 无重叠区间, 763.划分字母区间, 56. 合并区间, 738.单调递增的数字

标签: LeetCode闯关记


435. 无重叠区间

思路: (cf 452. 用最少数量的箭引爆气球)需要删除的区间个数,即重叠区间的个数 一旦找到重叠区间,count++,并更新重叠区间的最小右边界

//按照左边界排列
class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
    Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));
    int count = 0;//change cf:452. 用最少数量的箭引爆气球
    for (int i = 1; i < intervals.length; i++) {
    if(intervals[i][0] < intervals[i-1][1]){//两个区间有重叠空间
    intervals[i][1] = Math.min(intervals[i-1][1],intervals[i][1]);//更新重叠区间的最小右边界
    count++;
}
}
return count;//返回重叠区间的个数,即需要删除的区间个数
}
}

time: 30min

763.划分字母区间

思路:

  • 找出对应字母最后出现的位置,并存入int[]数组; 遍历char数组,直至遍历到字母出现的最后位置(i == right);
  • 注意: 在遍历过程中,需要实时更新right 的值,记录已经遍历过的字母中,最大的最后出现位置; 出现问题:
    1. right = Math.max(right, edge[chars[i]- 'a']);//写成了right = Math.max(right, edge[i]) 错因: 不熟悉记录26个字母最后出现位置的用法,即edge[char[i] - 'a'];
  • 2)把left,right的初始化值放入了for循环中,导致每一次for循环都重置了left,最终导致输出结果为空; 错因: 对于left的定位不准+细节:left需要在for循环中实时更新;
//这实现也太妙了
class Solution {
    public List<Integer> partitionLabels(String s) {
        List<Integer> res = new ArrayList<>();
        char[] chars = s.toCharArray();
        int[] edge = new int[26];
        for (int i = 0; i < chars.length; i++) {
            edge[chars[i] - 'a'] = i;
        }
        int left = -1;
        int right = Integer.MIN_VALUE;
//            int left = 0;//犯错,把left,right的初始化值放入了for循环中,导致每一次for循环都重置了left,最终导致输出结果为空
//            int right = Integer.MIN_VALUE;
        for (int i = 0; i < chars.length; i++) {

            right = Math.max(right, edge[chars[i]- 'a']);//写成了right = Math.max(right, edge[i])
            if(right == i){
                res.add(right - left);
                left = right;
            }
        }
        return res;
    }
}

time: 54min

56. 合并区间

自己选的 ArrayList<ArrayList<Integer>> res来收集结果出现的恶果, 反思如何掌握一门语言自带的数据结构,并选取最好的来解题,归根结底是没有熟悉了解java

class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        int left = intervals[0][0];
        int maxRight = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if(intervals[i][0] <= maxRight){//说明有重叠区间 "="也是?
                maxRight = Math.max(maxRight,intervals[i][1]);
            }
            else {
                ArrayList<Integer> interval = new ArrayList<>();
                interval.add(left);
                interval.add(maxRight);
                res.add(interval);
                left = intervals[i][0];
                maxRight = intervals[i][1];
            }
        }
        ArrayList<Integer> interval = new ArrayList<>();
        interval.add(left);
        interval.add(maxRight);
        res.add(interval);

        int[][] resArray = new int[res.size()][2];
        for (int j = 0; j < res.size(); j++) {
            resArray[j][0] = res.get(j).get(0);
            resArray[j][1] = res.get(j).get(1);
        }

        return resArray;


    }
}

正解:用ArrayList<int[]> res

class Solution {
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals,(a,b) -> Integer.compare(a[0],b[0]));
        ArrayList<int[]> res = new ArrayList<>();
        int left = intervals[0][0];
        int maxRight = intervals[0][1];
        for (int i = 1; i < intervals.length; i++) {
            if(intervals[i][0] <= maxRight){//说明有重叠区间 "="也是?
                maxRight = Math.max(maxRight,intervals[i][1]);//有重叠,则更新右边界
            }
            else {
                res.add(new int[]{left,maxRight});//没有重叠,则将i之前的区间[left,maxRight]加入结果集
                left = intervals[i][0];
                maxRight = intervals[i][1];
            }
        }

        res.add(new int[]{left,maxRight});//不要忘记,将最后一个区间加入结果集
        return res.toArray(new int[res.size()][]);
    }
}
//在这段代码中,res.toArray(new int[res.size()][])操作的作用是将 ArrayList 对象 res 转换成一个二维数组。具体而言,new int[res.size()][] 会创建一个大小为 res.size() 的一维数组,其中每个元素都是 null。然后,res.toArray(...) 方法将 res 中的元素复制到这个已分配但空间未分配的二维数组中。每个元素都是一个长度为2的一维数组,对应于排序后不重叠的区间的左右端点。最后,返回结果是一个二维数组,表示合并后的区间。因此,res.toArray(new int[res.size()][]) 中的最后一个 [] 表示将转换后的对象强制转换为二维数组类型。
//leetcode submit region end(Prohibit modification and deletion)

time: 50min

738.单调递增的数字

思路: 后序遍历,比较相邻两个数的大小,如果第i-1个 > 第i个,那么第i个数字需要变为'9',第i-1个需要-1; 重点理解:

  1. 为什么后序遍历?
  2. 为什么需要start? eg: 数字 1000, 在i=3,i=2时, 不会进入if判断体, 若没有start,最终输出结果为900,而不是999;
  3. start的初始化值有何妙处? 为了避免原数为: 1234 这种类型,若start初始化为0,那么,会进入第二个for循环,导致最终结果为99999,得到错误结果

出现问题

  • start = i写成start--,这样写的话,默认String s 的每一位数各个之间都不相等. 但是,eg:测试用例:100,测试结果:9, 期望结果:99 因为'00',0=0,并没有进入if判断,更不会执行start--;

总结

  • 此题的细节: 关键考虑不进入 if(chars[i-1] > chars[i])的情况
class Solution {
    public int monotoneIncreasingDigits(int n) {
        String s = String.valueOf(n);
        char[] chars = s.toCharArray();
        int start = chars.length//细节: 为了避免原数为: 1234 这种类型,若start初始化为0,那么,会进入第二个for循环,导致最终结果为99999,得到错误结果
        for (int i = chars.length - 1; i > 0 ; i--) {
            if(chars[i-1] > chars[i]){
                chars[i-1]--;
                start = i;/*错误: 写成start--,但是这样写的话,默认String s 的每一位数各个之间都不相等. 但是,eg:测试用例:100
                测试结果:9
                期望结果:99
                因为'00',0=0,并没有进入if判断,更不会执行start--;
                */

            }
        }
        System.out.println(start);
        for (int i = start; i < chars.length; i++) {
            chars[i] = '9';
        }
        return Integer.parseInt(String.valueOf(chars));
    }
}

time: 1h

968.监控二叉树 (太难了没做也听不太懂)