【问题标题】:Remove duplicate in a string without using arrays [closed]在不使用数组的情况下删除字符串中的重复项[关闭]
【发布时间】:2012-12-13 18:21:36
【问题描述】:
    String input = "AAAB";

    String output = "";
    for (int index = 0; index < input.length(); index++) {
        if (input.charAt(index % input.length()) != input
                .charAt((index + 1) % input.length())) {

            output += input.charAt(index);

        }
    }
    System.out.println(output);

但如果我的输入是“ABABAB”或只是“AAAA”,它就不起作用。有什么想法吗?

【问题讨论】:

  • 我不完全确定您的意图是什么,您能否添加输入示例并匹配预期输出?
  • 您需要定义:不使用数组input.charAt(..) 正在使用数组,例如...

标签: java


【解决方案1】:

使用数据结构来了解是否已找到字符,例如Set。例如,您可以使用其add() 方法并检查其返回值。

另外,您可以考虑使用StringBuilder 进行重复连接,这样效率更高。

Set<Character> characters = new HashSet<Character>();
String input = "AAAB";
StringBuilder output = new StringBuilder();
for (int index = 0; index < input.length(); index++) {
    char character = input.charAt(index);
    if (characters.add(character)) {
        output.append(character);
    }
}
System.out.println(output.toString());

【讨论】:

  • 具有讽刺意味的是,使用数组会更难。
  • 这是个好主意,但我不允许使用任何类型的数组,我的意思也是 hashset。
【解决方案2】:

针对速度版本进行了优化

public static void main(String[] args) {
    String input = "AAAB";
    StringBuilder output = new StringBuilder();
    for (int i = 0; i < input.length(); i++) {
        if (!contains(output, input.charAt(i))) {
            output.append(input.charAt(i));
        }
    }
    System.out.println(output);
}

private static boolean contains(StringBuilder output, char c) {
    for(int i = 0; i < output.length();  i++) {
        if (output.charAt(i) == c) {
            return true;
        }
    }
    return false;
}

【讨论】:

  • 由于contains 方法,这不是 O(n(log n)) 吗?使用HashSet#add() (O(1)) 并遍历字符串 (O(n)) 是 O(n)
  • 此程序仅适用于原始字符。你能想象为每个字符创建一个对象的成本吗?如果不进行测试,我可以说差异将是巨大的。
  • 实际上,从 JLS 的 5.1.7. Boxing Conversion 开始装箱时,\u0000-\u007f 范围内的字符似乎被缓存了。不过,这绝对是一个好点。作为旁注,正如@assylias 在他的评论中指出的那样,使用StringBuilder 搜索字符可以被视为使用数组。但是话又说回来,几乎所有流行的数据结构(例如HashSet/Map)最终都使用数组:)
【解决方案3】:

让我们看看你的循环在做什么:

if (input.charAt(index % input.length()) != input
  .charAt((index + 1) % input.length()))

1) 首先,您应该认识到执行 '% input.length()' 操作是在浪费时间和处理能力,因为 index 总是小于 input.length(),所以 index %input.length() 总是等于索引。

让我们忽略 %input.length() 。

2) 当您将 input.charAt(index) 与 input.charAt(index+1) 进行比较时,您只是将当前字符与下一个字符进行比较。如果我理解正确的话,最初的问题是要求您删除所有重复项,而不仅仅是那些并排出现的重复项。

3) 您的算法很可能会引发 IndexOutOfBounds 异常,因为当您到达字符串末尾时(当 index == input.length() - 1 时)检查 input.charAt(index+1) 也会看起来是一个字符远在字符串中。

正如第一个答案所建议的那样,您需要利用某种形式的数据结构来存储您遇到的所有 DISTINCT 字符。每当您遇到一个新角色时,您都需要 a) 将其添加到数据结构中,b) 将其添加到输出的末尾。

【讨论】:

  • 他使用模数只是为了避免 IOOB。在这种情况下,最好让它发生,因为他将最后一个字符与第一个字符进行比较。
  • 是的,我这样做是因为我想看看最后一个元素是否 == 第一个元素。
【解决方案4】:
public static void print(String s) {
    List<String> v = new ArrayList<String>();
    for(int j=0; j<s.length(); j++) {
        if(!v.contains("" + s.charAt(j)))
            v.add("" + s.charAt(j));
    }


    for(String e : v)
        System.out.print(e);
}

【讨论】:

  • 对不起,我把前面的删掉了,是的,前面的代码因为TreeSet的缘故是按顺序打印的,这个保持原来的顺序。
【解决方案5】:

(我希望你的意思是重复,而不是重复。)

public static String withoutDuplicates(String s) {
    for (int i = 0; i < s.length(); ) {
        boolean removedDuplicate = false;
        for (int duplicateLength = (s.length() - i) / 2; duplicateLength >= 1; 
                --duplicateLength) {
            if (foundDuplicate(s, i, duplicateLength)) {
                s = s.substring(0, i) + s.substring(i + duplicateLength);
                removedDuplicate = true;
                break;
            }
        }
        if (!removedDuplicate) {
            ++i;
        }
    }
    return s;
}

private static boolean foundDuplicate(String s, int i, int duplicateLength) {
    String sought = s.substring(i, i + duplicateLength);
    return s.indexOf(sought, i + duplicateLength) != -1;
}

更正: duplicateLength 初始化值超出范围。

【讨论】:

  • 但是当我使用 ABCCDA 时出现错误。
  • 那应该变成 BCDA(一如既往地删除第一个重复项)。
猜你喜欢
  • 2023-03-09
  • 2011-10-20
  • 1970-01-01
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
  • 2021-08-29
  • 2011-05-22
  • 1970-01-01
相关资源
最近更新 更多