题目
给出 n 个数对。 在每一个数对中,第一个数字总是比第二个数字小。
现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面。我们用这种形式来构造一个数对链。
给定一个数对集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
示例:
输入:[[1,2], [2,3], [3,4]]
输出:2
解释:最长的数对链是 [1,2] -> [3,4]
题解一 dp
class Solution {
public int findLongestChain(int[][] pairs) {
//状态转移方程:dp[k]表示前k个数组中能组成的最长数对链的长度,
//if(pairs[k][0]>pairs[k-1][1]) dp[k]=dp[k-1]+1;
if(pairs.length<=1)return pairs.length;
Arrays.sort(pairs,(a,b)->a[0]-b[0]);
int[] dp=new int[pairs.length];
Arrays.fill(dp,1);
for(int i=1;i<pairs.length;i++){
for(int j=0;j<i;j++){
if(pairs[j][1]<pairs[i][0]){
dp[i]=Math.max(dp[i],dp[j]+1);
}
}
}
Arrays.sort(dp);
return dp[dp.length-1];
}
}
笔记:
- 最长递增子序列惯用的状态转移方程:若i<j时,num[i]<num[j],num[j]=max(num[j],num[i+1])
题解二 贪心
class Solution {
public int findLongestChain(int[][] pairs) {
//贪心算法
if(pairs.length<=1)return pairs.length;
Arrays.sort(pairs,(a,b)->a[1]-b[1]);
int ans=0;
int compare=Integer.MIN_VALUE;
for(int[] pair:pairs){
if(compare<pair[0]){
compare=pair[1];//此处指的是比较前一个数组的第二个数是不是小于后一个数组的第一个数
ans++;
}
}
return ans;
}
}
笔记:
- 贪心,按右边界升序,当前右边界越小,下一个选择的范围就越大。局部最优到整体最优。
- 在所有可作为下一个数对的集合中选择第二个数最小的数对添加到数对链。