【问题标题】:Removing duplicates from a sorted int[] using binarysearch使用二进制搜索从排序的 int[] 中删除重复项
【发布时间】:2013-06-11 18:24:30
【问题描述】:

我有一个相当大的 int[],它使用 Arrays.sort() 排序。我需要从数组中删除重复的元素。

这个问题源自 sedgewick 的算法书 1.1.28

1.1.28 删除重复项。修改 BinarySearch 中的测试客户端,以在排序后删除白名单中的所有重复键。

我尝试创建一个 noDupes() 方法,该方法接受一个 int[] 并返回一个删除重复项的 int[]

rank() 方法来自 sedgewick 的代码。它执行二进制搜索

public static int[] noDupes(int[] a){
    Arrays.sort(a);
    int maxval= a[a.length-1];
    int[] nodupes = new int[maxval];
    int i=0;
    for(int j=0;j<a.length;j++){
        int rnk = rank(a[j],nodupes);
        System.out.println(a[j]+" rank="+rnk);
        if (rnk < 0){
            System.out.println(a[j]+" is not dupe");
            nodupes[i] = a[j];
            i++;
        }
    }

    return nodupes;
}
public static int rank(int key,int[] a){
    return rank(key,a,0,a.length-1);
}

public static int rank(int key,int[] a,int lo,int hi){
    if(lo > hi) return -1;
    int mid = lo+(hi-lo)/2;

    if(key < a[mid])return rank(key,a,0,mid-1);
    else if(key > a[mid])return rank(key,a,mid+1,hi);
    else return mid;
}

当我用一个示例数组运行它时

int[] a =new int[]{2,2,2,3,4,4,5,6};
int[] ret = noDupes(a);

我得到了一些意想不到的输出..即使将 2 添加到 nodupes 数组中,现有元素的排名也是 -1..

2 rank=-1
2 is not dupe
2 rank=-1
2 is not dupe
2 rank=-1
2 is not dupe
3 rank=-1
3 is not dupe
4 rank=-1
4 is not dupe
4 rank=4
5 rank=-1
5 is not dupe
6 rank=-1
6 is not dupe
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
    at ...noDupes(BinSearch.java:85)
    at ...main(BinSearch.java:96)

我不知道我做错了什么......有人可以帮忙吗?

【问题讨论】:

  • 为什么不能使用Set&lt;Integer&gt;
  • @sanbhat - 因为这不是练习的目的。
  • 我正在尝试在不使用任何库类的情况下学习如何做到这一点。我认为这个练习意味着使用二进制搜索来解决这个问题
  • 这里有问题。如果数组已经排序,您可以通过线性扫描找到重复项。无需二分查找。
  • @EJP 你是对的..线性扫描就可以了

标签: java arrays binary-search duplicate-removal


【解决方案1】:

我会这样做

public static int[] noDupes(int[] a) {
    Arrays.sort(a);
    int noDupCount = 0;
    for (int i = 0; i < a.length; i++) {
        if (i == 0 || a[i] != a[i - 1]) {
            noDupCount++;
        }
    }
    int[] a2 = new int[noDupCount];
    for (int i = 0, j = 0; i < a.length; i++) {
        if (i == 0 || a[i] != a[i - 1]) {
            a2[j++] = a[i];
        }
    }
    return a2;
}

【讨论】:

  • 那不会花费 O(n) 时间吗?
  • 会的,但我认为如果不遍历整个数组就无法完成
  • 您可以通过使用大于必要的数组、循环一次并执行 System.arraycopy 来加快速度
【解决方案2】:

只需将所有数组值添加到 HashSet,它将自动删除重复项并为您提供唯一值,然后再次将其转换为您需要的数组

【讨论】:

  • 这不会保持顺序 - 尽管您当然应该在删除重复项后进行排序。
  • 好吧,使用 SortedSet 而不是 HashSet 并且会保持顺序。
【解决方案3】:

如果您对数组进行了排序并且想要删除重复项,我认为您不需要为此使用二进制搜索。

当你对数组进行排序时,重复的元素会彼此相邻。

例如数组 = {9,8,9,1,2,5,2,5,1} 排序后 Array = {1,1,2,2,5,5,8,9,9}

您可以使用以下方式删除重复项(就地)

int a[] = {sorted array}

for(int i=0,target=0;i<a.length-1;i++) {
  if(a[i]!=a[i+1]) {
     a[target++] = a[i];
  }
}
a[target++] = a[a.length-1];
for(int i=target;i<a.length;i++) {
a[i] = 0; // fill in the values which you don't want.
}

只会一次性删除重复项

【讨论】:

    【解决方案4】:

    这应该会有所帮助:

    int[] nodupes = new int[a.length];
    

    nodupes 数组超出范围。

    注意:我不确定您使用的逻辑是否最适合该问题。但这应该可以解决您的异常。

    【讨论】:

      【解决方案5】:

      此代码将帮助您。

      public Integer[] removeDuplicates(Integer[] input){
              Integer[] arrayWithoutDuplicates = null;
              Set<Integer> set = new LinkedHashSet<Integer>();
              for(int i : input){
                  set.add(i);
              }
              arrayWithoutDuplicates = (Integer[]) set.toArray();
              return arrayWithoutDuplicates;
      }
      

      【讨论】:

        猜你喜欢
        • 2013-09-26
        • 1970-01-01
        • 2015-09-28
        • 1970-01-01
        • 2016-11-11
        • 2016-10-20
        • 2013-10-29
        • 2021-12-03
        • 2013-06-01
        相关资源
        最近更新 更多