这是一道关于字符串的操作的问题,一开始思考的时候,感觉需要取出各种不同的子序列,如果是这样时间复杂度就会变成指数级别。不过在朋友的指示下,发现其实它是有规律可寻的,最后的算法时间负责度只要O(n),而且代码极其简单。
虽然朋友是直接告诉了我其中的规律,但是我还是花了点时间思考和证明了一下,才放心的写下了代码。现在把它总结在这里。
整个问题的证明基本是使用数学归纳法,以及奇数和偶数的一些性质。感叹数学的世界真奇妙。也庆幸自己一直以来我十分喜欢数学。其实计算机的世界本来就是建立在各种数学理论之上,比如离散数学,模糊数学,逻辑数学。但是计算机又让数学的应该变得更加的广阔。
(你可以在看完题之后直接跳到红色的部分看这个问题的结论。)
String Reduction
Given a string consisting of a,b and c’s, we can perform the following operation: Take any two adjacent distinct characters and replace it with the third character. For example, if ‘a’ and ‘c’ are adjacent, they can replaced with ‘b’. What is the smallest string which can result by applying this operation repeatedly?
Sample Input
3 cab bcab ccccc
Sample Output
2 1 5
Explanation
For the first case, you can either get cab -> cc or cab -> bb, resulting in a string of length 2.
For the second case, one optimal solution is: bcab -> aab -> ac -> b. No more operations can be applied and the resultant string has length 1.
For the third case, no operations can be performed and so the answer is 5.
Idiom
X, Y, Z: symbol of character ‘a’, ‘b’, ‘c’; X could be any one of three, and Y would be any one of remain two, then Z is the last one.
O, E: O is for Odd number; E is for Even number.
S: original string.
|X|, |Y|, |Z|: the count of X(Y,Z) in S
|S|: the length of original string
String contains only 1 type of characters
This situation is easy. The string could not be reduced. So the answer would be the length of string.
String contains 2 types of characters
If the string only contains Xs and Ys, we consider it as:
|S| = 2
S would be either XY or YX, in either format, it could be reduced to Z. Hence the answer is 1.
|S| = 3
Consider |X|=2 and |Y|=1, the S could has three formats: XXY, XYX, YXX.
For any formats, we could replace X and Y with Z, and then replace X and Z with Y.
So the answer is 1.
|S| > 3
From |S|=3, we know that we could reduce XXY, XYX or YXX to Y without introduce the other character.
So we could reduce the string by following step:
- Choose a type of character, say Y, where |Y|≤|X|;
- From all Ys in S, we could find at least one Y that match format XXY, XYX or YXX (I don’t know how to prove it, but it is true, perhaps contradiction would work); choose one format and replace it with Y,
- Change S to new string;
- If |S|>=3 go to step 1
The step 2 reduce the S by 2, since the replaced character is Y, we did not introduce the third character, i.e. reduced string still only contains two characters.
|S| is O
After several times reduced by 2, it finally has only 1 character remain. Then the answer is 1.
|S| is E
Then we would have 2 character remains. If one is X, and the other is Y, we could replace them with Z, and get answer 1. But if these two characters are the same, then we could not do more reduction, hence the answer is 2.
So, how could we know what are the remaining two characters when |S| is E?
From step 2, we could also get know that not only S is reduced by 2, but |X| is also reduced by 2.
When |S| is E, there would be two E/O situations for |X| and |Y|.
|X| is O, and |Y| is O
Since every time we reduce either |X| or |Y| by 2, finally we have each one of X and Y. So we would have final answer to be 1.
|X| is E, and |Y| is E
Since every time we reduce either |X| or |Y| by 2, finally we would reduce either |X| or |Y| to 0. So the other character would leave 2. Then we have answer 2.
Conclusion
When |S|=2, since we have 1 each of X and Y, both |X| and |Y| is O;
When |S|=3, |X| is E, |Y| is O.
So we could have conclusion for the answer of reduction when S only contains two types of character:
If both |X| and |Y| are Even then the answer is 2; otherwise the answer is 1.
String contains all 3 types of characters
The main though is try to reduce S to only contains 2 types of characters.
So we have following reduction steps:
- Choose a type of character, say Z, where |Z|≤|X| and |Z|≤|Y|;
- Find a Z that is next to either X or Y;
- Replace the Z and X(Y) with Y(X);
- If |Z| > 0, go to step 2.
Finally, we have only 2 types of characters left. However, from previous conclusion, we should know the E/O situation of the remaining characters.
How can we get that?
Before that, we need to introduce some properties of E/O:
O + O -> E O - O -> E E + E -> E E - E -> E E + O -> O E - O -> O O - E -> O
The properties are the E/O situations for the math add/minus.
O + O -> E means: an Odd number plus an Odd number, we get an Even number.
From the step2, we know that each time we reduce |Z| by 1, and also reduce |X|(|Y|) by 1, but increase |Y|(|X|) by 1.
Claim |Rx| and |Ry| are the number that reduced with Z; |Ix| and |Iy| are the number that increased with Z.
We would have:
|Rx| + |Ry| = |Z| |Rx| = |Iy| |Ry| = |Ix|
And the final count of X and Y is:
|X| = |Ox| + |Ix| - |Rx| = |Ox| + (|Ry| - |Rx|) |Y| = |Oy| + |Iy| - |Ry| = |Oy| + (|Rx| - |Ry|)
where |Ox| and |Oy| are original count of X and Y
|Z| is O
From the properties of E/O, we could know that |Rx| and |Ry| should be one for O and the other one for E. Say |Rx| is O and |Ry| is E.
Then both (|Ry| – |Rx|) and (|Rx| – |Ry|) are O.
So if both |Ox| and |Oy| are O, then finally both |X| and |Y| are E. From previous conclusion, we got answer 2.
Otherwise, we have at lease one of |X| and |Y| is O, and get answer to be 1.
|Z| is E
In this situation, |Rx| and |Ry| should be either O or E at the same time. But no matter what are the E/O state of |Rx| and |Ry|, both (|Ry| – |Rx|) and (|Rx| – |Ry|) are E.
So if both |Ox| and |Oy| are E, then finally both |X| and |Y| are E. From previous conclusion, we got answer 2.
Otherwise, we have at lease one of |X| and |Y| is O, and get answer to be 1.
Exception
The only exception for the step is that when we have such strings:
ZXYY… …YYZXYY… …YYXZ
Where both |X| and |Z| are exactly 1. If we replace them with Y, we get a string only contains one type of characters. This is not good. We should choose the one next to Y and replace them.
Conclusion
From the analysis, we know that the final answer only base on the E/O state of each type of characters, if the string have more than 1 type.
When string only contains two types, then the count of left type of character is 0, which is an even number.
So we could conclude answer for string reduction as following:
|X|==|S| && |Y|==0 && |X| ==0, answer = |S|; |X|, |Y|, |Z| are all Odd (Even), answer = 2 ; |X|, |Y|, |Z| is at least one is Odd, and one is Even answer = 1 ;