合并区间
题目来源:https://leetcode-cn.com/problems/merge-intervals/
/**
* 输入: [[1,3],[2,6],[8,10],[15,18]]
* 输出: [[1,6],[8,10],[15,18]]
* 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
* 必须做的事情
* */
public int[][] merge(int[][] intervals) {
List<int[]> res = new ArrayList<>();
if (intervals.length == 0 || intervals == null) return res.toArray(new int[0][]);
// 对起点终点进行排序
//从小到大排序
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
int i = 0;
while (i < intervals.length) {
//left
int left = intervals[i][0];
//right
int right = intervals[i][1];
// 如果有重叠,循环判断哪个起点满足条件
//intervals[i + 1][0] 左小于他的右
//判断重叠
//只有当下一个元素跟这个元素的right的有交叉,进入循环
while (i < intervals.length - 1 && intervals[i + 1][0] <= right) {
//先加在比较
i++;
//比较哪个右大
right = Math.max(right, intervals[i][1]);
}
// 将现在的区间放进res里面
res.add(new int[]{left, right});
// 接着判断下一个区间
i++;
}
return res.toArray(new int[0][]);
}
另外一道笔试题,不太记得了,好像是最大连续子数组的个数最多的输出最后一个
有点类似于:
/**
* 给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
* 示例 1 :
* 输入:nums = [1,1,1], k = 2
* 输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
*/
public int subarraySum(int[] nums, int k) {
int count = 0;
for (int start = 0; start < nums.length; ++start) {
int sum = 0;
for (int end = start; end >= 0; --end) {
sum += nums[end];
if (sum == k) {
count++;
}
}
}
return count;
}
优化解法:
/**
* 其实有点像是所有连续子数组
* 属于数学推导:
* pre[i] = 0 -i 的和
* [j..i]这个子数组和为 k
* pre[i]−pre[j−1]=k
* 移项
pre[j−1] = pre[i]−k
虑以 i结尾的和为 k 的连续子数组个数时只要统计有多少个前缀和 为 pre[i]−k 的 pre[j] 即可
卧槽,因为pre是不断累加的。
pre[i]=pre[i−1]+nums[i] 加就完事了。
那么到pre[i]这里的时候,他需要找到一个pre[j-1]
那么把之前的pre全放进去就好了
*/
public static int subarraySum2(int[] nums, int k) {
//输出子数组个数
int count = 0, pre = 0;
HashMap<Integer, Integer> map = new HashMap<>();
//这个Map的意义是什么?
map.put(0, 1);
//循环n次
for (int i = 0; i < nums.length; i++) {
pre += nums[i];
if (map.containsKey(pre - k)) {
count += map.get(pre - k);
}
//这个map存的是出现的次数。
map.put(pre, map.getOrDefault(pre, 0) + 1);
}
return count;
}