随想录训练营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 的值,记录已经遍历过的字母中,最大的最后出现位置; 出现问题:
- 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; 重点理解:
- 为什么后序遍历?
- 为什么需要start? eg: 数字 1000, 在
i=3,i=2时, 不会进入if判断体, 若没有start,最终输出结果为900,而不是999;- 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