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

时间:2014-03-05 23:19:13

标签: java algorithm

我无法提出最佳解决方案(O(n)时间)以递归方式从字符串中删除相邻的重复项。我的尝试:

public static String removeDuplicate(String s) {
   if ( s == null ) return null;
   if ( s.length() <= 1 ) return s;
   if( s.substring(1,2).equals(s.substring(0,1))) 
      return removeDuplicate(s.substring(1));
   else return s.substring(0,1) + removeDuplicate(s.substring(1));
}

但它不适用于以下情况:

 "azxxzy" -> "ay"

在上面的例子中,这些是字符串转换:

azxxzy azzy AY

示例输入输出:

输入:azxxzy输出:ay

输入:caaabbbaacdddd输出:空字符串

输入:acaaabbbacdddd输出:acac

更新

我已在下面发布了一个答案版本。

12 个答案:

答案 0 :(得分:3)

正如您的问题评论中提到的那样,String操作已经是O(n),因为String是不可变的。这可以通过使用Character s的数组来解决。由于您还要删除内容,因此您还应该在该数组中使用null,以防止每次删除字符时都要移动内容。最后,您需要对数组进行额外的传递,以将其转换为字符串。

您要问的真正问题更简单。从xx之类的字符串中删除azxxzy会将xx之前和之后的字符放在彼此旁边,它们可能是相同的。因此,只需再次检查:将光标放在一个位置。继续使用字符串zzy而不是zy

复杂性将保持为O(n),因为每个字符最多检查两次,最多可以删除一次。

由于你专门要求一个递归的答案,我会假设这是一个家庭作业练习并将实现留给你(使用Character数组并添加起始位置的索引作为方法的额外参数)。非递归算法会更高效,也更容易实现!

答案 1 :(得分:0)

我将它转换为char数组。此外,我不确定这完成的速度有多快,但你的问题似乎没有强调O-time,你只想要一个有效的(如果我正确地读了你的问题)。

转换为char数组意味着您不必使用不可变的字符串(因此每次进行更改时都必须重新构建它们)。

public static String removeDuplicate(String string) {
    if(string == null) return null;
    return String.copyValueOf(removeDuplicate(string.toCharArray()));
}

public static char[] removeDuplicate(char[] chars) {
    if(chars.length < 1) return new char[0];
    else if(chars.length == 1) return chars;

    for(int i=0; i<chars.length-1; i++) {
        if(chars[i] == chars[i+1]) {
            char[] before = Arrays.copyOfRange(chars, 0, i);
            char[] after = Arrays.copyOfRange(chars, i+2, chars.length);
            char[] combined = new char[before.length + after.length];
            System.arraycopy(before, 0, combined, 0, before.length);
            System.arraycopy(after, 0, combined, before.length, after.length);
            chars = removeDuplicate(combined);
            break;
        }
    }
    return chars;
}

你可以用这个来测试它:

public static void main(String args[]) {
    System.out.println(removeDuplicate("azxxzy"));
    System.out.println(removeDuplicate("Does this have any duplicates?"));
    System.out.println(removeDuplicate("Nfggfoyy frttrfihht dfbllbfoedssssdsnpr''rp'tuiiu"));
}

答案 2 :(得分:0)

我想出了这个丑陋的解决方案,JasonC的想法(实际上我的第一个想法,我没有追求)将字符附加到输出中,以防万一从输出中删除相邻的重复。

public static String removeDuplicate(String s) {
 StringBuilder builder = new StringBuilder();
 char lastchar = '\0';
 for (int i = 0; i < s.length(); i++) {
   String str = builder.toString();
   if (!str.equals("")
       && (str.charAt(str.length() - 1) == s.charAt(i))) {
     builder.deleteCharAt(str.length() - 1);
   } else if (s.charAt(i) != lastchar)
     builder.append(s.charAt(i));
   lastchar = s.charAt(i);
 }
return builder.toString();
}

<强>更新 但最好的解决方案是:在this

的帮助下
public static String removeDuplicates(String s) {
if (s.isEmpty()) {
    return s;
}
char[] buf = s.toCharArray();
char lastchar = buf[0];

// i: index of input char
// o: index of output char
int o = 1;
for (int i = 1; i < buf.length; i++) {
    if (o > 0 && buf[i] == buf[o - 1]) {
        lastchar = buf[o - 1];
        while (o > 0 && buf[o - 1] == lastchar) {
            o--;
        }
    } else if (buf[i] == lastchar) {
        // Don't copy to output
    } else {
        buf[o++] = buf[i];
    }
}
return new String(buf, 0, o);
}

答案 3 :(得分:0)

您还可以使用堆栈

 public class StackDemo {
    public static void main(String[] args) throws Exception {
        CharStackArray stack = new CharStackArray(15);
        char[] dupliactes = { 'a', 'z', 'x', 'x', 'z', 'y' };
        stack.removeAdjacentDuplicate(dupliactes);
    }

}

class CharStackArray {
    private char[] array;
    private int top;
    private int capacity;

    public void removeAdjacentDuplicate(char[] arr) throws Exception {
        for (int i = 0; i < arr.length; i++) {
            if (isEmpty()) { // if stack is empty
                push(arr[i]);
                display();
                System.out.println();
            } else {
                int count = 0;
                int j = i;
                /*
                 * while top of stack is equal to next value in array (ie same
                 * adjacent values)
                 */
                while (j < arr.length && peek() == arr[j]) {
                    count++; // count of same occurences
                    j++;
                }
                if (count == 0) { // no same occurence
                    push(arr[i]); // push to stack
                    display();
                    System.out.println();
                } else {
                    for (int k = 1; k < count; k++) // skip the array index for
                        // same adjacent duplicates
                        i++;
                    pop(); // pop the duplicate value from stack
                    display();
                    System.out.println();

                }
            }

        }
    }

    public CharStackArray(int cap) {
        capacity = cap;
        array = new char[capacity];
        top = -1;
    }

    public void push(char data) {
        array[++top] = data;
    }

    public char pop() throws Exception {
        return array[top--];
    }

    public void display() {
        for (int i = 0; i <= top; i++) {
            System.out.print(array[i] + "->");
        }
    }

    public char peek() throws Exception {
        return array[top];
    }

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

}

<强>输出:

A-&GT;

A-&GT; Z-&GT;

A-&GT; Z-&GT; X-&GT;

A-&GT; Z-&GT;

A-&GT;

A-&GT; Y-&GT;

答案 4 :(得分:0)

非递归的简单解决方案是

public class RemoveAdjucentDuplicates {
public static void main(String[] args) {
    String s = "azxxzy";
    s = "geeksforgeeg";
    System.out.println(remove(s));
}

static String remove(String s) {
    char res[] = new char[s.length()];
    int j = 0;
    res[j] = s.charAt(0);
    for (int i = 1; i < s.length(); i++) {
        if (s.charAt(i) != res[j]) {
            res[++j] = s.charAt(i);
        } else {
            res[j--] = '\u0000';
        }
    }

    String result = String.valueOf(res);
    return result.substring(0,j+1);
}
}

答案 5 :(得分:0)

public class RemoveAdjacant
{
 public String replaceAdjacent(String s)
 {
  if (s.equals(""))
   return s;
  String adjacentString = "";
  char cha;
  int count = 1;
  for (int i = 0; i < s.length(); i++)
  {
   cha = s.charAt(i);
   adjacentString = adjacentString + cha;
   for (int j = 1 + i; j < s.length(); j++)
   {
    if (cha == s.charAt(j))
    {
     adjacentString = adjacentString + cha;
     count++;
    } else
    {
     if (count >= 3)
      break;
     else
     {
      count = 1;
      adjacentString = "";
      break;
     }
    }
   }
   if (count >= 3)
   {
    int index = s.indexOf(adjacentString);
    s = s.substring(0, index)
      + s.substring(index + adjacentString.length());
    return replaceAdjacent(s);
   }
  }
  return s;
 }
 public static void main(String[] args)
 {
  RemoveAdjacant ra = new RemoveAdjacant();
  Scanner scan = new Scanner(System.in);
  System.out.println("Enter string");
  String s = scan.nextLine();
  System.out.println("rem string=" + ra.replaceAdjacent(s));
 }
}

答案 6 :(得分:0)

我猜,最好使用递归。此外,字符串到字符数组的转换也会消耗一些时间。所以,我更喜欢使用正常的字符串输入。

我的代码在某种程度上看起来如下(我使用过Java 8):

 import java.io.*;
    import java.util.*;
    import java.util.concurrent.TimeUnit;
    import com.google.common.base.Stopwatch;

    /*
     "Given a string, remove the consecutive character pairs repetitively.
    input: saabbs , output : 
    input: aaabbbccc , output : abc"

     */

    class Solution {
      public static String removeDuplicates(String s) {
        int count=0;
        String sout = "";
        if (s.isEmpty() || s.length()==1) {
            return s;
        }
        else{
          s=s+" ";
          for(int i=0; i<s.length()-1;i++){
            if(s.charAt(i)!= s.charAt(i+1) || s.charAt(i+1)==' '){
              sout = sout+s.charAt(i);
            }else{
              count++;
              i=i+1;
            }
          }
        }
        //int count=0;
        for(int i=0; i<sout.length()-1;i++){
          if(sout.charAt(i)==sout.charAt(i+1))
            count++;
        }
        if(count>0){
          return removeDuplicates(sout);
        }else
          return sout;
    }
      public static void main(String[] args) throws IOException{

        Stopwatch timer = Stopwatch.createStarted();
       // String s = "saabbs";
      String s1 = "aaabbbccc";
      //System.out.println("Output1:\t"+removeDuplicates(s));
      System.out.println("Output2:\t"+removeDuplicates(s1));
        timer.stop();
         System.out.printf("Time taken: %,10d microseconds\n", timer.elapsed(TimeUnit.MICROSECONDS));

      }

    }

答案 7 :(得分:0)

package algorithms;

public class Sample {

    public static void main(String args[]){
        new Sample().fix("Whaaaatupducck");
    }

    public void fix(String input){
        StringBuilder sb = new StringBuilder();

        for(int index = 0; index<input.length()-1 ;index++){

            System.out.println("compare "+ 
            input.charAt(index)+                
            " and "+
            input.charAt(index+1));

            if(input.charAt(index) == input.charAt(index+1)){
                continue; // skipping repeats
            }else{
                sb.append(input.charAt(index));
            }

            if((index+2) == input.length()){
                sb.append(input.charAt(index+1)); // handling last character
            }
        }
        System.out.println("Result : "+sb.toString());
    }
}

输出:

  

比较W和h |比较h和a |比较a和a比较a和a   比较a和a比较a和t |比较t和u |比较你和p |   比较p和d |比较d和u |比较你和c |比较c和c |   比较c和k |

结果:

  

Whatupduck

答案 8 :(得分:0)

这是删除所有相邻重复项的简单递归python解决方案。

def rmv(st,i):
    if i==len(st)-1:
        return
    if not st:
        return 
    if st[i]==st[i+1]:
        tmp=st[i]
        while(i<len(st) and st[i]==tmp):
            st.pop(i)
        if not i-1:
            rmv(st,i-1)
        else:
            rmv(st,0)
    else:
        rmv(st,i+1)

inp=list("azxxzy")
rmv(inp,0)
print ''.join(inp)

该程序将 ay 打印为输出。

答案 9 :(得分:0)

另一个使用stack的解决方案:

private static String remove(String str1) {
    StringBuilder sb = new StringBuilder();
    Stack<Character> stack = new Stack<Character>();
    stack.push(str1.charAt(0));
    int inx = 1;
    char lastDeleted = '\0';
    while(!stack.isEmpty() && inx < str1.length()){
        if(str1.charAt(inx) == stack.peek()) {
            //repeating character found..
            lastDeleted = stack.pop();
        }else if(str1.charAt(inx) == lastDeleted) {
            //repeating character found but already removed from the stack.
        }else {
            //when a new character is introduced..
            stack.push(str1.charAt(inx));
        }
        inx++;
        if(stack.isEmpty() && inx < str1.length()) {
            //if stack is empty, then insert at least one element if present..
            stack.push(str1.charAt(inx));
            inx++;
        }
    }
    if(stack.isEmpty()) {
        return "";
    }else {
        while(!stack.isEmpty()) {
            sb.insert(0, stack.pop());
        }
    }
    return sb.toString();
}

答案 10 :(得分:0)

    public class RemoveAdjacentDuplicates {

        public static void main(String[] args) {
            System.out.println(removeDuplicates("azxxzy"));
        }

         public static String removeDuplicates(String S) {
             char[] stack = new char[S.length()];

             int i = 0;

             for(int j = 0 ; j < S.length() ; j++) {

                 char currentChar = S.charAt(j);
                 if(i > 0 && stack[i-1] == currentChar) {
                     i--;
                 }else {
                     stack[i] = currentChar;
                     i++;
                 }

             }
             return new String(stack , 0 , i);
         }

    }

该程序的结果是:

    input - "azxxzy" 
    output - "ay"

答案 11 :(得分:0)

   public static void removeDuplicates(String str)
     {
         if(str.length()<=1)
         {
             System.out.println(str);
             return;
         }
         String n=new String();
         int count=0;
         for(int i=0;i<str.length();i++)
         {
             while(i<str.length()-1 && str.charAt(i)==str.charAt(i+1))
             {
                 if(i<str.length()-2 && str.charAt(i)!=str.charAt(i+2))
                    i+=2;
                 else
                    i++;
                 count++;
             }
             if(i!=str.length()-1){
                 n=n+str.charAt(i);
             }
             else if(i==str.length()-1 && str.charAt(i)!=str.charAt(i-1)){
                 n=n+str.charAt(i);
             }
         }
         if(count>0)
         removeDuplicates(n);
         else
         System.out.println(n);
     }
}

结果:

Input: acaaabbbacdddd
Output : acac
Input : azxxzy
Output: ay