删除字符串中的重复字符

时间:2015-04-11 01:29:48

标签: java arrays

这是破解编码面试手册。

  

设计算法并编写代码以删除字符串中的重复字符   不使用任何额外的缓冲区。注意:一个或两个额外的变量是好的。   数组的额外副本不是。

在书中它说时间复杂度是$ O(N ^ 2)$。我们如何判断解决方案的时间复杂度是$ O(N ^ 2)$? 我对解决方案如何删除重复字符有疑问。我已将它们包含在下面的内联评论中。

   public static void removeDuplicates(char[] str) {
      if (str == null) return; // if the array is empty return  nothing?
      int len = str.length; // get the length of the array 
      if (len < 2) return; // if the array length is only 1 return nothing?
      int tail = 1; // initialise tail variable as 1 ! 
      // Why are we starting at second character here (at i = 1),why not start at i = 0 ? 
      for (int i = 1; i < len; ++i) { 
        int j;

        for (j = 0; j < tail; ++j) { // so are we checking if j is less then 1 as tail has been initialized to 1 
          if (str[i] == str[j]) break; // stop, if we find duplicate.
        }

        if (j == tail) { why are we comparing j to tail(1) here ?
          str[tail] = str[i]; // assigning the value 
          ++tail; // incrementing tail
        }
      }
      str[tail] = 0; //setting last element as 0 
    }


 - 

5 个答案:

答案 0 :(得分:3)

我完全依赖@pbabcdefp评论,因为我懒得测试它,但看起来你的算法不起作用。

无论如何我不喜欢它,在这里我将如何在评论中解释:

public static void main(String[] args) {
    removeDuplicates(new char[]{'a','a','b','b','c','d','c'});
}

public static final void removeDuplicates(char[] str)
{
    /*
     * If the str is not instantiated, or there is maximum 1 char there is no need to remove duplicates as 
     * it is just impossible to have duplicate with 1 char.
    */
    if (str == null || str.length < 2)
        return;

    //loop over each char
    for(int i = 0; i < str.length; i++)
    {
        //no need to check with earlier character as they were already checked, so we start at i + 1
        for(int j = i + 1; j < str.length; j++)
        {
            //if they match we clear
             if(str[j] == str[i])
                str[j] = ' ';
        }
    }

    System.out.println(str);
}

这将输出a b cd

答案 1 :(得分:3)

首先,这是一本很棒的书,我希望向大家推荐!

通常,如果允许使用大量内存,可以节省时间,如果允许使用一些变量,那么您仍然可以通过较慢的算法解决此问题。当你检查每一个可能的解决方案时,有完整的暴力算法。

public static void removeDuplicates(char[] str) {
  if (str == null) return; // if the array is empty return  nothing?

输入是字符串指针,因此字符串存在于内存中的某个位置,代码可以修改它,但它保持在同一个地方。这就是函数的返回类型为void的原因,因此它不会返回任何内容。返回时,原始位置的字符串不重复。

  int len = str.length; // get the length of the array 
  if (len < 2) return; // if the array length is only 1 return nothing?

与上述相同,没有返回值。如果字符串小于2个字符,则它不能包含重复。

从这里开始,逻辑如下: 拿第i个角色。检查字符串中此位置之前是否存在。如果存在,则算法删除第i个字符。如果它不存在则保留在字符串中。

证明这是正确的算法: 没有任何字符会保留字符串中较早存在的字符。如果字符串稍后存在,则由于先前的规则,它将被删除。

如果这是算法,它会正常工作,但字符串中会有“空”字符。字符串不会更小,即使很难,它应该包含更少的字符。

这就是算法跟踪“输出字符串尾部”的原因。这就是尾部在开头等于1的原因,因为第一个字符肯定是结果字符串的一部分。 当应删除当前字符时,输出字符串的尾部不会移动,不会在结果中添加新字符。当前字符应该是结果的一部分时,它会被复制到结果字符串的尾部。

当算法到达输入字符串的末尾时,它会关闭结果字符串。

复杂性: 这意味着,相对于输入的大小,称为“n”算法必须采取多少步骤。通常,循环和递归仅计数。 此代码有2个for循环嵌入到彼此中。 外部每次从1到n。 内部从0到尾部,尾部从1到n。因此,在最糟糕的情况下,内部的平均值从1到n / 2。 这意味着您的复杂性为n *(n / 2)。由于2是常数,因此复杂度为n * n。

答案 2 :(得分:2)

O时间复杂度与最坏情况有关。忽略你得到的数组以及你对它做的动作,当你有两个由字符串长度限制的嵌套for循环时,你的复杂性不能高于n ^ 2,因此它是O(n ^ 2) (它只是一个上限,如果你想表明它也是一个下限,应该做更多的工作。)

答案 3 :(得分:2)

O(N ^ 2)基本上意味着随着输入数量的增加,N是输入数量,复杂度(执行的操作数量)将按比例缩放到N ^ 2 +某个常数值。

所以看一下代码,str.length是N.对于每个元素,你将它与其他元素进行比较,N比较N次= N ^ 2.

现在O(N ^ 2)并不准确。根据定义,它只关注导致复杂性增长的非常数因素。它永远不会告诉你特定算法运行的速度,它纯粹告诉你运行所需的时间如何随着操作元素数量的波动而缩放。

答案 4 :(得分:0)

使用它来删除每个重复的小写

static boolean contains(char c, char[] array) {
    for (char x : array) {
        if (x == c) {
            return true;
        }
    }
    return false;
}
public static void main(String[] args) {
String s = "stackoverflow11221113" ;

String result = "";
for(char ch:s.toCharArray()){
  if(!contains(ch,result.toCharArray())){
    result +=ch;
  }
}
System.out.println(result);
}

用于删除每个重复的小写或大写字符

static boolean contains(char c, char[] array) {
    for (char x : array) {
        if (x == c) {
            return true;
        }
    }
    return false;
}
public static void main(String[] args) {
String s = "StackOverFlow11221113" ;
String result = "";
for(char ch:s.toCharArray()){
  if(!contains(ch,result.toLowerCase().toCharArray())){
    result +=ch;
  }
}
System.out.println(result);
}