簡體   English   中英

在 Java 中查找 List 中具有重復項的唯一元素

[英]Find one unique element in List with duplicates in Java

我們列出了整數(或其他對象),例如:

[0, 0, 1, 1, ... , 777777, ... , 999999, 999999]

爪哇代碼:

List<Integer> ints = new LinkedList<Integer>();
for (int i = 0; i < 999999; i++) {
    ints.add(i); // add first value
    if (i!=777777){
        ints.add(i); // add duplicate value in not '5'
    }
}

我是這樣解決這個問題的:

Integer unique = null;
while (true) {
    unique = ints.get(0);
    ints.remove(0);
    if (ints.contains(unique)) {
        ints.remove(ints.indexOf(unique));
    } else {
        break;
    }
}
System.out.println(unique);// 777777

大約需要 30 毫秒。 使用 ArrayList,它的工作時間更長。 問題是如何以最佳(正確/優雅/最快)方式從此列表中獲取一個唯一值(例如 777777)。

您的實現非常低效,因為您在循環中運行線性時間操作,例如ints.contains(unique)ints.indexOf(unique) 因此,在最壞的情況下,您的運行時間為O(n^2)

如果數字總是排序的(就像它們在你的例子中一樣),你可以在列表的元素上迭代一次,找到不等於list.get(i-1)list.get(i+1)的元素list.get(i) list.get(i+1) 這將需要O(n)

如果數字並不總是排序,你可以在O(nlogn)對它們進行排序並像以前一樣繼續。

或者你也可以遍歷數一次,統計每個號碼(可以存儲在計數的出現次數HashMap ),並找到其計為1。這將需要數O(n)不管是否輸入列表是否排序。

除了其他答案給出的Set解決方案之外,如果您知道重復元素只出現兩次(或偶數次)並且只有一個非重復數字,則可以對所有值進行異或以找到唯一的一。

public int findUnique(int[] nums) { // Or (List<Integer> nums), it works also
    int xor = 0;
    for(int i : nums){
        xor ^= i;
    }
    return xor;
}

該解決方案比其他解決方案更快、更短。


你也可以用 Java 8 風格來做,但它當然會更慢:

public int findUnique(int[] nums) {
    return Arrays.stream(nums)
            .reduce((acc,i) -> acc ^= i)
            .orElseThrow(IllegalArgumentException::new);
}

您正在使用錯誤的集合。 List 不是這個問題的正確集合。
你應該使用HashSet來解決這個問題。

private void find(List<Integer> ints){
   HashSet<Integer> set = new HashSet<>();
   for(int i=0;i<ints.size();i++){
       if(set.contains(i)){
          set.remove(i);
       }else{
          set.add(i);
       }
   }
   Iterator<Integer> itr = set.iterator();
   if(itr.hasNext()){
      System.out.println("Unique value is :"+itr.next());
   }else{
      System.out.println("There is no duplicated value");
   }
}

此方法僅適用於 2 和 1 計數列表項。 如果你有 3 次相同的數字,這種方法會發現它是重復的。

排序可能是答案,但排序最多只有 O(logn),之后 O(n) 用於查找重復元素。 如果您可以在創建列表時創建哈希集,則此方法將發現重復元素為 O(1)。

首先獲取唯一元素,然后使用集合 api 的頻率方法來獲取重復的出現次數

Set<String> uniqueSet = new HashSet<String>(list);

for (String temp : uniqueSet) {
    if(Collections.frequency(list, temp)==1) {
      System.out.println(temp);
    }

}

這將從列表中返回唯一元素。

如何嘗試 jdk8 的流 API,如下所示:

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FiindUnique {

    public static void main(String[] args) {
        System.out.println("Hello World");
        Collection<String> list = Arrays.asList("A", "B", "C", "D", "A", "B", "C");

        //solution 1
        List<String> distinctElements = list.stream().filter(name -> Collections.frequency(list, name) == 1).collect(Collectors.toList());
        System.out.println(distinctElements);

        //Solution 2

        List<String> distinctElements2 = list.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
            .entrySet()
            .stream()
            .filter(e -> e.getValue() == 1)
            .map(e -> e.getKey())
            .collect(Collectors.toList());
         System.out.println(distinctElements2);
    }
}

通過二分查找找到反轉點,即唯一數偶數和奇數索引前的數相同,唯一數后奇數和偶數的數相同,所以我們可以進行二分查找來找到反演點時間復雜度為 log(N)

您是否假設數組已排序? 這應該會更快。

HashSet<Integer> s = new HashSet<Integer>();

for ( Integer i : ints){
    if ( s.contains(i)){
        s.remove(i); // remove dups
    }
    else{
        s.add(i); //add uniques
    }
}

for ( Integer unique: s){
// should contain one value
    System.out.println(unique);// 777777
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM