带有转换操作的01字符串,求连续1子串的最大长度

本文探讨了一道编程题目,即在给定01字符串中进行k次0到1的转换,目标是找出经过转换后最长的连续1子串。文章通过实例解释了问题,并提出了一种高效的解决方案,利用相邻0的概念简化了搜索过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

昨晚有两道题没有做出来。其中一题是01字符串的输入,求经过转换后连续1的子串的最大长度。结束之后和同学讨论,得出了一个非常满意的结果。

问题重述

输入是一个01字符串s,其中可以做k次转换操作(将0变成1),求经过k次转换之后能够得到的最长的连续1子串的长度。

示例1:

输入:101010101 3
输出:7
注:可以对字符串做3次转换操作,可有111111101或111110111或111011111或101111111四种操作,最长的连续1子串为7个1.

示例2:

输入:11010111001010 2
输出:8
注:将前两个0变成1,则得到11111111001010,有8个1连续,其余的操作都得不到更多的,所以输出为8。

解决方法

最开始看到这道题,基本没啥思路,就想着要不要暴力求解,把所有的情况列出来然后再向动态规划和贪心方向优化,以及是否可以二分递归地做下去。但是后面变量的值可能很大,就会导致整个搜索空间很复杂,展开过程也比较繁琐。然后和另一名同学进行了友好地辩论,在辩论中发现了一个规律,正是这个规律引导了我们巧妙的解决了这个问题。

因为这个问题是求最大值的问题,那我们发现,如果只能够更改两个0,被更改的0一定是相邻的(此处的相邻指:两个0之间可能有1,但一定不能有0),不然其中一个0的改变就失去了意义。同理可以想到,第k个0前面k-1个0也一定是相邻的,不然这个更改就没有作用。

由此我们可以想到一个好的思路,只需要依次搜索k个相邻的0所构成的解,找到最大值即可,通过第一个0和最后一个0向两边拓展,找到当前的最长子串,然后得出全局的最长子串即可。

这个思路已经将复杂度降至很低了,不过还是需要每次向两个方向拓展,找到所有的1,这个过程是否可以省略呢?

答案是可以!我们可以通过遍历字符串得到0的位置并存入数组中,其中k0(eg,从i位置到j位置,正好为k个相邻的0)外面的1字符长度可以直接通过i-1j+1得到,因为这两个位置是最近的0位置。

由此,我们的代码按照上面的思路写了出来:

#include<iostream>
#include<vector>
#include<string>

using namespace std;

int main()
{
    string input;
    cin>>input;
    int windows=0;
    cin>>windows;

    int length=input.size();
    vector<int> logs;
    for(int i=0;i<length;i++)
    {
        if(input[i]=='0')
            logs.push_back(i);
    }
    //first view
    int longestNum=logs[windows];
    int logsSize=logs.size();
    //full view
    for(int i=1;i<logsSize-windows;i++)
    {
        int temp=logs[i+windows]-logs[i-1]-1;
        if(longestNum<temp)
            longestNum=temp;
    }

    //final view
    if(longestNum < (length-logs[logsSize-windows-1]-1) )
        longestNum=(length-logs[logsSize-windows-1]-1);

    cout<<longestNum;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值