簡體   English   中英

找到2個排序數組中的值對(每個數組中的1個值),其中和最接近目標值

[英]find the value pair in 2 sorted arrays (1 value from each array) where the sum is closest to a target value

原始問題有一個2個整數的未排序列表。 為了簡化這個問題,我們只考慮輸入是2個排序的整數數組和一個整數目標。 如果有超過1個解決方案對,則值對可以重復。

例如:[7,8,14],[5,10,14]目標:20解決方案是[14,15],第一個數組為14,第二個數組之和為5,最接近20。

我的解決方案是從頭到尾遍歷兩個數組,並與跟蹤的最小差異進行比較,並在新差異較小時進行更新。

但這是蠻力。 有沒有更好的解決方案?

我在網上找到的大多數解決方案是從同一個陣列中找到目標,2個陣列目標問題和1個陣列之間是否有任何相似之處?

一個關鍵的洞察力:給定一對(x,y),其總和高於目標,該總和比任何對(x,y')的總和更接近,其中y'> y。 相反,如果(x,y)的和低於目標,則該和比任何對(x',y)的總和更接近,其中x'<x。

這產生了線性時間的算法:

  1. 啟動列表X的第一個元素和列表Y的最后一個元素
  2. 檢查它是否是目前為止最好的一對(如果是,請記住)
  3. 如果該總和小於目標,則移動到X的下一個更高元素。如果該總和大於目標,則移動到Y的下一個較低元素
  4. 循環步驟2 - 3,直到X或Y中的元素用完為止

在Java中:

private static Pair<Integer, Integer> findClosestSum(List<Integer> X, List<Integer> Y, int target) {
    double bestDifference = Integer.MAX_VALUE;
    Pair<Integer, Integer> bestPair = null;
    int xIndex = 0;
    int yIndex = Y.size() - 1;

    while (true) {
        double sum = X.get(xIndex) + Y.get(yIndex);
        double difference = Math.abs(sum - target);
        if (difference < bestDifference) {
            bestPair = new Pair<>(X.get(xIndex), Y.get(yIndex));
            bestDifference = difference;
        }

        if (sum > target) {
            yIndex -= 1;
            if (yIndex < 0) {
                return bestPair;
            }
        } else if (sum < target) {
            xIndex += 1;
            if (xIndex == X.size()) {
                return bestPair;
            }
        } else {
            // Perfect match :)
            return bestPair;
        }
    }
}

您可以通過起始段落中的邏輯證明此算法是詳盡無遺的。 對於沒有被訪問的任何一對,必須有包括訪問,它的兩個元件中的一個的一對,並具有嚴格更接近目標的總和。

編輯:如果您只想要小於目標的總和(不是那些超調的那些),則仍然適用相同的邏輯。 在過沖情況下,(x,y')與(x,y)一樣無效,因此它不能是更好的候選和。 在這種情況下,只需要修改第2步,只有當它是迄今為止最接近的非超越總和時才存儲總和。

謝謝你的算法,我實現了我的邏輯。 是的,它確實需要是目標下面最接近的一對,所以我相應地進行了代碼更改。 由於輸入可能是重復的,因此我也確保了句柄。 結果也可能是多個,因此也可以處理。 如果您發現任何潛在的優化,請告訴我。 這是代碼:

  public static List<List<Integer>> findClosest(int[] x, int[] y, int target){
         List<List<Integer>> result = new ArrayList<List<Integer>>();
         int[] pair = new int[2];
         int bestDiff = Integer.MIN_VALUE;
         int xIndex = 0;
         int yIndex = y.length - 1;
         //while left doesn't reach left end and right doesn't reach right end
         while(xIndex < x.length && yIndex >= 0){
             int xValue = x[xIndex];
             int yValue = y[yIndex];
             int diff = xValue + yValue - target;
             //values greater than target, y pointer go right
             if(diff > 0){
                 yIndex--;
                 while(yIndex > 0 && yValue == y[yIndex - 1]) yIndex--;
             }else{//combined == 0 which match target and < 0 which means the sum is less than target
                 //duplicates result, just add
                 if(diff == bestDiff){
                     result.add(Arrays.asList(xValue, yValue));
                 }
                 //found better pair, clear array and add new pair
                 else if(diff > bestDiff){
                     result.clear();
                     result.add(Arrays.asList(xValue, yValue));
                     bestDiff = diff;
                 }
                 xIndex++;
             }
         }
         return result;
  }

暫無
暫無

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

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