算法训练:贪心

1.1221. 分割平衡字符串

原题链接

          在一 平衡字符串 中,‘L’ 和 ‘R’ 字符的数量是相同的。
          给你一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。
          注意:分割得到的每个字符串都必须是平衡字符串,且分割得到的平衡字符串是原平衡字符串的连续子串。
          返回可以通过分割得到的平衡字符串的 最大数量 。
示例 1:
输入:s = “RLRRLLRLRL”
输出:4
解释:s 可以分割为 “RL”、“RRLL”、“RL”、“RL” ,每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’ 。
示例 2:
输入:s = “RLLLLRRRLR”
输出:3
解释:s 可以分割为 “RL”、“LLLRRR”、“LR” ,每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’ 。
示例 3:
输入:s = “LLLLRRRR”
输出:1
解释:s 只能保持原样 “LLLLRRRR”.
示例 4:
输入:s = “RLRRRLLRLL”
输出:2
解释:s 可以分割为 “RL”、“RRRLLRLL” ,每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’ 。
提示:
1 <= s.length <= 1000
s[i] = ‘L’ 或 ‘R’
s 是一个 平衡 字符串

          经典的括号匹配类型的问题,甚至比经典的括号匹配更简单。一个字符串是平衡字符串,那么在字符串中L的数量要等于R,扫描一边数组并记录即可。

class Solution {
public:
    int balancedStringSplit(string s) {
        int ans=0;
        int cntr=0,cntl=0;
        for(int i=0;i<s.size();i++){
            s[i]=='R'?cntr++:cntl++;
            if(cntr==cntl){
                cntr=cntl=0;
                ans++;
            }
        }
        return ans;
    }
};

2.1827. 最少操作使数组递增

原题链接

          给你一个整数数组 nums (下标从 0 开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。
          比方说,如果 nums = [1,2,3] ,你可以选择增加 nums[1] 得到 nums = [1,3,3] 。
          请你返回使 nums 严格递增 的 最少 操作次数。
          我们称数组 nums 是 严格递增的 ,当它满足对于所有的 0 <= i < nums.length - 1 都有 nums[i] < nums[i+1] 。一个长度为 1 的数组是严格递增的一种特殊情况。
示例 1:
输入:nums = [1,1,1]
输出:3
示例 2:
输入:nums = [1,5,2,4,1]
输出:14
示例 3:
输入:nums = [8]
输出:0

         按照题目模拟即可,遍历一遍数组如果当前数字比之前的小或相等就把他变成前一个数字加1,否则更新前一个数字。

class Solution {
public:
    int minOperations(vector<int>& nums) {
        if(nums.size()==0){
            return 0;
        }
        int ans=0;
        int prev=nums[0];
        for(int i=1;i<nums.size();++i){
            if(prev>=nums[i]){
                ans+=prev-nums[i]+1;
                prev++;
            }else prev=nums[i];
        }
        return ans;
    }
};

3.2144. 打折购买糖果的最小开销

原题链接

         一家商店正在打折销售糖果。每购买 两个 糖果,商店会 免费 送一个糖果。
         免费送的糖果唯一的限制是:它的价格需要小于等于购买的两个糖果价格的 较小值 。
         比方说,总共有 4 个糖果,价格分别为 1 ,2 ,3 和 4 ,一位顾客买了价格为 2 和 3 的糖果,那么他可以免费获得价格为 1 的糖果,但不能获得价格为 4 的糖果。
         给你一个下标从 0 开始的整数数组 cost ,其中 cost[i] 表示第 i 个糖果的价格,请你返回获得 所有 糖果的 最小 总开销。
示例 1:
输入:cost = [1,2,3]
输出:5
解释:我们购买价格为 2 和 3 的糖果,然后免费获得价格为 1 的糖果。
总开销为 2 + 3 = 5 。这是开销最小的 唯一 方案。
注意,我们不能购买价格为 1 和 3 的糖果,并免费获得价格为 2 的糖果。
这是因为免费糖果的价格必须小于等于购买的 2 个糖果价格的较小值。
示例 2:
输入:cost = [6,5,7,9,2,2]
输出:23

         首先我们为了充分利用条件,也就是想要使得免费获得的糖果价格最高,那么我们就要依次选择糖果价格最高的两个,并免费获得剩下的价格最高的糖果。至于为什么不依次买价格最小的两个或者是价格最大和最小的两个是因为如果是这样那么就无法免费获得任何一个糖果了得不偿失。

class Solution {
public:
    int minimumCost(vector<int>& cost) {
        sort(cost.begin(),cost.end(),[&](const int& a,const int &b){
            return a>b;
        });
        int ans=0;
        for(int i=0;i<cost.size();++i){
            ans+=cost[i];
            if(i<cost.size()-1){
                ans+=cost[i+1];
                i+=2;
            }
        }
        return ans;
    }
};

4.1400. 构造 K 个回文字符串

原题链接

         给你一个字符串 s 和一个整数 k 。请你用 s 字符串中 所有字符 构造 k 个非空 回文串 。
         如果你可以用 s 中所有字符构造 k 个回文字符串,那么请你返回 True ,否则返回 False 。
示例 1:
输入:s = “annabelle”, k = 2
输出:true
解释:可以用 s 中所有字符构造 2 个回文字符串。
一些可行的构造方案包括:“anna” + “elble”,“anbna” + “elle”,“anellena” + “b”
示例 2:
输入:s = “leetcode”, k = 3
输出:false
解释:无法用 s 中所有字符构造 3 个回文串。
示例 3:
输入:s = “true”, k = 4
输出:true
解释:唯一可行的方案是让 s 中每个字符单独构成一个字符串。
示例 4:
输入:s = “yzyzyzyzyzyzyzy”, k = 2
输出:true
解释:你只需要将所有的 z 放在一个字符串中,所有的 y 放在另一个字符串中。那么两个字符串都是回文串。
示例 5:
输入:s = “cr”, k = 7
输出:false
解释:我们没有足够的字符去构造 7 个回文串。
提示:
1 <= s.length <= 10^5
s 中所有字符都是小写英文字母。
1 <= k <= 10^5

         其实这道题看起来十分复杂,又是回文又是要在整个字符串里面构造出来k个回文串,单单是一个回文可能我们以前在做的时候就很烦了。
         现在我们分析原字符串s,先把其中的每个字符出现的频率映射到一个数组hash中去。现在将其出现次数分为奇数次和偶数次,对于偶数次的字母我们不用管,因为他们之间组合总能构成一个回文串。而对于奇数组的字母,有他们参与构造的回文串就有一下两种形式 :
         1.该字母单独构成一个回文串,比如“aaa”,“aa",“aaaaa”
         2.将该字母插入到某个由任意个偶数构成的一个回文串中比如"bbcbb",“aabbcccbba    a”,“cceeeeeefeeeeeecc”.
         现在我们开始思考构造的回文串个数和偶数字符以及奇数字符的个数之间的关系。从上面的例子可以看出,偶数字符在构造回文串的过程中起到的往往是辅助作用,因为一个回文串可以仅仅只有偶数字符组成也可以有由若干个偶数字符组成,更可以由若干个偶数字符和一个奇数字符组成。所以某个偶数字符可以任意添加到某个已经构成的回文串中,不影响最终个数。所以这里仅仅考虑奇数字符的个数。
         那么接下来就十分简单了,我们统计字符串中奇数字符的个数,如果有小于等于K个的奇数字符,就一定可以将字符串中所有字符用完构成k个回文串,但是大于了K个就绝对无法将所有字符用完构成k个回文串。另外,如果字符串中没有出现频率是奇数的字符,这个时候该怎么办?这就代表此时字符串中全为偶数个字符,将他们任意拆分,一定可以构成k个回文串,比如s=”aabb",k=3,那么我们的回文串可以为“a",“a”,“bb"或者"b”,“b”,“aa”,这个时候也返回true。

class Solution {
public:
    bool canConstruct(string s, int k) {
        if(k>s.size()){
            return false;
        }
        int hash[26];
        int i;
        int num=0;
        memset(hash,0,sizeof(hash));
        for(i=0;i<s.size();i++){
            ++hash[s[i]-'a'];
        }
        for(i=0;i<26;++i){
            if(((hash[i]%2)&1)){
                num++;
            }
        }
        return num<=k||num==0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值