646. 最长数对链
给你一个由 n 个数对组成的数对数组 pairs ,其中 p a i r s [ i ] = [ l e f t i , r i g h t i ] pairs[i] = [left_i, right_i] pairs[i]=[lefti,righti] 且 l e f t i < r i g h t i left_i < right_i lefti<righti。
现在,我们定义一种 跟随 关系,当且仅当 b < c 时,数对 p2 = [c, d] 才可以跟在 p1 = [a, b] 后面。我们用这种形式来构造 数对链 。
找出并返回能够形成的 最长数对链的长度 。
你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
示例 1:
输入:pairs = [[1,2], [2,3], [3,4]]
输出:2
解释:最长的数对链是 [1,2] -> [3,4] 。
示例 2:
输入:pairs = [[1,2],[7,8],[4,5]]
输出:3
解释:最长的数对链是 [1,2] -> [4,5] -> [7,8] 。
提示:
- n = = p a i r s . l e n g t h n == pairs.length n==pairs.length
- 1 < = n < = 1000 1 <= n <= 1000 1<=n<=1000
- − 1000 < = l e f t i < r i g h t i < = 1000 -1000 <= left_i < right_i <= 1000 −1000<=lefti<righti<=1000
思路:
首先对二维数组进行排序:
- 使用Arrays.sort(arr,Comparator<>)
对数组中相邻的两个数进行比较, 一轮完了接着二轮 是一个冒泡排序,时间复杂度为: O ( n 2 ) O(n^2) O(n2)
(a, b) -> a - b 相当于
function(a,b){
return a-b;
}
Arrays.sort(arr, (a, b) -> a - b) 是对数组进行冒泡排序
如果 a - b>0 则b 在前 a 在后、直到有序
二维数组
Arrays.sort(arr, (a, b) ->(a[clomun]- b[clomun]))
以行为整体 按指定列比较
- 使用快排,时间复杂度为:O(nlogn)
法一:动态规划
- 排序(按上述两种方法)
- 定义 dp[i] 为以 pairs[i] 为结尾的最长数对链的长度。
- 计算 dp[i] 时,可以先找出所有的满足 pairs[i][0] > pairs[j][1] 的 j,并求出最大的
dp[j],dp[i]的值即可赋为这个最大值再加一。
法二:贪心
使用贪心思想扩展数对链,在所有可作为下一个数对的集合中选择第二个数最小的数对添加到数对链。
要挑选最长数对链的第一个数对时,最优的选择是挑选第二个数字最小的,这样能给挑选后续的数对留下更多的空间。挑完第一个数对后,要挑第二个数对时,也是按照相同的思路,是在剩下的数对中,第一个数字满足题意的条件下,挑选第二个数字最小的。按照这样的思路,可以先将输入按照第二个数字排序,然后不停地判断第一个数字是否能满足大于前一个数对的第二个数字即可。
- 排序(按上述两种方法)
- 由于所有的数对都已按照第一个升序排序,所以在构造数对链过程中,只需挑选数对第二数尽量小的数。使用temp0,temp1 记录数对链的最后一组数据。
- 对任意pairs[i - 1][0] <= pairs[i][0],所以 temp0 <= pairs[i][0]
- 如果 pairs[i][0] > temp1 ,添加到数对链中,长度加1
- 如果 pairs[i][1] < temp1 , 可以使数对链最后一个数对的第二个数更小,则替换最后一个数对
- 其他的都跳过.
代码:(Java)
快排函数:
private static void quicksort(int[][] pairs, int left, int right) {//快排
// TODO Auto-generated method stub
int i = left, j = right;
if(i >= j)
return;
int temp1 = pairs[i][0], temp2 = pairs[i][1];
int a, b;
while(i != j) {
while(pairs[j][0] >= temp1 && i < j) {
j--;
}
while(pairs[i][0] <= temp1 && i < j) {
i++;
}
if(i < j) {
a = pairs[i][0];
b = pairs[i][1];
pairs[i][0] = pairs[j][0];
pairs[i][1] = pairs[j][1];
pairs[j][0] = a;
pairs[j][1] = b;
}
}
pairs[left][0] = pairs[i][0];
pairs[left][1] = pairs[i][1];
pairs[i][0] = temp1;
pairs[i][1] = temp2;
quicksort(pairs, left, i-1);
quicksort(pairs, i+1, right);
return;
}
}
法一:动态规划
import java.util.Arrays;
public class FindLongestChain {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] pairs = {{1,2}, {7,8}, {4,5}};
System.out.println(findLongestChain(pairs));
}
public static int findLongestChain(int[][] pairs) {
int n = pairs.length;
//Arrays.sort(pairs, (a,b)->(a[0] - b[0]));//冒泡排序
quicksort(pairs, 0, n-1);
int[] dp = new int[n];
Arrays.fill(dp, 1);
for(int i = 0; i < n; i++) {
for(int j = 0; j < i; j++) {
if(pairs[i][0] > pairs[j][1]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
return dp[n - 1];
}
法二:贪心
import java.util.Arrays;
public class FindLongestChain {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] pairs = {{1,2}, {7,8}, {4,5}};
System.out.println(findLongestChain(pairs));
}
public static int findLongestChain(int[][] pairs) {
int n = pairs.length;
//Arrays.sort(pairs, (a,b)->(a[0] - b[0]));//冒泡排序
quicksort(pairs, 0, n-1);
int len = 1;
int temp0 = pairs[0][0], temp1 = pairs[0][1];
for(int i = 1; i < n; i++) {
if(pairs[i][0] > temp1) {
len ++;
temp0 = pairs[i][0];
temp1 = pairs[i][1];
}else if(pairs[i][1] < temp1 ) {
temp0 = pairs[i][0];
temp1 = pairs[i][1];
}else {
continue;
}
}
return len;
}
运行结果:
力扣提交:
复杂度分析
法一:动态规划
-
时间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n 为 pairs 的长度。排序的时间复杂度为 O(nlogn),两层 for 循环的时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
-
空间复杂度:O(n),数组 dp的空间复杂度为 O(n)。
法二:贪心
-
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),其中 n 为 pairs 的长度。排序的时间复杂度为 O(nlogn)。
-
空间复杂度:O(1)。
注:仅供学习参考!
题目来源:力扣。