Reputation:
I have the following task. There is a string. I must do replacement in it according to 6 rules till it is possible to make a replacement in a string.
The solution I found is below. It works right. The problem is that its performance is low. How else can I make replacement according to multiple rules? Is there any algorithm?
P.S. This task is from codility site. I got 100% correctness and 25% performance for my solution.
class Test {
private Map<String,String> rules;
private void initRules(){
rules=new HashMap<>();
rules.put("AB", "AA");
rules.put("BA", "AA");
rules.put("CB", "CC");
rules.put("BC", "CC");
rules.put("AA", "A");
rules.put("CC", "C");
}
public String test(String S) {
initRules();
loop:while(true){
String oldString=S;
for (Map.Entry<String, String> rule : rules.entrySet())
{
S=S.replace(rule.getKey(), rule.getValue());
}
if (oldString==S){
break loop;
};
}
return S;
}
}
public class NewMain {
public static void main(String[] args) {
Test test=new Test();
System.out.println("Result:"+test.test("ABBCC"));;
}
}
Upvotes: 5
Views: 7956
Reputation: 1168
I prefer do while loop instead of recursion :
Here is the answer :
public String stringReduce(String input) {
String previous;
do {
previous = input;
input = input.replace("AA", "A").replace("CC", "C").replace("BC", "C").replace("CB", "C")
.replace("BA", "A").replace("AB", "A");
} while (!previous.equals(input));
return input;
}
Upvotes: 1
Reputation: 31
You can impliment a recursive algorythm for this. Then you can reduce the rules and apply. For instance AB -> AA, AA -> A then AB->A Then the answer would be
public static String stringReduce(String s){
String transformed = s.replace("AA", "A").replace("CC", "C")
.replace("BC", "C").replace("CB", "C").replace("BA", "A")
.replace("AB", "A");
if(transformed.equals(s)){
return transformed;
}
else{
return stringReduce(transformed);
}
}
Upvotes: 2
Reputation: 1
Here is my C# Solution:
public static string solution(string S)
{
return Getreplace(S);
}
public static string Getreplace(string input)
{
string retval = input.Replace("AB", "AA")
.Replace("BA", "AA")
.Replace("CB", "CC")
.Replace("BC", "CC")
.Replace("AA", "A")
.Replace("CC", "C");
if (input == retval)
return retval;
else
return Getreplace(retval);
}
Upvotes: 0
Reputation: 12712
I followed the reasoning of @vish4071 .
I look for sub-Strings of "B" and "A" only , I know this segment will be become "A" . Same for sub-Strings "B" and "C" only.
"BAABBABAB" becomes "A" due to replace("AB" by "AA"),replace("BA" by "AA"), replace("AA" by "A")
input: "BBBAABABBBCCBCBBCACB"
"BBBAABABBB" "CCBCBBC" "A" "CB"
"A" "C" "A" "C"
output : "ACAC"
The two algorithms keep track when the sub String "A" changes from/to "C". I append the known previous char. Because change detection is based on "A" to "C" or "C" to "A", you don't previous char in the first sub-string. After the loop , you have to append with last previous char.
Runtime complexity : O(n)
Space complexity : O(1)
Here is the implementation in Java.
public static String solution(String S) {
final char C = 'C';
final char A = 'A';
// if contains only B return itself
if(!S.contains("A") || !S.contains("C")) return S;
String res = "";
boolean hasLetterChanged = false;
char prevChar = 'D';
for(char c : S.toCharArray()){
if (c == A){
if (prevChar == C){hasLetterChanged = true;}
}else if(c == C){
if (prevChar == A){hasLetterChanged = true;}
}
if(hasLetterChanged){
res = res + prevChar;
hasLetterChanged = false;
}
if(c == A || c == C){
prevChar = c;
}
}
return res + prevChar;
}
Here is the implementation in Python 2.7 ( compatible with 3x) .
def solution(S):
if not(S.__contains__('C') and S.__contains__('A')): return S
has_char_changed = False
prev_char = 'B'
A = 'A'
C = 'C'
res = ""
for c in S:
if c == A:
if prev_char == C:
has_char_changed = True
elif c == C:
if prev_char == A:
has_char_changed = True
if has_char_changed:
res = res + prev_char
has_char_changed = False
if c == A or c == C:
prev_char = c
return res + prev_char
if __name__ == '__main__':
assert solution("ABBCC") == "AC"
assert solution("BCBCABB") == "CA"
assert solution("BBBAABABBBCCBCBBCACB") == "ACAC"
assert solution("BBBBBBB") == "BBBBBBB"
Upvotes: 0
Reputation: 71
My Solution in python using the regular expression.
Explanation: if input is "ABACAABBCA".
First while iteration: Will replace AB -> A, AA->A, BC->C. The value of strng is "AACACA"
Second while iteration: Will replace AA->A. The value of strng is "ACACA"
Third while iteration: Nothing to replace so will exit and return the final substituted string (strng). Let me know if any improvements or corrections needed.
def solution(strng):
prevS=""
subst={"AB":"A","BA":"A","CB":"C","BC":"C","AA":"A","CC":"C"}
subs=lambda st:subst[st.group(0)]
while prevS!=strng:
prevS=strng
strng=re.sub(r'(([A][BA])|([B][A])|([CB][C])|([C][B]))',subs,strng)
return strng
Upvotes: 0
Reputation: 5277
Here is an algorithm you can use:
Assumption: String consists of only (A,B,C)
If string is composed of B's
only (no A/C), output = input string.
Otherwise:
Divide the string in the following way. If a substring consists of (B,A) or (B,C), divide them. Replace with A and C respectively. That will be the answer.
eg. Let the string be: "BBBAABABBBCCBCBBCACB". This will be divided as:
"BBBAABABBB" "CCBCBBC" "A" "CB"
And this will result in output string as: ACAC
Basically, just ignore all B's
and replace clusters of A's
with A
and clusters of C's
with C
.
Upvotes: 5