最长上升子序列和

最长上升子序列长度

题意:给定一个无序的整数数组,找到其中最长上升子序列的长度。

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4

解法:这是一道经典的动态规划
状态表示:dp[i]表示序列前i个数(必须包含nums[i])的最长上升子序列长度
状态转移:dp[i] = max(dp[j] + 1), 0<=j<i && nums[j]<nums[i]
程序(CPP)

const int N = 1e5+10;
int dp[N];
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        int res = 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);
            res = max(res, dp[i]);
        }
        return res;
    }
};

带限制的子序列和

题意:给你一个整数数组 nums 和一个整数 k ,请你返回 非空 子序列元素和的最大值,子序列需要满足:子序列中每两个 相邻 的整数 nums[i] 和 nums[j] ,它们在原数组中的下标 i 和 j 满足 i < j 且 j - i <= k 。
数组的子序列定义为:将数组中的若干个数字删除(可以删除 0 个数字),剩下的数字按照原本的顺序排布。

输入:nums = [10,-2,-10,-5,20], k = 2
输出:23
解释:子序列为 [10, -2, -5, 20]

思路:与最长上升子序列问题一样
状态表示:dp[i]表示序列前i个数(必须包含nums[i])的带限制的子序列和最大值
状态转移:dp[i] = nums[i] + max(dp[j]), i-k<=j<i
朴素解法如下:

const int N = 1e5+10;
int dp[N];
class Solution {
public:
    int constrainedSubsetSum(vector<int>& nums, int k) {
        int n = nums.size();
        int res = nums[0];
        for(int i = 0; i < n; i++)
        {
            dp[i] = nums[i];
            for(int j = max(0, i - k); j < i; j++)
                dp[i] = max(dp[i], dp[j] + nums[i]);
            res = max(res, dp[i]);
        }
        return res;
    }
};

高级解法:状态转移方程为dp[i] = nums[i] + max(dp[j]), i-k<=j<i,暴力解法每次求max(dp[j]), i-k<=j<i都要遍历k个数,时间复杂度为O(nk)O(nk)。我们可以用优先队列维护max(dp[j]) i-k<=j<i,时间复杂度将为O(nlogk)O(nlogk),程序如下:

const int N = 1e5+10;
int dp[N];
class Solution {
public:
    int constrainedSubsetSum(vector<int>& nums, int k) {
        // 优先队列队首元素为{max(dp[j]), 对应最大dp[j]的下标}
        priority_queue<pair<int, int>> q;
        int n = nums.size();
        int res = nums[0];
        for(int i = 0; i < n; i++)
        {
            dp[i] = nums[i];
            // 下标与i距离超过k的以后永远不会用到,出队即可
            while(!q.empty() && i-q.top().second > k) q.pop();
            if(!q.empty()) dp[i] = max(dp[i], q.top().first + nums[i]);
            q.push({dp[i], i});
            res = max(res, dp[i]);
        }
        return res;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章