leetcode第388场周赛

3074. 重新分装苹果

先计算苹果总数是多少,然后将箱子按容量从大到小排序,然后直到把所有苹果装满为止的箱子数就是最少的。

class Solution {
public:
    int minimumBoxes(vector<int>& a, vector<int>& b) {
        //箱子容量从大到小排序
        sort(b.begin(), b.end());
        reverse(b.begin(), b.end());
        //苹果总数
        int sum = accumulate(a.begin(), a.end(), 0);
        for (int i = 0; i < b.size(); i++) {
            sum -= b[i];
            if (sum <= 0) return i + 1;
        }
        return 0;
    }
};

3075. 幸福值最大化的选择方案

每轮都选当前幸福值最大的孩子。因为你每轮选最大的那么你的损失是最小的。因为正常来说k轮损失的值是(k - 1) + (k - 2) + ... + 2 + 1 = (k - 1) * k / 2(每轮没选的每个孩子幸福值都减1了)。但是幸福值最小值为0,如果你后选幸福值小的孩子,有可能在k轮前他的幸福值就已经为0了,不会再减少了,这肯定是比后选幸福值大的方案是更优的。

class Solution {
public:
    long long maximumHappinessSum(vector<int>& a, int k) {
        //幸福值从大到小排序
        sort(a.begin(), a.end());
        reverse(a.begin(), a.end());
        long long ans = 0;
        //幸福值最小是0
        for (int i = 0; i < k; i++) ans += max(a[i] - i, 0); 
        return ans;
    }
};

3076. 数组中的最短非公共子字符串

n的范围很小,直接枚举每一个字串,然后用map记录。时间复杂度O(n^3)

class Solution {
public:
    vector<string> shortestSubstrings(vector<string>& arr) {
        int n = arr.size();
        //记录子串在不同字符串出现过的次数
        map<string, int> mp;
        //枚举每个字符串
        for (int i = 0; i < n; i++) {
            int m = arr[i].size();
            //nice数组是只将字符串相同的子串记录一次
            map<string, bool> nice;
            //记录每个不同的子串
            for(int j = 0; j < m; j++) {
                for (int len = 1; len + j  - 1 < m; len++) {
                    string substr = arr[i].substr(j, len);
                    if (nice[substr] == 1) continue;
                    mp[substr]++, nice[substr] = 1;
                }
            }
        }    
        //记录答案
        vector<string> ans(n, "");
        for (int i = 0; i < n; i++) {
            int m = arr[i].size();
            for(int j = 0; j < m; j++) {
                for (int len = 1; len + j  - 1 < m; len++) {
                    string substr = arr[i].substr(j, len);
                    if (mp[substr] == 1) {
                        if (ans[i] == "") ans[i] = substr;
                        else {
                            if (ans[i].length() > substr.length()) ans[i] = substr;
                            else if (ans[i].length() == substr.length()) ans[i] = min(ans[i], substr);
                        }
                    }
                }
            }
        }
        return ans;
    }
};

3077. K 个不相交子数组的最大能量值

动态规划。
首先前缀和数组s[],用于方便求一段连续数组的和。
状态设置:
设f[i][j]为前j个数中选i个不相交数组的最大能量值。
状态转移:
第i个数组第j个值(最后)不选:f[i][j] = f[i][j - 1];  
第i个数组第j个值选,此时我们就要枚举第i个数组的起点l。状态方程为:f[i][j] = max(f[i][j], (s[j] - s[l - 1]) * w + f[i - 1][l - 1]);
时间复杂度为O(n^3),超时。

       for (int i = 1; i <= k; i++) {
           f[i][i - 1] = LLONG_MIN;
           //w为题目要求的某一轮相乘的值
           int w = (k - i + 1) * (i % 2 ? 1 : -1);
           long long mx = LLONG_MIN;
           for (int j = i; j <= n; j++) {
               f[i][j] = f[i][j - 1];
               //第i组数组的起点至少是i,因为每个数组至少要1个数
               for (int l = i; l<= j; l++)
                    f[i][j] = max(f[i][j], (s[j] - s[l - 1]) * w + f[i - 1][l - 1]);
           }
       }

优化方程:
f[i][j] = max(f[i][j], (s[j] - s[l - 1]) * w + f[i - 1][l - 1]);

进行拆解:f[i][j] = s[j] * w + f[i - 1][l - 1] - s[l - 1] * w

我们只需要维护max(f[i - 1][l - 1] - s[l - 1] * w)[i <= l < = j],就可以省去枚举k的循环。因为k的每轮循环只比他上一轮循环只增加了一个数f[i - 1][j - 1] - s[j - 1] * w,我们在枚举j的过程中就可以维护好这个最大值,我们只需要用一个mx维护mx = max(mx, f[i - 1][j - 1] - s[j - 1] * w);就可以达到O(n^2)的时间复杂度了。
 

class Solution {
public:
    long long maximumStrength(vector<int> &nums, int k) {
       int n = nums.size();
       vector<long long> s(n + 1);
       for (int i = 0; i < n; i++) {
           s[i + 1] = s[i] + nums[i]; 
       }
       vector<vector<long long>> f(k + 1, vector<long long> (n + 1));
       for (int i = 1; i <= k; i++) {
           f[i][i - 1] = LLONG_MIN;
           int w = (k - i + 1) * (i % 2 ? 1 : -1);
           long long mx = LLONG_MIN;//最小值
           for (int j = i; j <= n; j++) {
               mx = max(mx, f[i - 1][j - 1] - s[j - 1] * w);
               f[i][j] = max(f[i][j - 1], mx + s[j] * w);
           }
       }
       return f[k][n];
    }
};

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值