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

本文讲述了在编程问题中处理区间(例如435.无重叠区间、763.划分字母区间和56.合并区间)的几种贪心算法策略,包括按左边界或右边界排序并调整区间边界以达到最优解。
摘要由CSDN通过智能技术生成

 题目与题解

435. 无重叠区间

题目链接:435. 无重叠区间

代码随想录题解:435. 无重叠区间

视频讲解:贪心算法,依然是判断重叠区间 | LeetCode:435.无重叠区间_哔哩哔哩_bilibili

解题思路:

        求无重叠区间,要返回需要移除区间的最小数量,使剩余区间互不重叠,相当于有区间重叠时,只能保留其中一个区间,且为了保证最后能保留的区间尽可能多,保留的区间要尽可能小。

        首先将左边界作为第一关键字,对区间进行升序排序,这样保证左边界都是有序的,只需要判断前一个保留的右边界与下一个左边界是否重合。如果有重合,则需要移除的区间数目加一,右边界更新为当前区间和右边界之间的较小值。否则右边界更新为当前区间右边界。

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
		if (intervals.length <= 1) return 0;
		Arrays.sort(intervals, new Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				if (o1[0] == o2[0])
					return Integer.compare(o1[1], o2[1]);
				return Integer.compare(o1[0], o2[0]);
			}
		});
		int end = intervals[0][1];
		int count = 0;
		for (int i = 1; i < intervals.length; i++) {
			if (end > intervals[i][0]) {
				count++;
				end = Math.min(intervals[i][1], end);
			} else {
				end = intervals[i][1];
			}
		}
		return count;
    }
}

看完代码随想录之后的想法 

        随想录的方法一反其道而行之,先对区间右边界进行排序,求非重合区间的个数,再用总区间数减掉它,得到最终需要移除区间的个数。说实话感觉有点难想有点绕,还是喜欢方法二这种从区间左边界开始排序,直接求需要移除区间的办法。

遇到的困难

        一开始想的太粗暴了,遍历时只要有重合就直接移除当前区间,忽略了有时比起前一个区间,当前区间才是最优解(如前一个区间是[1,4],当前区间是[2,3],肯定保留更小的当前区间更优)。还有就是要注意end是需要实时更新的,否则一定出错。

763.划分字母区间

题目链接:​​​​​​​763.划分字母区间

代码随想录题解:763.划分字母区间

视频讲解:贪心算法,寻找最远的出现位置! LeetCode:763.划分字母区间_哔哩哔哩_bilibili

解题思路:

        先不提算法,假设手动计算区间划分,做法应该是:首先记录第一个字母第一次出现的位置和最后一次出现的位置,然后再从第一个字母最后一次出现的位置出发,记录第二个字母最后一次出现的位置,然后取这两个最后一次出现位置的较大值,更新本次分割的终点,然后再对第三个、第四个。。。直到本次终点的字母做相同的操作,就得到了一个分割序列长度;下一个序列从上次分割终点后的第一个字母开始,重复上述操作。

        写成代码就是:设置每次分割的起点start和终点end,初始化为0,对start和end之间的字符进行遍历。每轮遍历先记录当前字符,然后搜索end+1到字符串结束中间有没有当前字符,如果有,更新end为当前字符最后一次出现的位置。每轮遍历完成后,记录start到end之间的字符数,然后更新start = end = end + 1,开始下一次的遍历。

        为了节约时间,每轮遍历之前还需要设置一个大小为26的charExistence的boolean数组,用来记录当前字符有没有被查找过,如果查找过就可以跳过本轮循环。        

class Solution {
    public List<Integer> partitionLabels(String s) {
		List<Integer> result = new ArrayList<>();
		int start = 0;
		int end = 0;
		while (start < s.length() && end < s.length()) {
			boolean[] charExistence = new boolean[26];
			for (int i = start; i <= end ; i++) {
				char c = s.charAt(i);
				if (charExistence[c - 'a']) continue;
				charExistence[c - 'a'] = true;
				for (int j = end + 1; j < s.length(); j++) {
					if (s.charAt(j) == c) end = j;
				}
			}
			result.add(end - start + 1);
			start = end + 1;
			end = start;
		}
		return result;
    }
}

看完代码随想录之后的想法 

        随想录的解答更巧妙,先统计每个字符最后一次出现的位置,然后再遍历字符串,更新分割区间的右边界,直到当前字符最后一次出现的位置跟右边界一致,说明当前分割完成,记录字符数即可。

class Solution {
    public List<Integer> partitionLabels(String S) {
        List<Integer> list = 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) {
                list.add(i - last);
                last = i;
            }
        }
        return list;
    }
}

遇到的困难

        一开始直接求解会有点无从下手,可以分步做,先写出第一个字符怎么操作,第二个字符怎么操作,再填充遍历的起点终点和其他细节,就可以写出完整的过程了。

56. 合并区间

题目链接:56. 合并区间

代码随想录题解:56. 合并区间

视频讲解:贪心算法,合并区间有细节!LeetCode:56.合并区间_哔哩哔哩_bilibili

解题思路:

        这题跟去除重复区间的思想有点类似,不同的地方在于遇到重叠的区间时,要取两个区间中更大的右边界,来合并两个区间。

        首先对区间进行排序,关键字为区间左边界。然后用result这一链表记录合并后的区间值,初始化时将第一个区间加入。遍历剩余区间,如果当前区间的左边界大于result最后一个元素的右边界,说明二者不重叠,不用合并,将当前区间加入result即可;否则将result的最后一个元素右边界更新为更大的那个右边界。

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

看完代码随想录之后的想法 

        思路差不多,写法上稍微有点区别,就不赘述了。

遇到的困难

        这题有前面几题的铺垫,写起来非常容易了。

今日收获

        集中练习了一下区间重叠相关的题目,这些题重点在于:如何对原区间进行排序,排序后再遍历时,如何根据要求更新区间的边界值,保证不重复不遗漏。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第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、付费专栏及课程。

余额充值