递归删除所有相邻的重复项

时间:2014-11-09 04:46:16

标签: string algorithm stack time-complexity

找到一个算法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)

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

3 个答案:

答案 0 :(得分:4)

  

这是一个正确的解决方案

是的。让我尝试消除你使用堆栈的想法,考虑到@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中,我们肯定会从堆栈A中弹出一个元素,因此在每个步骤3之后,堆栈A的大小会减少1。

  

canyone解释帖子中解释的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)

Sidenote - 每当考虑递归时,总是更容易想到它,就像函数深度调用展开然后返回值然后被收集以返回最终结果。

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

答案 1 :(得分:0)

检查一下:

Scanner scanner = new Scanner(System.in);
String str = scanner.next();
for (int i = 1; i < str.length(); i++)
{
    if (str.charAt(i) == str.charAt(i-1)) 
    {
        str = str.substring(0, i-1) + str.substring(i+1);
        i = 0;
    }
}
if (str.length() == 0) {
    System.out.println("Empty String");
} else {            
    System.out.println (str);
}

答案 2 :(得分:0)

package tryout.examples;

import java.util.Scanner;

public class RemovingAdjacentCharacterUsingStack 
{
    public static void main(String[] args)
    {
        Scanner in =new Scanner(System.in);
        String str=in.next();

        CharStack cs=new CharStack(10);

        char [] arr=str.toCharArray();

        for(int i=0;i<arr.length;i++)
        {
            if(i==0 || cs.top==-1)
            {
                cs.push(arr[i]);
            }
            else
            {
                if(cs.peek()==arr[i])
                {
                    cs.pop();
                }
                else
                {
                    cs.push(arr[i]);
                }
            }

        }
        System.out.println("after removing adjacent same characters-->");
        cs.display();

    }
}

    class CharStack
    {
        private char[] finalCharArray;
        public int top;


        public CharStack(int capacity)
        {
            top = -1;
            finalCharArray=new char[capacity];
        }

        public void push(char element)
        {
            finalCharArray[++top]=element;
        }

        public char pop()
        {
            return finalCharArray[top--];
        }

        public void display()
        {
            for(int i=0;i<=top;i++)
            {
                System.out.println(finalCharArray[i]);
            }
        }

        public char peek()
        {
            return finalCharArray[top];
        }

        public boolean isEmpty() {
            return (top == -1);
        }


    }