#day1 力扣每日一题

每个字符至少取K个

题干

给你一个由字符 'a''b''c' 组成的字符串 s 和一个非负整数 k 。每分钟,你可以选择取走 s 最左侧 还是 最右侧 的那个字符。

你必须取走每种字符 至少 k 个,返回需要的 最少 分钟数;如果无法取到,则返回 -1 。

示例 1:

输入:s = "aabaaaacaabc", k = 2
输出:8
解释:
从 s 的左侧取三个字符,现在共取到两个字符 'a' 、一个字符 'b' 。
从 s 的右侧取五个字符,现在共取到四个字符 'a' 、两个字符 'b' 和两个字符 'c' 。
共需要 3 + 5 = 8 分钟。
可以证明需要的最少分钟数是 8 。

示例 2:

输入:s = "a", k = 1
输出:-1
解释:无法取到一个字符 'b' 或者 'c',所以返回 -1 。

提示:

  • 1 <= s.length <= 105
  • s 仅由字母 'a''b''c' 组成
  • 0 <= k <= s.length

思路:

1、滑动窗口

2、left和right两个边界,其中需要注意的是,left包含在子串中而right不含在子串中。

3、tar数组表示a、b、c三个字母在字符串s中的总数量-k

4、如果cnt数组即任意三个字母的数量大于tar数组,则移动left边界且减去相应的cnt数量

代码:

using namespace std;
class Solution {
public:
    int takeCharacters(string s, int k) {
        int left=0,right=0;
        int max_len=0;   //用于记录满足条件的最大子串长度

        int total[3]={0};

        total[0]=count(s.begin(),s.end(),'a')-k;
        total[1]=count(s.begin(),s.end(),'b')-k;
        total[2]=count(s.begin(),s.end(),'c')-k;

        if(total[0] < 0 || total[1] < 0 || total[2]<0){
            return -1;
        }else if(total[0]==0 && total[1]==0 && total[2]==0){
            return s.length();
        }else{
            int cnt[3]={0};
            while(right<s.length()){
                cnt[s[right++]-'a']++;  //增加右指针字符的计数
                //检查当前窗口是否符合要求
                while(cnt[0]>total[0] || cnt[1]>total[1] || cnt[2]>total[2]){
                    cnt[s[left++]-'a']--;
                }
                max_len = max(max_len,right-left);  //left包含在子串中,right不包含在子串中,所以这里不用-1
            }
            return s.length()-max_len;

        }
    }
};

收获:

1、c++中判断字符串中某个字符的出现个数可以用count(s.begin(),s.end(),'a')

2、利用某个字符减去'a'直接得到各字符的数组的数字位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值