最长递增子序列和ta的衍生题
主要是找出最多独立的区间
最长递增子序列
这是一切开始的地方
class Solution { public int lengthOfLIS(int[] nums) { int n = nums.length, len = 0; int[] tails = new int[nums.length]; for (int i = 0; i < nums.length; i++) { int l = 0, r = len - 1; while (l <= r) { int mid = (r - l) / 2 + l; if (nums[i] <= tails[mid]) { //这里要取等号,相同即替换 //ans = mid; r = mid - 1; } else { l = mid + 1; } } tails[l] = nums[i]; if (l == len) len++; } return len; } }
下标为 i 表示长度为 i + 1是最长上升子序列的末尾是数字。时刻更新保证长度为i + 1的最长上升子序列的末尾的数字是最小的。
class Solution { public int lengthOfLIS(int[] nums) { int n = nums.length; int[] tails = new int[nums.length]; tails[0] = nums[0]; int len = 1; for (int i = 1; i < nums.length; i++) { if (nums[i] > tails[len - 1]) { tails[len++] = nums[i]; } int l = 0, r = len - 1; while (l <= r) { int mid = (r - l) / 2 + l; if (nums[i] <= tails[mid]) { //ans = mid; r = mid - 1; } else { l = mid + 1; } } tails[l] = nums[i]; } return len; } }
无重叠区间
根据第二个元素先排序,至于原由你细品。最长上升子序的个数就是无重叠区间的个数。(贪心是最优解,这样只是提供了另一个思路)
class Solution { public int eraseOverlapIntervals(int[][] intervals) { if (intervals.length == 0) return 0; Arrays.sort(intervals, (o1, o2) -> o1[1] - o2[1]); int[] dp = new int[intervals.length]; Arrays.fill(dp, 1); int res = 1; for (int i = 1; i < intervals.length; i++) { for (int j = 0; j < intervals.length; j++) { if (intervals[i][0] >= intervals[j][1]) { dp[i] = Math.max(dp[j] + 1, dp[i]); } } res = Math.max(dp[i], res); } return intervals.length - res; } }
用最少数量的箭引爆气球
和上面的思路一样,有多少不重叠的区间就射多少箭。你这样想,不重叠的区间就是至少射的箭的数量,只要射得是重叠区间的交集就可以顺带把重叠区间射掉。(同样贪心跟简单,这只是另一种思路)
class Solution { public int findMinArrowShots(int[][] points) { if (points.length == 0) return 0; Arrays.sort(points, (o1, o2) -> (o1[1] < o2[1] ? -1 : 1)); int res = 1; int[] dp = new int[points.length]; Arrays.fill(dp, 1); for (int i = 0; i < points.length; i++) { for (int j = 0; j < i; j++) { if (points[i][0] > points[j][1]) { dp[i] = Math.max(dp[j] + 1, dp[i]); } } res = Math.max(res, dp[i]); } return res; } }
最长数对链
同样的配方,熟悉的味道。
class Solution { public int findLongestChain(int[][] pairs) { Arrays.sort(pairs, (o1, o2) -> o1[1] - o2[1]); int[] dp = new int[pairs.length]; Arrays.fill(dp, 1); int res = 1; for (int i = 0; i < pairs.length; i++) { for (int j = 0; j < i; j++) { if (pairs[i][0] > pairs[j][1]) { dp[i] = Math.max(dp[j] + 1, dp[i]); } } res = Math.max(res, dp[i]); } return res; } }
俄罗斯套娃信封问题
二维LIS
class Solution { public int maxEnvelopes(int[][] envelopes) { if (envelopes.length == 0) return 0; //这里排序要注意[[1,2], [2,2],[3,2], [4,3]]要排序成[[3,2], [2,2], [1,2],[4,3]] Arrays.sort(envelopes, (o1, o2) -> o1[1] == o2[1] ? o2[0] - o1[0] : o1[1] - o2[1]); int n = envelopes.length, end = 0; int[] tail = new int[n]; for (int i = 0; i < n; i++) { int l = 0, r = end - 1; while (l <= r) { int mid = (r - l) / 2 + l; if (envelopes[i][0] <= tail[mid]) { //ans = mid; r = mid - 1; } else { l = mid + 1; } } tail[l] = envelopes[i][0]; if (l == end) end++; } return end; } }