Skip to main content
Code Review

Return to Answer

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

Sylvain Boisse Sylvain Boisse makes a very good observation about the importance of the guarantee that

Sylvain Boisse makes a very good observation about the importance of the guarantee that

Sylvain Boisse makes a very good observation about the importance of the guarantee that

Fix typo which dramatically changes the meaning
Source Link
Peter Taylor
  • 24.4k
  • 1
  • 49
  • 94

and a good suggestion to use a stack. Observe that if we encounter a character which neither starts a potential match nor continues the current potential match then it blocks all (unremoved) characters before it from being part of a word, since they would have to span it. Therefore the stack can be clearercleared, and the code can be remarkably simple.

 static string RepeatedRemoval(string initial, string removed)
 {
 if (removed.Length == 0) return initial;
 StringBuilder sb = new StringBuilder(initial.Length);
 char startRemoved = removed[0];
 // The main case
 int[] stack = new int[initial.Length + 1];
 int stackIdx = 0;
 foreach (char ch in initial)
 {
 sb.Append(ch);
 // Since all characters in removed are distinct, a match for removed[0] starts a new match
 if (ch == startRemoved) stack[++stackIdx] = 1;
 // A match for the next character expected extends the current match
 else if (ch == removed[stack[stackIdx]]) ++stack[stackIdx];
 // And any other character blocks everything up to now from being part of a match
 else stackIdx = 0;
 if (stack[stackIdx] == removed.Length)
 {
 --stackIdx;
 sb.Length -= removed.Length;
 }
 }
 return sb.ToString();
 }

and a good suggestion to use a stack. Observe that if we encounter a character which neither starts a potential match nor continues the current potential match then it blocks all (unremoved) characters before it from being part of a word, since they would have to span it. Therefore the stack can be clearer, and the code can be remarkably simple.

 static string RepeatedRemoval(string initial, string removed)
 {
 if (removed.Length == 0) return initial;
 StringBuilder sb = new StringBuilder(initial.Length);
 char startRemoved = removed[0];
 // The main case
 int[] stack = new int[initial.Length + 1];
 int stackIdx = 0;
 foreach (char ch in initial)
 {
 sb.Append(ch);
 // Since all characters in removed are distinct, a match for removed[0] starts a new match
 if (ch == startRemoved) stack[++stackIdx] = 1;
 // A match for the next character expected extends the current match
 else if (ch == removed[stack[stackIdx]]) ++stack[stackIdx];
 // And any other character blocks everything up to now from being part of a match
 else stackIdx = 0;
 if (stack[stackIdx] == removed.Length)
 {
 --stackIdx;
 sb.Length -= removed.Length;
 }
 }
 return sb.ToString();
 }

and a good suggestion to use a stack. Observe that if we encounter a character which neither starts a potential match nor continues the current potential match then it blocks all (unremoved) characters before it from being part of a word, since they would have to span it. Therefore the stack can be cleared, and the code can be remarkably simple.

 static string RepeatedRemoval(string initial, string removed)
 {
 if (removed.Length == 0) return initial;
 StringBuilder sb = new StringBuilder(initial.Length);
 char startRemoved = removed[0];
 int[] stack = new int[initial.Length + 1];
 int stackIdx = 0;
 foreach (char ch in initial)
 {
 sb.Append(ch);
 // Since all characters in removed are distinct, a match for removed[0] starts a new match
 if (ch == startRemoved) stack[++stackIdx] = 1;
 // A match for the next character expected extends the current match
 else if (ch == removed[stack[stackIdx]]) ++stack[stackIdx];
 // And any other character blocks everything up to now from being part of a match
 else stackIdx = 0;
 if (stack[stackIdx] == removed.Length)
 {
 --stackIdx;
 sb.Length -= removed.Length;
 }
 }
 return sb.ToString();
 }
Source Link
Peter Taylor
  • 24.4k
  • 1
  • 49
  • 94

Messing around with the GC settings is a big red flag. If you think that's necessary for a programming challenge then you should instead look at the algorithm.

Sylvain Boisse makes a very good observation about the importance of the guarantee that

The characters in the substring are all different

and a good suggestion to use a stack. Observe that if we encounter a character which neither starts a potential match nor continues the current potential match then it blocks all (unremoved) characters before it from being part of a word, since they would have to span it. Therefore the stack can be clearer, and the code can be remarkably simple.

 static string RepeatedRemoval(string initial, string removed)
 {
 if (removed.Length == 0) return initial;
 StringBuilder sb = new StringBuilder(initial.Length);
 char startRemoved = removed[0];
 // The main case
 int[] stack = new int[initial.Length + 1];
 int stackIdx = 0;
 foreach (char ch in initial)
 {
 sb.Append(ch);
 // Since all characters in removed are distinct, a match for removed[0] starts a new match
 if (ch == startRemoved) stack[++stackIdx] = 1;
 // A match for the next character expected extends the current match
 else if (ch == removed[stack[stackIdx]]) ++stack[stackIdx];
 // And any other character blocks everything up to now from being part of a match
 else stackIdx = 0;
 if (stack[stackIdx] == removed.Length)
 {
 --stackIdx;
 sb.Length -= removed.Length;
 }
 }
 return sb.ToString();
 }

A minor optimisation can be obtained by handling the case removed.Length == 1 specially.

 static string RepeatedRemoval(string initial, string removed)
 {
 if (removed.Length == 0) return initial;
 StringBuilder sb = new StringBuilder(initial.Length);
 char startRemoved = removed[0];
 if (removed.Length == 1)
 {
 foreach (char ch in initial)
 {
 if (ch != startRemoved) sb.Append(ch);
 }
 return sb.ToString();
 }
 // The main case
 int[] stack = new int[initial.Length + 1];
 int stackIdx = 0;
 foreach (char ch in initial)
 {
 sb.Append(ch);
 // Since all characters in removed are distinct, a match for removed[0] starts a new match
 if (ch == startRemoved) stack[++stackIdx] = 1;
 else if (ch == removed[stack[stackIdx]])
 {
 // Extend the match by one char, and if it's a full match then pop.
 if (++stack[stackIdx] == removed.Length)
 {
 --stackIdx;
 sb.Length -= removed.Length;
 }
 }
 // This char blocks everything up to now from being part of a match
 else stackIdx = 0;
 }
 return sb.ToString();
 }
lang-cs

AltStyle によって変換されたページ (->オリジナル) /