646. 最長數對鏈(動態規劃)
阿新 • • 發佈:2021-01-26
技術標籤:力扣
646. 最長數對鏈
題目
給出 n 個數對。 在每一個數對中,第一個數字總是比第二個數字小。
現在,我們定義一種跟隨關係,當且僅當 b < c 時,數對(c, d) 才可以跟在 (a, b) 後面。我們用這種形式來構造一個數對鏈。
給定一個數對集合,找出能夠形成的最長數對鏈的長度。你不需要用到所有的數對,你可以以任何順序選擇其中的一些數對來構造。
提示:
- 給出數對的個數在 [1, 1000] 範圍內。
解題思路
這題其實借用了 354.俄羅斯套娃信封問題的思想。我們需要對這個二維陣列的開始值進行升序排序,如果遇到相同的,就按照結束值進行降序排序,然後就得到了一個排序後的陣列。
我們這裡就可以用300.最長遞增子序列的方法來求出結果了。
需要注意的是if判斷那一塊:要注意用前一個的結束和後一個的開始去進行比較。因為這個單獨抽離成一個一維陣列比較麻煩,所以直接在這裡用這種方式進行比較。
/*用nums當前的開始去比較nums之前的 結束 。
[[1,2],[3,4]] 這就相當於用3去和2比較
*/
if (nums[j][1] < nums[i][0]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
程式碼
class Solution {
public int findLongestChain (int[][] pairs) {
int N = pairs.length;
if (N == 0) {
return 0;
}
Arrays.sort(pairs, new Comparator<int[]>() {
//按照每個區間的開始進行升序排列,若開始一樣,則按結束降序排列
public int compare(int[] a, int[] b) {
/*
a[0]、b[0]分別代表前一個、後一個數組的開始
a[1]、b[1]分別代表前一個、後一個數組的結束
*/
return a[0] == b[0] ? b[1] - a[1] : a[0] - b[0];
}
});
return lengthOfLIS(pairs);
}
//用來求最長遞增子序列。這裡稍微修改一下作為輔助方法
public int lengthOfLIS(int[][] nums) {
if (nums.length == 0) {
return 0;
}
int N = nums.length;
//dp[i]存放的是:以nums[i]結尾的最長遞增子序列的長度
int[] dp = new int[N];
//base case:將dp[]都初始化為1
Arrays.fill(dp, 1);
for (int i = 0; i < N; i++) {//i=N-1就是dp[]的最後一個元素了,原為dp[]的長度和nums[]的相同
for (int j = 0; j < i; j++) {
/*用nums當前的開始去比較nums之前的 結束
假設有[[1,2],[3,4]] 這就相當於用3去和2比較
*/
if (nums[j][1] < nums[i][0]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
int res = 0;
//來遍歷一次經過整理的dp[],找出最大值
for (int i = 0; i < dp.length; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}