【力扣周赛】第 353 场周赛


https://leetcode.cn/contest/weekly-contest-353

Q1:6451. 找出最大的可达成数字(脑筋急转弯?)

https://leetcode.cn/problems/find-the-maximum-achievable-number/
在这里插入图片描述

思路——数学(脑筋急转弯?)

每次可以将差异减少2,一共可以操作 t 次,所以可达成的数字范围是:
[ x − 2 ∗ t , x + 2 ∗ t ] [x - 2 * t, x + 2 * t] [x2t,x+2t]
其中的最大值是 x + 2 ∗ t x + 2 * t x+2t

竞赛时代码

class Solution {
    public int theMaximumAchievableX(int num, int t) {
        return num + 2 * t;
    }
}

在这里插入图片描述

Q2:6899. 达到末尾下标所需的最大跳跃次数(DP)

https://leetcode.cn/problems/maximum-number-of-jumps-to-reach-the-last-index/

在这里插入图片描述

最开始想错方向了!以为是 BFS 求最短路!
结果是求最长路。。。

思路——DP

数据范围是 1000 1000 1000
可以选择 O ( n 2 ) O(n^2) O(n2) 的时间复杂度的算法。

枚举每个位置,在枚举每个位置时检查可以从前面哪些位置转移过来,并更新达到当前位置所需的最大跳跃次数。

dp数组初始化 为 -1,表示到不了这个位置,dp[0] = 0,表示不用跳就能到。

状态转移方程为: d p [ i ] = M a t h . m a x ( d p [ i ] , d p [ j ] + 1 ) ; dp[i] = Math.max(dp[i], dp[j] + 1); dp[i]=Math.max(dp[i],dp[j]+1);,表示能从 j 跳过来那跳跃次数就 + 1。

竞赛时代码——DP

class Solution {
    public int maximumJumps(int[] nums, int target) {
        int n = nums.length;
        int[] dp = new int[n];  // dp[i]表示达到i的最大跳跃次数
        Arrays.fill(dp, -1);    // -1表示到不了这个位置
        dp[0] = 0;
        for (int i = 1; i < n; ++i) {
            for (int j = 0; j < i; ++j) {
                // 能从j跳过来且j可以被达到
                if (Math.abs(nums[i] - nums[j]) <= target && dp[j] != -1) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
        }
        return dp[n - 1];
    }
}

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n ) O(n) O(n)

Q3:6912. 构造最长非递减子数组(DP)

https://leetcode.cn/problems/longest-non-decreasing-subarray-from-two-arrays/

在这里插入图片描述

思路

看数据范围,大概率使用 O ( n ) O(n) O(n) 的算法。

考虑 DP。

dp[i][0] 表示 第 i 个位置选 nums1[i] 和 nums2[i] 中较值时,以nums3[i]为结尾的最大子数组长度
dp[i][1] 表示 第 i 个位置选 nums1[i] 和 nums2[i] 中较值时,以nums3[i]为结尾的最大子数组长度

枚举每个下标 i,则要么选择 n u m s 1 [ i ] nums1[i] nums1[i],要么选择 n u m s 2 [ i ] nums2[i] nums2[i],选择时的最大长度可以从上个状态 i − 1 i - 1 i1 转移过来。
通过比较数值大小判断能否转移,如果能够转移过来,那长度为 M a t h . m a x ( d p [ i ] , d p [ j ] + 1 ) Math.max(dp[i], dp[j] + 1) Math.max(dp[i],dp[j]+1)

竞赛时代码

class Solution {
    public int maxNonDecreasingLength(int[] nums1, int[] nums2) {
        int n = nums1.length, ans = 1, last = Math.min(nums1[0], nums2[0]);
        int[][] dp = new int[n][2];
        dp[0][1] = dp[0][0] = 1;        // 分别记录当前选较小值或最大值时的最大长度
        int lastmn = Math.min(nums1[0], nums2[0]), lastmx = Math.max(nums1[0], nums2[0]);
        for (int i = 1; i < n; ++i) {
            dp[i][0] = dp[i][1] = 1;
            int mn = Math.min(nums1[i], nums2[i]), mx = Math.max(nums1[i], nums2[i]);
            // 检查是否可以状态转移过来
            if (mn >= lastmn) dp[i][0] = Math.max(dp[i][0], dp[i - 1][0] + 1);
            if (mn >= lastmx) dp[i][0] = Math.max(dp[i][0], dp[i - 1][1] + 1);
            if (mx >= lastmn) dp[i][1] = Math.max(dp[i][1], dp[i - 1][0] + 1);
            if (mx >= lastmx) dp[i][1] = Math.max(dp[i][1], dp[i - 1][1] + 1);
            lastmn = mn;
            lastmx = mx;
            ans = Math.max(ans, Math.max(dp[i][0], dp[i][1]));
        }
        return ans;
    }
}

可以看到 dp[i] 的状态只会从 dp[i - 1] 转移过来,即无后效性,可以优化 dp 数组成变量节省空间。

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

Q4:6919. 使数组中的所有元素都等于零

https://leetcode.cn/problems/apply-operations-to-make-all-array-elements-equal-to-zero/
在这里插入图片描述
提示:

1 <= k <= nums.length <= 10^5
0 <= nums[i] <= 10^6

思路——贪心+记录每个数字对之后的影响

我们从前往后枚举,当前数字 < 0 时返回 false, == 0 时不需要操作, > 0 时一定是减到 0的。(贪心)

每个位置 i 减去一个数字时,后面紧接着的 k - 1 个数字(也就是以 i 为开头的大小为 k 的窗口内的其它所有数字)。

我们用一个变量 sum 记录前面 k - 1 个数字对 i 的影响。


或者解释说:

对于位置靠前的数,如果前面的数的操作都不足以让其减为0(小于0直接返回False),则直接在当前位置操作(如果不在此处操作,后面的操作无法影响前面),用前缀和记录一下修改的数值即可。

竞赛时代码

class Solution {
    public boolean checkArray(int[] nums, int k) {
        int n = nums.length, sum = 0;   // sum是当前位置被前面k-1个位置影响减去的数值
        int[] d = new int[n];
        for (int i = 0; i < n; ++i) {
            // sum减去被移除窗口位置对应元素贡献的减去值,因为i-k影响不到i
            if (i >= k) sum -= d[i - k];        
            
            // nums[i]会被前面的数值影响减成负数,不合理
            if (nums[i] < sum) return false; 

            // 如果是最后k-1个数字,直接判断是否为0
            // 因为长度不够k了,所以最后的k-1个元素不能操作了。(不能作为窗口开始位置)
            if (nums[i] - sum != 0 && i > n - k) return false;   
            else {
                // 计算num[i]还需要减多少到0
                d[i] = nums[i] - sum;               
                sum += d[i];
            }
        }
        return true;
    }
}

在这里插入图片描述

成绩记录

在这里插入图片描述

4道 easy 题,但是我是傻逼!写的也太慢了!老是想歪。

写题的顺序是 1 2 4 3

第一题 39 s,多么美妙的开局!
但是!
怎么第 2 题是DP呀?
第 2 题是 DP 就算了怎么第 3 题还是 DP 呀?你会不会出点别的题!?

凎!

在这里插入图片描述

结束之后看了下别人写的题解,基本上和我也差不多,所以就还好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei *

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值