📅  最后修改于: 2023-12-03 14:49:58.838000             🧑  作者: Mango
在一段二进制字符串中,如果相邻的两个字符相同,则它们必须被交替(或称“翻转”),直到所有相邻的字符都不相同为止。本题中,我们要求找出最小的子串,使得经过翻转后,该子串内的所有相邻字符都不相同。
例如,对于二进制字符串0001100,可以将第2~3个字符翻转(变成01),从而得到0101100。若直接翻转前3个字符(变成1001100)则不会得到最小的子串。
首先,我们可以将所有连续相同的字符缩成一个字符,以方便后面的处理。这样,我们只需要处理连续相异的字符即可。
假设某个连续相异的区间的长度为L,其中包含两种字符,分别是a和b。我们想让它们交替,即变成ababab…或bababa…的形式。为了尽可能少地翻转子串,我们只需要考虑将其翻转为ababab…的形式,再与bababa…比较即可。
具体来说,如果a出现的次数小于等于L/2,我们就将子串中的b全部变为a,否则将a全部变为b。这可以通过一次遍历字符串而得到。
本题只需要一次线性扫描,时间复杂度为O(n)。空间复杂度为O(1)。
def min_flips(s: str) -> int:
# 将连续相同的字符缩成一个字符
s = ''.join(c for i, c in enumerate(s) if i == 0 or s[i-1] != c)
ans = 0
for i in range(1, len(s), 2):
ans += s[i] != s[i-1]
return ans
int minFlips(string s) {
int ans = 0;
for (int i = 1; i < s.size(); i++) {
if (s[i] == s[i-1]) {
ans++;
s[i] = s[i] == '0' ? '1' : '0';
}
}
return ans;
}
public static int minFlips(String s) {
int ans = 0;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == s.charAt(i-1)) {
ans++;
char c = s.charAt(i);
s = s.substring(0, i) + (c == '0' ? '1' : '0') + s.substring(i+1);
}
}
return ans;
}
function minFlips(s) {
let ans = 0;
s = [...s];
for (let i = 1; i < s.length; i++) {
if (s[i] === s[i-1]) {
ans++;
s[i] = s[i] === '0' ? '1' : '0';
}
}
return ans;
}
def min_flips(s)
ans = 0
s = s.chars.chunk_while {|a, b| a == b}.map(&:first).join
for i in 1...s.size
if s[i] == s[i-1]
ans += 1
s[i] = s[i] == '0' ? '1' : '0'
end
end
ans
end
func minFlips(s string) int {
ans := 0
tmp := []byte(s)
for i := 1; i < len(tmp); i++ {
if tmp[i] == tmp[i-1] {
ans++
if tmp[i] == '0' {
tmp[i] = '1'
} else {
tmp[i] = '0'
}
}
}
return ans
}