【问题描述】56.合并区间
给出一个区间的集合,请合并所有重叠的区间。
示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
【解答思路】
1. 双指针
左边位置一定是确定,就是 a[0],而右边位置是 max(a[1], b[1])
时间复杂度:O(N) 空间复杂度:O(1)
public int[][] merge(int[][] intervals) {List<int[]> res = new ArrayList<>();if (intervals == null || intervals.length == 0)return res.toArray(new int[0][]);// Arrays.sort(intervals, (a, b) -> a[0] - b[0]);// a[0] - b[0]大于0就交换顺序// 根据二维数组第一个数字大小按每一行整体排序Arrays.sort(intervals, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {// TODO Auto-generated method stubreturn o1[0] - o2[0];}});int i = 0;while (i < intervals.length) {int left = intervals[i][0];int right = intervals[i][1];// i不能到最后一行,所以要小于(数组的长度 - 1)// 判断所在行的right和下一行的left大小,对right重新进行赋最大值,之后再不断进行while循环判断while (i < intervals.length - 1 && right >= intervals[i + 1][0]) {i++;right = Math.max(right, intervals[i][1]);}res.add(new int[] { left, right });i++;}return res.toArray(new int[0][]);}
2. 栈思想(威威)
- 如果当前遍历到的区间的左端点 > 结果集中最后一个区间的右端点,说明它们没有交集,此时把区间添加到结果集;
- 如果当前遍历到的区间的左端点 <= 结果集中最后一个区间的右端点,说明它们有交集,此时产生合并操作,即:对结果集中最后一个区间的右端点更新(取两个区间的最大值)。
时间复杂度:O(N) 空间复杂度:O(1)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Stack;public class Solution {public int[][] merge(int[][] intervals) {int len = intervals.length;if (len < 2) {return intervals;}// 按照起点排序Arrays.sort(intervals, Comparator.comparingInt(o -> o[0]));// 也可以使用 Stack,因为我们只关心结果集的最后一个区间List<int[]> res = new ArrayList<>();res.add(intervals[0]);for (int i = 1; i < len; i++) {int[] curInterval = intervals[i];// 每次新遍历到的列表与当前结果集中的最后一个区间的末尾端点进行比较int[] peek = res.get(res.size() - 1);if (curInterval[0] > peek[1]) {res.add(curInterval);} else {// 注意,这里应该取最大peek[1] = Math.max(curInterval[1], peek[1]);}}return res.toArray(new int[res.size()][]);}public static void main(String[] args) {Solution solution = new Solution();int[][] intervals = {{1, 3}, {2, 6}, {8, 10}, {15, 18}};int[][] res = solution.merge(intervals);for (int i = 0; i < res.length; i++) {System.out.println(Arrays.toString(res[i]));}}
}
【总结】
1. Java 数组题 转化 List
List<int[]> res = new ArrayList<>();
res.add(new int[] { left, right });
res.toArray(new int[0][]);
2. Java中Arrays.sort()的几种用法
- Arrays.sort(int[] a) 对一个数组的所有元素进行排序,并且是按从小到大的顺序
- Arrays.sort(int[] a, int fromIndex, int toIndex) 对数组部分排序,也就是对数组a的下标从fromIndex到toIndex-1的元素排序,注意:下标为toIndex的元素不参与排序
- public static void sort(T[] a,int fromIndex, int toIndex, Comparator<? super T> c) Comparator类型的参数
Arrays.sort(intervals, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {// TODO Auto-generated method stubreturn o1[0] - o2[0];}});
- 区间类的问题,一般而言是需要画图思考的。
- 和物理现象相关的
- 本身问题描述就和图形相关的问题
- 链表问题
- 回溯算法问题
- 动态规划问题
- 贪心算法
- 贪心算法(Greedy Algorithm)是指:在对问题求解时,总是做出在当前看来是最好的选择。也就是不从整体最优上加以考虑,贪心算法所做出决策是在某种意义上的局部最优解。
- 可以适用贪心的问题就是每一步局部最优,最后导致结果全局最优。
- 必须具备无后效性,,即某个状态以前的过程不会影响以后的状态,只与当前状态有关
- 由于贪心算法适用的场景一般都是在一组决策里选择最大或者最小值,因此常常在使用贪心算法之前,需要先对数据按照某种规则排序
- 一旦贪心选择性质不成立,可以考虑的另一种算法思想就是「动态规划」。「动态规划」在每一步做决策的时候,就不只考虑当前步骤的最优解。
- 贪心算法应用
- 对数据压缩编码的霍夫曼编码(Huffman Coding)
- 求最小生成树的 Prim 算法和 Kruskal 算法
- 求单源最短路径的Dijkstra算法