LeetCode 1425 Constrained Subsequence Sum (dp,滑动窗,推荐)

177 篇文章 0 订阅
60 篇文章 0 订阅

Given an integer array nums and an integer k, return the maximum sum of a non-empty subsequence of that array such that for every two consecutive integers in the subsequence, nums[i] and nums[j], where i < j, the condition j - i <= k is satisfied.

subsequence of an array is obtained by deleting some number of elements (can be zero) from the array, leaving the remaining elements in their original order.

Example 1:

Input: nums = [10,2,-10,5,20], k = 2
Output: 37
Explanation: The subsequence is [10, 2, 5, 20].

Example 2:

Input: nums = [-1,-2,-3], k = 1
Output: -1
Explanation: The subsequence must be non-empty, so we choose the largest number.

Example 3:

Input: nums = [10,-2,-10,-5,20], k = 2
Output: 23
Explanation: The subsequence is [10, -2, -5, 20].

Constraints:

  • 1 <= k <= nums.length <= 105
  • -104 <= nums[i] <= 104

题目链接:https://leetcode.com/problems/constrained-subsequence-sum/

题目大意:给一个数组,从中取数,要求相邻两数下标不超过k,求所能取得的数的和的最大值

题目分析:一开始想的做法是dp[i][0/1]表示位置i不取或取时的最大值,之后发现dp[i][1]不能通过dp[i][0]转移,因为dp[i][0]没法知道其之前某个位置是不是取了数字,于是直接将状态修改成dp[i]表示取第i个数字时的最大值,最后只要对dp数组求个max就是答案,现在的问题是相邻下标不超过k的限制如何实现,可以先写出转移方程:

dp[i] = max(nums[i], max(dp[i - 1], dp[i - 2], ..., dp[i - k]))

左边的nums[i]表示从i位置开始取,前面全不要

右边的max表示取i-1,i-2,一直到i-k的dp值,很明显的滑动窗,滑动窗维护区间最值可以参考这篇:https://blog.csdn.net/Tc_To_Top/article/details/82933983?spm=1001.2014.3001.5501

17ms,时间击败63.57%

class Solution {
    public int constrainedSubsetSum(int[] nums, int k) {
        int n = nums.length;
        int[] dp = new int[n];
        int ans = nums[0];
        dp[0] = nums[0];
        Deque<Integer> dq = new LinkedList<>();
        dq.offerFirst(0);
        //System.out.println("dp[0] = " + dp[0]);
        for (int i = 1; i < n; i++) {
            while (dq.size() != 0 && i - dq.peekFirst() > k) {
                dq.pollFirst();
            }
            dp[i] = Math.max(nums[i], nums[i] + dp[dq.peekFirst()]);
            //System.out.println("dp[" + i + "] = " + dp[i]);
            ans = Math.max(ans, dp[i]);
            while (dq.size() != 0 && dp[dq.peekLast()] < dp[i]) {
                dq.pollLast();
            }
            dq.offerLast(i);
        }
        return ans;
    }
}

改成用数组模拟双端队列后:

5ms,时间击败100%

class Solution {
    public int constrainedSubsetSum(int[] nums, int k) {
        int[] dp = new int[nums.length];
        int ans = nums[0];
        dp[0] = nums[0];
        int[] dq = new int[nums.length + 1];
        int l = 0, r = 0;
        dq[++r] = 0;
        for (int i = 1; i < nums.length; i++) {
            while (l <= r && i - dq[l] > k) {
                l++;
            }
            dp[i] = Math.max(nums[i], nums[i] + dp[dq[l]]);
            ans = Math.max(ans, dp[i]);
            while (l <= r && dp[dq[r]] < dp[i]) {
                r--;
            }
            dq[++r] = i;
        }
        return ans;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值