LeetCode --- 401周赛

题目列表

3178. 找出 K 秒后拿着球的孩子

3179. K 秒后第 N 个元素的值

3180. 执行操作可获得的最大总奖励 I

3181. 执行操作可获得的最大总奖励 II

一、找出K秒后拿着球的孩子

这题可以直接模拟,从前往后,再从后往前走k次,最后直接返回下标。或者我们可以直接计算,先算出球是从前往后走,还是从后往前走,然后判断球是第几个,返回下标即可,代码如下

//数学
class Solution {
public:
    int numberOfChild(int n, int k) {
        int m = k/(n-1), left = k%(n-1); // 因为起始下标是0,所以只要走n-1步就能到最后
        // m如果是奇数,说明是从后往前,如果是偶数,说明是从前往后
        return m&1 ? n - left - 1 : left; 
    }
};

// 模拟
class Solution {
public:
    int numberOfChild(int n, int k) {
        int i = 0, dir = -1;
        while(k){
            if(i <= 0|| i >= n-1) dir *= -1;
            i += dir;
            k--;
        }
        return i;
    }
};

二、K秒后第N个元素的值

这题可以直接模拟,就是求k次前缀和,返回最后一个元素,也可以直接用数学,去观察它,本质是在求一个组合数C(n+k-1,n-1),具体过程如下

代码如下

// 数学
const int MOD = 1e9+7;
int C[2001][2001]{};
int init=[]()->int{
    C[0][0] = 1;
    for(int i = 1; i < 2001; i++){
        C[i][0] = C[i][i] = 1;
        for(int j = 1; j <= i/2; j++){
            C[i][j] = C[i][i-j] = (C[i-1][j] + C[i-1][j-1])%MOD;
        }
    }
    return 0;
}();

class Solution {
public:
    int valueAfterKSeconds(int n, int k) {
        return C[n+k-1][k];
    }
};

// 模拟
class Solution {
    const int MOD = 1e9+7;
public:
    int valueAfterKSeconds(int n, int k) {
        vector<int> v(n,1);
        while(k--){
            for(int i=1;i<n;i++){
                v[i] = (v[i] + v[i-1])%MOD;
            }
        }
        return v.back();
    }
};

三、执行操作可获得的最大总奖励 I & II

这题和0-1背包很相似,状态定义为:dp[i][j]表示能否在前i个数中选出一些数使得它们的和为j

状态转移方程为

  • 不选nums[i],dp[i][j] = dp[i-1][j]
  • 选nums[i],dp[i][j] = dp[i-1][j-nums[i]],其中 0 <= j - nums[i] < nums[i]
  • 故dp[i][j] = dp[i-1][j] | dp[i-1][j-nums[i]]

代码如下

class Solution {
public:
    int maxTotalReward(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        nums.erase(unique(nums.begin(),nums.end()),nums.end()); // 无法选择多个相同的数
        int n = nums.size(), mx = ranges::max(nums);
        vector<vector<bool>> dp(n+1,vector<bool>(mx*2));
        dp[0][0] = true;
        int ans = 0;
        for(int i = 0; i < n; i++){
            for(int j = 0; j < 2*nums[i]; j++){ // 当 j >= 2*nums[i] 时,dp[i+1][j] = dp[i][j],根据递推,它们都是false,没必要更新
                dp[i+1][j] = dp[i][j];
                if(j >= nums[i]) dp[i+1][j] = dp[i+1][j] | dp[i][j - nums[i]];
            }
        }
        for(int i=mx*2-1;i>=0;i--)
            if(dp[n][i])
                return i;
        return -1;
    }
};
// 优化
class Solution {
public:
    int maxTotalReward(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        nums.erase(unique(nums.begin(),nums.end()),nums.end());
        int n = nums.size(), mx = ranges::max(nums);
        vector<bool>dp(mx*2);
        dp[0] =true;
        int ans = 0;
        for(int i = 0; i < n; i++){
            for(int j = nums[i]; j < 2*nums[i]; j++){
                dp[j] = dp[j] | dp[j - nums[i]];
            }
        }
        for(int i=mx*2-1;i>=0;i--)
            if(dp[i])
                return i;
        return -1;
    }
};

第四问的数据范围变大,我们还需要对时间复杂度进行优化,如何做???

根据上面的代码,我们只要维护一个2*mx大小的bool数组就可以,但是维护true / false其实只需要一个二进制位就能表示,我们可以将数组大小进行压缩,同时,一旦它用二进制来表示,我们的状态转移,就可以用二进制的 | 运算进行,即可以批量的进行,因为整数在cpu上计算时是以32位整型/64位整型进行或运算的,即速度会提升32倍/64倍,代码如下

class Solution {
public:
    int maxTotalReward(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        nums.erase(unique(nums.begin(),nums.end()),nums.end());
        int n = nums.size(), mx = ranges::max(nums);
        bitset<100000> f = 1;
        for(auto v:nums){
            int shift = f.size() - v;
            f |= f << shift >> shift << v;
        }
        for(int i = mx*2 - 1; i >= 0; i--)
            if(f.test(i))
                return i;
        return -1;
    }
};
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值