区间问题
1. 会议室(判断区间是否重叠)
思路:很容易理解一个人不可能同时出席两场会议,也就是会议时间不能重叠。先按照开始时间排序,逐个比较下一个会议开始时间是否大于前一个会议的结束时间
public static boolean canAttendMeetings(int[][] intervals) {// 将区间按照会议开始实现升序排序Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);// 遍历会议,如果下一个会议在前一个会议结束之前就开始了,返回 false。for (int i = 1; i < intervals.length; i++) {if (intervals[i][0] < intervals[i - 1][1]) {return false;}}return true;}
2. 合并区间
思路:合并有重叠的区间然后加入结果集,就是需要注意一些边界
class Solution {public int[][] merge(int[][] intervals) {if(intervals.length==1){return intervals;}Arrays.sort(intervals,(v1,v2)->v1[0]-v2[0]);ArrayList<int[]> list = new ArrayList<int[]>();int i = 1;while(i<intervals.length){if(intervals[i-1][1]<intervals[i][0]){list.add(intervals[i-1]);i++;}int k = i-1;while(i<intervals.length&&intervals[k][1]>=intervals[i][0]){intervals[k][1] = Math.max(intervals[i][1],intervals[k][1]);i++;}i++;list.add(intervals[k]);if(i == intervals.length){list.add(intervals[i-1]);}}return list.toArray(new int[list.size()][]);}
}
3. 插入区间
思路:无重复区间直接添加进结果集,重复的进行区间合并(左取小,右取大)
class Solution {public int[][] insert(int[][] intervals, int[] newInterval) {int left = newInterval[0];int right = newInterval[1];boolean placed = false;List<int[]> ansList = new ArrayList<int[]>();for (int[] interval : intervals) {if (interval[0] > right) {// 在插入区间的右侧且无交集if (!placed) {ansList.add(new int[]{left, right});placed = true; }ansList.add(interval);} else if (interval[1] < left) {// 在插入区间的左侧且无交集ansList.add(interval);} else {// 与插入区间有交集,计算它们的并集left = Math.min(left, interval[0]);right = Math.max(right, interval[1]);}}if (!placed) {ansList.add(new int[]{left, right});}int[][] ans = new int[ansList.size()][2];for (int i = 0; i < ansList.size(); ++i) {ans[i] = ansList.get(i);}return ans;}
}
字符串分割
思路:很容易想到首先遍历一遍获得每个字母的最后出现的下标位置,怎么找出包含当前字母最后一次出现的最短的片段呢?也就是在第二次遍历中:当前遍历的位置正好是前面所有字母中最长的end位置
class Solution {public List<Integer> partitionLabels(String s) {int[] last = new int[26];int len = s.length();for(int i = 0;i<len;i++){last[s.charAt(i)-'a'] = i;}int end = 0;List<Integer> list = new ArrayList<Integer>();int start = 0;for(int i = 0;i<len;i++){//当前字母的end是最后的endend = Math.max(last[s.charAt(i)-'a'],end);if(i == end){list.add(i - start + 1);start = end+1;}}return list;}
}
加油站
思路:如果每个加油站的剩余油量总和大于等于0那么就是能跑完全程,当前剩余油量小于零则不能从i之前的加油站出发,剩余总油量固定左边小右边就大
class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {int total = 0;int cur = 0;int start = 0;for(int i = 0;i<gas.length;i++){total += gas[i] - cost[i];cur += gas[i] - cost[i];if(cur<0){start = i + 1;cur = 0;}}if(total<0){return -1;}else{return start;}}
}