题目地址:
https://www.lintcode.com/problem/minimum-moves/description
给定一个只含a
和b
的字符串
s
s
s,允许将其中的a
变为b
或者将b
变为a
。问至少经过多少次变换可以使得
s
s
s中没有字母全相同的长度大于等于
3
3
3的子串。
直接求出所有长度大于等于 3 3 3的子串的长度 l l l,然后累加 l / 3 l/3 l/3即可。
算法正确性证明:
首先,考虑一个长度大于等于
3
3
3且字母全相同的字符串
t
t
t。我们先证明,至少要修改
t
/
3
t/3
t/3个字母才能使得没有连续相同的字母出现
3
3
3次或以上。不妨设
t
t
t是
3
3
3的倍数,将第
0
,
1
,
2
0,1,2
0,1,2个字母染成红色,
3
,
4
,
5
3,4,5
3,4,5染成蓝色,这样每三个染成红色,再三个染成蓝色,再三个又染成红色,以此类推。如果存在一种方案少于
t
/
3
t/3
t/3次修改,那么必然有一个红色块或者蓝色块没有被修改,矛盾;接下来给出一个方案,首先找到不大于
t
t
t的最大的能被
3
3
3整除的数,设为
t
′
t'
t′,将
t
′
t'
t′个字母按照上面方法染色,然后将每个色块的最中间的那个字母换一下,这样需要
t
/
3
t/3
t/3次,如果
t
=
t
′
t=t'
t=t′或者
t
=
t
′
+
1
t=t'+1
t=t′+1,那么这样就够了;如果
t
=
t
′
+
2
t=t'+2
t=t′+2,那么就取每个颜色块的最后一个字母变一下,(比如(aaa)(aaa)aa
,就变成(aab)(aab)aa
)。代码如下:
public class Solution {
/**
* @param s: a string
* @return: return the minimum number of moves
*/
public int MinimumMoves(String s) {
// write your code here
int res = 0;
for (int i = 0; i < s.length(); i++) {
int j = i;
while (j < s.length() && s.charAt(j) == s.charAt(i)) {
j++;
}
res += (j - i) / 3;
i = j - 1;
}
return res;
}
}
时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)。