天天看點

LeetCode300 最長上升子序列(DP)以及一些擴充題目

題目描述

給你一個整數數組 nums ,找到其中最長嚴格遞增子序列的長度。

子序列是由數組派生而來的序列,删除(或不删除)數組中的元素而不改變其餘元素的順序。例如,[3,6,2,7] 是數組 [0,3,1,6,2,2,7] 的子序列。

示例 1:

輸入:nums = [10,9,2,5,3,7,101,18]

輸出:4

解釋:最長遞增子序列是 [2,3,7,101],是以長度為 4 。

示例 2:

輸入:nums = [0,1,0,3,2,3]

輸出:4

示例 3:

輸入:nums = [7,7,7,7,7,7,7]

輸出:1

題解:

dp[i] 表示 前i 個元素最長上升子序列的長度,以第i 個元素為結尾。如何才能從dp[i-1] 轉移到 dp[ i ] 呢?當nums[i] > nums[j] 時,j 在[0,i-1] 之間。

即考慮往 dp[0…i−1] 中最長的上升子序列後面再加一個nums[i]。由于 dp[j] 代表 nums[0…j] 中以nums[j] 結尾的最長上升子序列,是以如果能從 dp[j] 這個狀态轉移過來,那麼 nums[i] 必然要大于nums[j],才能将 nums[i] 放在 nums[j] 後面以形成更長的上升子序列。

連結:https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/zui-chang-shang-sheng-zi-xu-lie-by-leetcode-soluti/
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n=nums.size();
        if(n==0) return n;
        int dp[n],res;
        
        for(int i=0;i<n;i++)
        {
            dp[i]=1;
            for(int j=0;j<i;j++)
            {
                if(nums[j]<nums[i])
                {
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
            res=max(res,dp[i]);
        }

        return res;
    }
};
           

leecode題解

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = (int)nums.size();
        if (n == 0) {
            return 0;
        }
        vector<int> dp(n, 0);
        for (int i = 0; i < n; ++i) {
            dp[i] = 1;
            for (int j = 0; j < i; ++j) {
                if (nums[j] < nums[i]) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
        }
        return *max_element(dp.begin(), dp.end());
    }
};
           

面試題 08.13. 堆箱子

堆箱子。給你一堆n個箱子,箱子寬 wi、深 di、高 hi。箱子不能翻轉,将箱子堆起來時,下面箱子的寬度、高度和深度必須大于上面的箱子。實作一種方法,搭出最高的一堆箱子。箱堆的高度為每個箱子高度的總和。輸入使用數組[wi, di, hi]表示每個箱子。

示例1:

輸入:box = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]

輸出:6

示例2:

輸入:box = [[1, 1, 1], [2, 3, 4], [2, 6, 7], [3, 4, 5]]

輸出:10

class Solution {
public:
    int pileBox(vector<vector<int>>& box) {
        sort(box.begin(),box.end());
        int n=box.size();
        vector<int> dp(n,0);
        for(int i=0;i<n;i++) dp[i]=box[i][2];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(box[i][0]>box[j][0] && box[i][1]>box[j][1] && box[i][2]>box[j][2])
                {
                    dp[i]=max(dp[i],dp[j]+box[i][2]);
                }
            }
        }
        return *max_element(dp.begin(),dp.end());
    }
};
           

435. 無重疊區間

給定一個區間的集合,找到需要移除區間的最小數量,使剩餘區間互不重疊。

注意:可以認為區間的終點總是大于它的起點。

區間 [1,2] 和 [2,3] 的邊界互相“接觸”,但沒有互相重疊。

示例 1:

輸入: [ [1,2], [2,3], [3,4], [1,3] ]

輸出: 1

解釋: 移除 [1,3] 後,剩下的區間沒有重疊。

示例 2:

輸入: [ [1,2], [1,2], [1,2] ]

輸出: 2

解釋: 你需要移除兩個 [1,2] 來使剩下的區間沒有重疊。

示例 3:

輸入: [ [1,2], [2,3] ]

輸出: 0

解釋: 你不需要移除任何區間,因為它們已經是無重疊的了。

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
         sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[1] == b[1] ? a[0] < b[0] : a[1] < b[1];
        });
        int n=intervals.size();
        int left=intervals[0][0],cnt=0;
        for(auto x:intervals)
        {
            if(x[0]>=left)
            {
                cnt++;
                left=x[1];
            }
        }
        return n-cnt;
    }
};
           

最長上升子序列擴充題目:646. 最長數對鍊,452. 用最少數量的箭引爆氣球,354. 俄羅斯套娃信封問題,960. 删列造序 III