LeetCode 每日一题 Day 47 - 50

2171. 拿出最少数目的魔法豆

给定一个 正整数 数组 beans ,其中每个整数表示一个袋子里装的魔法豆的数目。

请你从每个袋子中 拿出 一些豆子(也可以 不拿出),使得剩下的 非空 袋子中(即 至少还有一颗 魔法豆的袋子)魔法豆的数目 相等。一旦把魔法豆从袋子中取出,你不能再将它放到任何袋子中。

请返回你需要拿出魔法豆的 最少数目。

示例 1:

输入:beans = [4,1,6,5]
输出:4
解释:

  • 我们从有 1 个魔法豆的袋子中拿出 1 颗魔法豆。
    剩下袋子中魔法豆的数目为:[4,0,6,5]
  • 然后我们从有 6 个魔法豆的袋子中拿出 2 个魔法豆。
    剩下袋子中魔法豆的数目为:[4,0,4,5]
  • 然后我们从有 5 个魔法豆的袋子中拿出 1 个魔法豆。
    剩下袋子中魔法豆的数目为:[4,0,4,4]
    总共拿出了 1 + 2 + 1 = 4 个魔法豆,剩下非空袋子中魔法豆的数目相等。
    没有比取出 4 个魔法豆更少的方案。
    示例 2:

输入:beans = [2,10,3,2]
输出:7
解释:

  • 我们从有 2 个魔法豆的其中一个袋子中拿出 2 个魔法豆。
    剩下袋子中魔法豆的数目为:[0,10,3,2]
  • 然后我们从另一个有 2 个魔法豆的袋子中拿出 2 个魔法豆。
    剩下袋子中魔法豆的数目为:[0,10,3,0]
  • 然后我们从有 3 个魔法豆的袋子中拿出 3 个魔法豆。
    剩下袋子中魔法豆的数目为:[0,10,0,0]
    总共拿出了 2 + 2 + 3 = 7 个魔法豆,剩下非空袋子中魔法豆的数目相等。
    没有比取出 7 个魔法豆更少的方案。

提示:

1 <= beans.length <= 1e5
1 <= beans[i] <= 1e5

枚举即可:

class Solution {
public:
    long long minimumRemoval(vector<int>& beans) {
        sort(beans.begin(), beans.end());
        long long s = accumulate(beans.begin(), beans.end(), 0ll);
        long long ans = s;
        int n = beans.size();
        for (int i = 0; i < n; ++i) {
            ans = min(ans, s - 1ll * beans[i] * (n - i));
        }
        return ans;
    }
};

2809. 使数组和小于等于 x 的最少时间(Hard)

给你两个长度相等下标从 0 开始的整数数组 nums1 和 nums2 。每一秒,对于所有下标 0 <= i < nums1.length ,nums1[i] 的值都增加 nums2[i] 。操作 完成后 ,你可以进行如下操作:

选择任一满足 0 <= i < nums1.length 的下标 i ,并使 nums1[i] = 0 。
同时给你一个整数 x 。

请你返回使 nums1 中所有元素之和 小于等于 x 所需要的 最少 时间,如果无法实现,那么返回 -1 。

示例 1:

输入:nums1 = [1,2,3], nums2 = [1,2,3], x = 4
输出:3
解释:
第 1 秒,我们对 i = 0 进行操作,得到 nums1 = [0,2+2,3+3] = [0,4,6] 。
第 2 秒,我们对 i = 1 进行操作,得到 nums1 = [0+1,0,6+3] = [1,0,9] 。
第 3 秒,我们对 i = 2 进行操作,得到 nums1 = [1+1,0+2,0] = [2,2,0] 。
现在 nums1 的和为 4 。不存在更少次数的操作,所以我们返回 3 。
示例 2:

输入:nums1 = [1,2,3], nums2 = [3,3,3], x = 4
输出:-1
解释:不管如何操作,nums1 的和总是会超过 x 。

提示:

1 <= nums1.length <= 1e3
1 <= nums1[i] <= 1e3
0 <= nums2[i] <= 1e3
nums1.length == nums2.length
0 <= x <= 1e6

这个题目实在不会,看了题解是排序+DP:

class Solution {
public:
    int minimumTime(vector<int> &nums1, vector<int> &nums2, int x) {
        int n = nums1.size();
        vector<int> ids(n);
        iota(ids.begin(), ids.end(), 0);
        sort(ids.begin(), ids.end(), [&](const int i, const int j) {
            return nums2[i] < nums2[j];
        });

        vector<int> f(n + 1);
        for (int i = 0; i < n; i++) {
            int a = nums1[ids[i]], b = nums2[ids[i]];
            for (int j = i + 1; j; j--) {
                f[j] = max(f[j], f[j - 1] + a + b * j);
            }
        }

        int s1 = accumulate(nums1.begin(), nums1.end(), 0);
        int s2 = accumulate(nums2.begin(), nums2.end(), 0);
        for (int t = 0; t <= n; t++) {
            if (s1 + s2 * t - f[t] <= x) {
                return t;
            }
        }
        return -1;
    }
};

这里附上 灵神的题解:教你一步步思考本题!

2788. 按分隔符拆分字符串

给你一个字符串数组 words 和一个字符 separator ,请你按 separator 拆分 words 中的每个字符串。

返回一个由拆分后的新字符串组成的字符串数组,不包括空字符串 。

注意

separator 用于决定拆分发生的位置,但它不包含在结果字符串中。
拆分可能形成两个以上的字符串。
结果字符串必须保持初始相同的先后顺序。

示例 1:

输入:words = [“one.two.three”,“four.five”,“six”], separator = “.”
输出:[“one”,“two”,“three”,“four”,“five”,“six”]
解释:在本示例中,我们进行下述拆分:

“one.two.three” 拆分为 “one”, “two”, “three”
“four.five” 拆分为 “four”, “five”
“six” 拆分为 “six”

因此,结果数组为 [“one”,“two”,“three”,“four”,“five”,“six”] 。
示例 2:

输入:words = [“ e a s y easy easy”,“ p r o b l e m problem problem”], separator = “$”
输出:[“easy”,“problem”]
解释:在本示例中,我们进行下述拆分:

e a s y easy easy” 拆分为 “easy”(不包括空字符串)
p r o b l e m problem problem” 拆分为 “problem”(不包括空字符串)

因此,结果数组为 [“easy”,“problem”] 。
示例 3:

输入:words = [“|||”], separator = “|”
输出:[]
解释:在本示例中,“|||” 的拆分结果将只包含一些空字符串,所以我们返回一个空数组 [] 。

提示:

1 <= words.length <= 100
1 <= words[i].length <= 20
words[i] 中的字符要么是小写英文字母,要么就是字符串 “.,|KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲@" 中的字符(不包括引号) …#@” 中的某个字符(不包括引号)

模拟就行:

class Solution {
public:
    vector<string> splitWordsBySeparator(vector<string>& words, char separator) {
        vector<string> ans;
        for(string str : words){
            string cur;
            for(char ch : str){
                if(ch == separator){
                    if(!cur.empty())
                        ans.push_back(cur);
                    cur.clear();
                }else{
                    cur += ch;
                }
            }
            if(cur.size() != 0)
                ans.push_back(cur);
        }
        return ans;
    }
};

410. 分割数组的最大值(Hard)

给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组。

设计一个算法使得这 k 个子数组各自和的最大值最小。

示例 1:

输入:nums = [7,2,5,10,8], k = 2
输出:18
解释:
一共有四种方法将 nums 分割为 2 个子数组。
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。
因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。
示例 2:

输入:nums = [1,2,3,4,5], k = 2
输出:9
示例 3:

输入:nums = [1,4,4], k = 3
输出:4

提示:

1 <= nums.length <= 1000
0 <= nums[i] <= 106
1 <= k <= min(50, nums.length)

二分(看题解DP也行):

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        long l = nums[0], h = 0;
        for (auto i : nums)
        {
            h += i;
            l = l > i ? l : i;
        }
        while (l<h)
        {
            long mid = (l + h) / 2;
            long temp = 0;
            int cnt = 1;//初始值必须为1
            for(auto i:nums)
            {
                temp += i;
                if(temp>mid)
                {
                    temp = i;
                    ++cnt;
                }
            }
            if(cnt>m)
                l = mid + 1;
            else
                h = mid;
        }
        return l;
    }
};

你可能感兴趣的:(LeetCode,leetcode,算法)