leetcode 考试的最大困扰度

题目

一位老师正在出一场由 n 道判断题构成的考试,每道题的答案为 true (用 ‘T’ 表示)或者 false (用 ‘F’ 表示)。老师想增加学生对自己做出答案的不确定性,方法是 最大化 有 连续相同 结果的题数。(也就是连续出现 true 或者连续出现 false)。

给你一个字符串 answerKey ,其中 answerKey[i] 是第 i 个问题的正确结果。除此以外,还给你一个整数 k ,表示你能进行以下操作的最多次数:

每次操作中,将问题的正确答案改为 ‘T’ 或者 ‘F’ (也就是将 answerKey[i] 改为 ‘T’ 或者 ‘F’ )。
请你返回在不超过 k 次操作的情况下,最大 连续 ‘T’ 或者 ‘F’ 的数目
跳转链接

做法

个人拙劣做法

首先如果序列是 TTTFFTTT , 我们可以从左到右进行搜索,如果中间存在其他不一样的字符,那么就用替换,继续让len++, 最后替换次数用完了,就 break ,进行下一次搜索。这里也是有技巧的,我们可以记录一下第一次出现不一样字符的位置p,选择p+1这个位置作为下一次搜索的起始位置。
想法比较粗糙,没有啥出彩的地方,最后一个例子还超时了
这里贴一下代码,学习一下

class Solution {
public:
    int maxConsecutiveAnswers(string answerKey, int k) {
        int value = max(count(answerKey,k,'F'),count(answerKey,k,'T'));
        return (value <= answerKey.length() ? value : answerKey.length());
    }

    int count(string answerKey,int k,char c){
        int maxlen = 1; //记录整个过程中的最大长度
        int start = 0; //每次开始的索引
        while(start<answerKey.length()){
            int s = start; // 记录刚开始索引

            /* 如果不是目标,那就跳过*/
            if(answerKey[start] == c) {
                start++;
                continue;
            }

            int len = 1; //此循环的长度
            int t = k; // 记录剩余的替换次数

            /*记录下一段T的索引值*/
            int first_index = 0;
            bool flag = false;

            //向下寻找
            for(int j = start+1; j<answerKey.length();j++){
                if(answerKey[j] == c) {
                    if(t == 0) break;
                    start = j;
                    if(!flag){
                        first_index = start;
                        flag = true;
                    }
                    --t;
                }
                len++;
            }
            
            maxlen = max(maxlen,len + (t>s ? s:t ));
            if(flag) start = first_index;
            start++;
        }
        return maxlen;
    }
};

题解

题解用的是熟悉的滑动窗口的算法,这里讲一下滑动窗口的原理

滑动窗口

这里主要参考的是这篇文章
滑动窗口,顾名思义,就是有一个大小可变的窗口,左右两端方向一致的向前滑动(右端固定,左端滑动;左端固定,右端滑动)。 可以想象成队列,一端在push元素,另一端在pop元素

常用范围为:

  1. 一般是字符串或者列表
  2. 一般是要求最值(最大长度,最短长度等等)或者子序列

基本的算法思想是这样子的:
1.在序列中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为一个窗口。
2、先不断地增加 right 指针扩大窗口 [left, right],直到窗口中的序列符合要求。
3、此时,停止增加 right,转而不断增加 left 指针缩小窗口 [left, right],直到窗口中的序列不再符合要求。同时,每次增加 left前,都要更新一轮结果。
4、重复第 2 和第 3 步,直到 right 到达序列的尽头

思路其实很简单:第 2 步相当于在寻找一个可行解,然后第 3 步在优化这个可行解,最终找到最优解。左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动。

题解代码

class Solution {
public:
    int maxConsecutiveAnswers(string answerKey, int k) {
        int value = max(count(answerKey,k,'F'),count(answerKey,k,'T'));
        return (value <= answerKey.length() ? value : answerKey.length());
    }

    int count(string& answerKey,int k,char c){
        int len = 1;
        for(int left = 0, right = 0, sum = 0;right<answerKey.length();right++){
            sum += (answerKey[right] != c);
            while(sum > k){
                sum -= (answerKey[left++] != c);
            }
            len = max(len,right-left+1);
        }
        return len;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值