二进制字符串重新安排顺序需要的时间

89 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

问题描述

给你一个二进制字符串 s 。在一秒之中,所有 子字符串 "01" 同时 被替换成 "10" 。这个过程持续进行到没有 "01" 存在。

请你返回完成这个过程所需要的秒数。

示例 1:

输入: s = "0110101"
输出: 4
解释:
一秒后,s 变成 "1011010" 。
再过 1 秒后,s 变成 "1101100" 。
第三秒过后,s 变成 "1110100" 。
第四秒后,s 变成 "1111000" 。
此时没有 "01" 存在,整个过程花费 4 秒。
所以我们返回 4

示例 2:

输入: s = "11100"
输出: 0
解释:
s 中没有 "01" 存在,整个过程花费 0 秒。
所以我们返回 0 。

提示:

  • 1 <= s.length <= 1000
  • s[i] 要么是 '0' ,要么是 '1' 。

进阶:

你能以 O(n) 的时间复杂度解决这个问题吗?

思路分析

首先我们要先理解一下题目意思,题目会给我们一个只包含01的字符串,我们需要对字符串进行调整,将字符串中所有的01替换成10,直到字符串中不包含01子串为止,每一次替换会消耗1秒钟的时间,我们需要计算整个调整过程需要消耗多少时间。

  • 正则替换

首先我们最容易想到的肯定是直接暴力替换,我们可以直接使用正则来替换整个字符串,替换完之后再次判断字符串中是否还包含01字符串,如果还存在,则需要再次替换。

let res = 0;
while(s.indexOf('01') != -1){
    s = s.replace(/01/g,'10');
    res++;
}
  • 遍历计算

当然,我们也可以通过一次遍历来求出答案,我们再次分析一下题目,可以发现,题目的本质其实就是要将字符串中所有的1都移动到最左方,移动时间主要由以下两个因素影响:

1、需要移动元素前面0的个数 2、需要移动元素前面连续1的个数

要将当前位置的1移到最左方,因为每次移动需要和前一个相邻的0进行位置交换,所以其最少移动的次数应该为前面0的个数,而遇到连续1的时候,需要等待前一个1先往前移动腾出空位后当前位置的1才能继续往左移动,而且当前位置的1的移动次数至少应该是前一个1的移动次数加一。

let res = 0,zero = 0;
for(let i = 0; i < s.length; i++){
    if(s[i] == '0'){
        zero++;
    }
    else if(zero > 0) res = Math.max(res + 1,zero);
}

AC代码

完整代码如下:

/**
 * @param {string} s
 * @return {number}
 */
 var secondsToRemoveOccurrences = function(s) {
    let res = 0,zero = 0;
    for(let i = 0; i < s.length; i++){
        if(s[i] == '0'){
            zero++;
        }
        else if(zero > 0) res = Math.max(res + 1,zero);
    }
    return res;
};

说在后面

本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。