簡體   English   中英

如何找到3個數組中共有的最小數字?

[英]How to find the smallest number that is common among the 3 arrays?

這是問題:

Given 3 random arrays of integers, write a method to find the smallest number that is common among the 3 arrays. HINT: Sort first and just traverse first few elements until you reach the common number
  [-1,-2, 4,5,6,1,2,3,3,3,1,1,1]
  [54,6,7,8,1,3,5,1]
  [1,6,9,1,0,2,1]
  result = 1

我編寫了一個有效的解決方案代碼,但我想知道是否有更簡單,更有效的方法來執行此操作。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class Smcomm {

    public static void main(String[] args) {
        int[] A = {-1,-2,4,5,6,1,2,3,3,3,1,1,1};
        int[] B = {54,6,7,8,1,3,5,1};
        int[] C = {1,6,9,1,0,2,1};

        ArrayList<Integer> ar1 = new ArrayList<Integer>();
        ArrayList<Integer> ar2 = new ArrayList<Integer>();
        ArrayList<Integer> ar3 = new ArrayList<Integer>();

        for(int el: A){
            ar1.add(el);
        }

        for(int el: B){
            ar2.add(el);
        }

        for(int el: C){
            ar3.add(el);
        }

        Collections.sort(ar1);
        Collections.sort(ar2);
        Collections.sort(ar3);

        printer(ar1);
        printer(ar2);
        printer(ar3);

        finder(ar1,ar2,ar3);





    }


    static void printer(ArrayList ar){

        Iterator<Integer> it = ar.iterator();

        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("--------------------");
    }

    static void finder(ArrayList ar1, ArrayList ar2, ArrayList ar3){
        ar1.retainAll(ar2);
        ar1.retainAll(ar3);
        if(ar1.size()>0){
            System.out.println(ar1.get(1));
        }else {
            System.out.println("no comm el");
        }
    }

}

不convice我完全就是因為的retainAll我認為該方法具有復雜度為O(n ^ 2)。

我不需要找到所有元素,但是我只想找到最小的元素。 您是否知道在數組中找到第一個公共元素時是否有可能停止該方法的執行? 應該不難,因為數組已經排序。

謝謝您的幫助。

稍微不同的方法:

  • 把最短的數組變成一個排序的集合
  • 把另外兩個數組變成普通集合
  • 迭代該排序的集合,並針對每個條目檢查其他兩個集合是否包含它。

兩者都包含的第一個數字必須是最小的公共條目。 這樣可以防止您查看重復的條目(在這里真的沒關系),並且還避免了對所有三個數組進行排序。

最后,對於如此小的示例,任何正確的解決方案都足夠了。 僅當您在談論包含成千上萬甚至數百萬個條目的列表時,不同解決方案的潛在權衡才有意義。

首先,不需要將數組轉換為List (因為您不需要使用retainAll ,它可以找到3個數組的所有公共元素,這超出了您的需要)。

數組(或列表)的排序似乎對於確保O(NlogN)的最壞情況復雜度很有必要。 我不認為您可以做得更好。

一旦擁有3個排序數組,就可以使用3個索引(每個數組一個)在一個while循環中循環訪問3個數組,直到找到出現在所有3個數組中的第一個元素。 這將花費線性時間。

最后一件事-您當前的解決方案有一個小錯誤-它應該輸出ar1.get(0) ,而不是ar1.get(1)

您可以僅使用Arrays和foreach循環以簡單的方式實現此目的:

  • 對數組排序
  • 遍歷數組A,然后移動B和C直到數字>A。
  • 檢查它們是否相等,否則轉到下一個數字,但要避免再次遍歷相同的索引,請從其停止處繼續。

這是如何實現此目的的示例:

public static void main(String[] args) {
    int[] A = {-1, -2, 4, 5, 6, 1, 2, 3, 3, 3, 1, 1, 1};
    int[] B = {54, 6, 7, 8, 1, 3, 5, 1};
    int[] C = {1, 6, 9, 1, 0, 2, 1};

    Arrays.sort(A);
    Arrays.sort(B);
    Arrays.sort(C);

    Optional<Integer> inCommon = findInCommon(A, B, C);

    if (inCommon.isPresent()) {
        System.out.println(inCommon.get());
    } else {
        System.out.println("no comm el");
    }
}

private static Optional<Integer> findInCommon(int[] A, int[] B, int[] C) {
    int lastB = 0;
    int lastC = 0;

    for (int valA : A) {
        while (B[lastB] < valA) lastB++;
        while (C[lastC] < valA) lastC++;

        if (valA == B[lastB] && valA == C[lastC]) {
            return Optional.of(valA);
        }
    }
    return Optional.empty();
}

另一種使用Java 8流的方法,先計算交集,然后求出最小值:

 List<Integer> list1 = Arrays.asList(A);
 List<Integer> list2 = Arrays.asList(B);
 List<Integer> list3 = Arrays.asList(C);

 Set<Integer> commonElements = list1.stream().filter(list2::contains).filter(list3::contains).collect(Collectors.toSet());
 int minimumCommonElement = Collections.min(commonElements);

我認為最簡單的方法是將元素存儲在TreeSet中(自然排序並刪除重復項),而不是ArrayList,然后遍歷集合1中的每個元素,直到找到存在於所有元素中的元素為止。 3套

static void finder(Set<Integer> s1, Set<Integer> s2, Set<Integer> s3) {
    boolean found=false;
    for (int i: s1) {
        if (s2.contains(i) && s3.contains(i)) {
            System.out.println(i);
            found=true;
            break;
        }
    }
    if (!found) {
        System.out.println("no comm el");
    }
}

以下效果很好。 在我看來,您只需要對列表之一進行排序,並將其用作插入的來源。

      List<Integer> list1 = new ArrayList<>(
      List.of(-1, -2, 4, 5, 6, 3, 1, 2, 3, 3, 3, 1, 1, 1));
      List<Integer> list2 = new ArrayList<>(List.of(54, 6, 7, 8, -4, 1, 3, 5, 1));
      List<Integer> list3 = new ArrayList<>(List.of(1, 6, 9, 1, 0, -4, 2, 1));

      Collections.sort(list1);
      for (int e : list1) {
         if (list2.contains(e) && list3.contains(e)) {
            System.out.println(e);
            break;
         }
      }

這里的想法是,如果elist1 (排序后的列表)中最小,那么如果它在list2list3則它必須是所有三個中最小的。

通過使用集合刪除重復項可能會有所改善。 但是,除非最初將數據包含在要啟動的集合中,否則這樣做也可能會導致性能問題。

剛看過其他答案后,有人建議對最小的列表(或集合)進行排序。 這是我從未考慮過的好主意。

暫無
暫無

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

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