代码随想录算法训练营第36天|435. 无重叠区间,763.划分字母区间,56. 合并区间

435. 无重叠区间

力扣

思路:

1. 按左边界排序,从左到右遍历;用count记录需要移除的区间;

2. 若当前遍历区间的左边界小于前一个区间的右边界时,count++,更新当前区间右边界为作比较的这两个区间右边界的最小值;

3. 遍历结束,返回count;

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals,(a,b)->Integer.compare(a[0],b[0]));
        int count = 0;
        for(int i=1;i<intervals.length;i++){
            if(intervals[i][0]<intervals[i-1][1]){
                count++;
                intervals[i][1]=Math.min(intervals[i-1][1],intervals[i][1]);
            }
        }
        return count;
    }
}

思路2:

435.无重叠区间1. 按右边界从小到大排序,从左到右遍历;局部最优:遍历,留给下一个区间的空间大一些,从而尽量避免交叉。全局最优:选取最多的非交叉区间。

2. 用edge表示分割线(右边界),初始化为Integer.MIN_VALUE。若当前遍历区间左边界<分割线,说明有交集,count++;若当前遍历区间左边界>=分割线,说明无交集,更新分割线为当前遍历区间的右边界;

3. 遍历结束,返回count。

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals,(a,b)->Integer.compare(a[1],b[1]));
        int count = 0;
        int edge = Integer.MIN_VALUE;
        for(int i=0;i<intervals.length;i++){
            if(edge<=intervals[i][0]){//无交集
                edge=intervals[i][1];
            }else{//有交集(不更新edge)
                count++;
            }
        }
        return count;
    }
}

763.划分字母区间

力扣

思路:

1. 统计每个字母最后出现的位置;

2. 从头遍历字符,并更新字符的最远出现位置下标;若最远出现位置下标与当前下标相等,则找到了分割点。

763.划分字母区间

class Solution {
    public List<Integer> partitionLabels(String s) {
        List<Integer> res = new LinkedList<>();
        int[] edge = new int[26];
        char[] chars = s.toCharArray();
        for(int i=0;i<chars.length;i++){
            edge[chars[i]-'a']=i;
        }
        int idx = 0;
        int last = -1;
        for(int i=0;i<chars.length;i++){
            idx=Math.max(idx,edge[chars[i]-'a']);
            if(i==idx){
                res.add(i-last);
                last=i;
            }
        }
        return res;
    }
}

思路2:无重叠区间

1. 统计字符串中所有字符的起始和结束位置,记录为区间;

2. 按照左边界从小到大排序,找到边界将区间划分互不重叠的组;

3. 返回边界合集;

class Solution {
    public List<Integer> partitionLabels(String s) {
        List<Integer> res = new ArrayList<>();
        int[][] partitions = findPartitions(s);
        Arrays.sort(partitions,(o1,o2)->Integer.compare(o1[0],o2[0]));
        int right = partitions[0][1];//记录最大右边界
        int left = 0;
        for(int i=0;i<partitions.length;i++){
            if(partitions[i][0]>right){//分割
                res.add(right-left+1);
                left = partitions[i][0];
            }
            right = Math.max(right,partitions[i][1]);
        }
        res.add(right-left+1);
        return res;
    }
    public int[][] findPartitions(String s){
        //记录各个字母左右边界
        int[][] hash = new int[26][2];
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(hash[c-'a'][0]==0) hash[c-'a'][0]=i;//左边界
            hash[c-'a'][1]=i;//右边界
            hash[s.charAt(0)-'a'][0] = 0;//第一个元素左边界
        }
        //去除字符串中未出现的字母所占用区间
        List<Integer> temp = new ArrayList<>();
        List<List<Integer>> h = new LinkedList<>();
        for(int i=0;i<26;i++){
            temp.clear();
            temp.add(hash[i][0]);
            temp.add(hash[i][1]);
            h.add(new ArrayList<>(temp));
        }
        int[][] res = new int[h.size()][2];
        for(int i=0;i<h.size();i++){
            List<Integer> list = h.get(i);
            res[i][0] = list.get(0);
            res[i][1] = list.get(1);
        }
        return res;
    }
}

56. 合并区间

力扣

思路:

1. 按照左边界从小到大排序;

2. 局部最优:每次合并都取最大的右边界,这样就可以合并更多的区间;整体最优:合并所有重叠的区间;

3. 遍历区间;若当前所遍历的区间的左边界小于等于前一个区间的右边界,合并为一个新区间,加入result数组;若没有合并,则将原数组加入result数组。

class Solution {
    public int[][] merge(int[][] intervals) {
        LinkedList<int[]> res = new LinkedList<>();
        Arrays.sort(intervals,(o1,o2)->Integer.compare(o1[0],o2[0]));
        res.add(intervals[0]);
        for(int i=1;i<intervals.length;i++){
            if(intervals[i][0]<=res.getLast()[1]){
                int start = res.getLast()[0];
                int end = Math.max(intervals[i][1],res.getLast()[1]);
                res.removeLast();
                res.add(new int[]{start,end});
            }else{
                res.add(intervals[i]);
            }
        }
        return res.toArray(new int[res.size()][]);
    }
}

代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值