【问题标题】:Recursively remove all adjacent duplicates递归删除所有相邻的重复项
【发布时间】:2015-01-05 15:38:56
【问题描述】:

Find an algorithm to recursively remove all adjacent duplicates in a given string 这是最初的问题。我想到了一个使用堆栈的算法。

1.Initialize a stack  and a char_popped variable
2.Push the first char of str into the stack.
3.now iterate through the characters of string.
if the top of stack matches with the character 
{
pop the character from the stack,
char_popped=character
}
else
{
  if(character==char_popped)
         {DONT DO ANYTHING}
  else
         push the character on the stack
         char_popped=null
}

堆栈上剩下的就是结果字符串。

辅助空间:O(n) 复杂度:O(n)

这是一个正确的解决方案,canyone解释了帖子中解释的o(n)解决方案吗?

【问题讨论】:

  • 当您可以查看堆栈顶部时,为什么还要保留char_popped? (如果检查堆栈是否为空太痛苦,那就在开始之前压一个哨兵值。)

标签: string algorithm stack time-complexity


【解决方案1】:

这是一个正确的解决方案

是的。考虑到@rici 提到的内容,让我尝试清理您使用堆栈的想法。

你想遍历字符串一次的字符。这就是您的算法流程:

 1. Initialize a stack containing the string. (Stack A)
 2. Pop top most element of Stack A and push into Stack B thereby initializing Stack B
 3. Pop from Stack B and pop from Stack A and check if they are equal.
 4. If they aren't push both the elements in Stack B. (The popped element from Stack A is pushed later to preserve order)
 5. Do step 3 till Stack A is empty.

 Stack B should contain the chracters with adjacent duplicates removed.

上面的算法显然是O(N),因为在每一步 3,我们肯定会从 Stack A 中弹出一个元素,因此 Stack A 的大小在每一步 3 之后都会减少 1。

谁能解释一下帖子中解释的o(n)解决方案?

来到您想挂断的recursive algorithm。事情是这样的:

函数removeUtil在任何时间点都有两个值——一个是字符数组str 我们必须从中删除相邻的重复项,另一个是字符last_removed

带有一些描述的伪代码 -

1. It checks if the first two characters of the str are same, if they are:
   update last_removed and call removeUtil again on the remaining characters 
   (hence the str ++)

2. If first two characters are not same, we do the same exercise as in 1
   only this time we start from str[1], hence removeUtil(str+1, last_removed);

3. Now the returned value from call in 2 is stored in a rem_str because we have 
   characters that didn't match like str[0] in 2 that are orphan and need to be appended
   in the final array just like we pushed elements into the stack in your case.

4. Let's assume the string is 'abbac'-

   In the first call we reach here -> removeUtil("bbac", '\0');
   str[0] -> 'a'

   Now this call -> removeUtil("bbac", '\0'); returns "ac"
   and when the recursion unfolds at this point rem_str -> "ac"
   str[0] -> 'a'

   Hence this :
   if (rem_str[0] && rem_str[0] == str[0])
   {
     *last_removed = str[0];
     return (rem_str+1); // In our case this would return "c" to the previous function call
   }

5. if (rem_str[0] == '\0' && *last_removed == str[0])
     return rem_str;

  Consider the string they mention -> "acbbcddc"
  So at some point we have situation where:
    this call happens-> removeUtil("bbcddc", '\0');
    followed by -> removeUtil("cddc", 'b');
    followed by -> removeUtil("ddc", 'b');
    followed by -> removeUtil("c", 'd');
    That returns 'c' and considering the str[0] in the string "cddc" , it goes to case 4
    and therefore 'c' gets removed returning an empty string and last_removed -> 'c'.

  So removeUtil("bbcddc", '\0'); returns an empty string with last_removed -> 'c'.

  However, here str[0] is the same as the last_removed character and therefore should be removed.


6. If none of the following string matches that means str[0] should be appended to final answer.
   rem_str--;
   rem_str[0] = str[0];
   return rem_str;

由于我们正在遍历字符数组并“形成”通过适当附加和删除字符返回的最终字符数组,因此时间复杂度为 O(N)

旁注- 每当考虑递归时,总是更容易将其想象为函数调用的深度展开,然后返回值,然后收集这些值以返回最终结果。

无论如何,我希望我能澄清自己,并希望这能让你朝着正确的方向开始。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-29
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多