簡體   English   中英

將數組拆分為兩個偶數集合,每個集合使兩個集合相加為相同的數字

[英]Split array into two even sets of integers, each so that both sets add up to the same number

我在面試時遇到了這個問題,似乎無法思考如何解決它。 我還沒有找到任何解釋其背后邏輯的教程。

使用函數ArrayChallenge(arr) ,獲取存儲在arr的整數數組,該數組始終包含偶數個整數,並確定如何將它們拆分為兩個偶數集合,然后返回第一個集合的字符串表示,然后是第二個集合,每個整數用逗號分隔,兩個集合都按升序排序。 先行的集合是第一個整數最小的集合。

例如,如果 arr 是 [16,22,35,8,20,1,21,11],那么你的程序應該輸出 1,11,20,35,8,16,21,22

[16,22,35,8,20,1,21,11] 總和 = 134

1,11,20,35 之和 = 67 8,16,21,22 之和 = 67

兩個數組的大小也等於 arr.length /2

問題不需要按時間順序編碼。 制定一個集中程序來解決這個背包問題,但不要編碼。 然后對結果進行排序,並給出結果。

現在如果你解決失敗,比如超時,仍然有一個方法完成。

通過使用數組arr ,將其除以 2,然后搜索這個半和的子數組,可以進一步簡化問題。

該問題提出了一些奇怪的限制: arr保留偶數個值 (8),兩個結果數組應具有相同的偶數個值(均為 4)。

選擇第 i值所屬的子數組是二進制的。

所以從一個排序的數組開始,當達到一半時切割解決方案。

您可以從 00001111(位 1 的一半)開始,這可能太大了,接下來的位將是 00010111, 00011011, 00011101, 00011110, 00101110, ...

更容易的可能是簡單的遞歸,計數高達一半:

// Array arr sorted decreasingly to have less values to try out.
boolean solve(Set<Integer> selectedNumbers, int selectedSum, int index) {
    if (selectedNumbers.size() >= arr.length/2) {
        return sum == arrSum/2;
    }
    if (index > arr.length) {
        return false;
    }
    boolean solved = false;

    // First case: add array element at this index:
    if (selectedSum + arr[index] <= arrSum/2) {
        seplectedNumbers.add(arr[index]);
        arrSum += arr[index];
        solved = solve(selectedNumbers, arrSum, index + 1);
        if (!solved) {
            // No remove(int index), so remove an Object, Integer.
            selectedNumbers.remove(Integer.valueOf(arr[index]));
            arrSum -= arr[index];
        }
    }

    // Second case: do not add array element at this index:
    if (!solved) {
        solved = solve(selectedNumbers, arrSum, index + 1);
    }
    return solved;
}

以上當然是蠻力解決方案。 如果您從事運籌學研究,您可能會發現這些數字的分布(如提到的位)。 但是需要時間,對我來說,我微薄的數學知識會阻止這一點。 解決后,如果您知道更快的解決方案,您可能會發表評論。

這個答案在精神上與Joop Eggen 的答案相似。 它實現了檢查selectedTotaldiscardedTotal的(小)優化以在超過目標時中止分支(注意,這假設所有值都是正的;如果不是這種情況,最小值是,例如, x < 0 ,您只需將-x添加到所有值,運行算法並從答案中減去-x )。

輸出與原始帖子中指定的完全相同 - 並且由於它僅在找到完整解決方案時生成,因此此代碼應該比不斷添加和從部分答案中刪除值的算法更快,例如 Joop's ( selectedNumbers.add后跟selectedNumbers.remove當結果不起作用時;set 操作可能很快,但不執行它們甚至更快!)。

public class Main {
    public static boolean search(int[] values, int goal, int index,
                                int selectedTotal, int discardedTotal,
                                List<Integer> selected, List<Integer> discarded) {
        if (selected.size() == values.length/2 &&
                discarded.size() == values.length/2) {
            return selectedTotal == goal;
        }
        if (selectedTotal > goal ||
                discardedTotal > goal ||
                index == values.length) {
            return selectedTotal == goal;
        }

        // try selecting value at index ...
        if (selected.size() < values.length/2 &&
                search(values, goal, index + 1,
                    selectedTotal + values[index], discardedTotal,
                    selected, discarded)) {
            selected.add(values[index]);
            return true;
        }

        // ... and, if that did not work, try discarding value at index
        if (discarded.size() < values.length/2 &&
                search(values, goal, index + 1,
                    selectedTotal, discardedTotal + values[index],
                    selected, discarded)) {
            discarded.add(values[index]);
            return true;
        }
        return false;
    }

    public static List<Integer> solve(int[] values) {
        Arrays.sort(values);
        int goal = IntStream.of(values).sum() / 2;
        List<Integer> selected = new ArrayList<>();
        List<Integer> discarded = new ArrayList<>();
        if ( ! search(values, goal, 0,
                0, 0, selected, discarded)) {
            throw new IllegalArgumentException("This puzzle cannot be solved");
        }
        Collections.reverse(selected);
        Collections.reverse(discarded);
        selected.addAll(discarded);
        return selected;
    }

    public static void main(String[] args) {
        System.out.println(solve(new int[] {16,22,35,8,20,1,21,11}));
    }
}

您將使用迭代並首先遍歷數組。 然后你做2個整數。 在每個迭代周期中,首先檢查 integer1 是否大於 integer2。 然后將一個數字放入 array1 並將其值添加到 integer1。 重復。 如果 int1 大於 int2,則將其放入 array2 並將值添加到 int2。 最后,對數組進行排序就大功告成了。 這就是我將如何解決它。 這行得通嗎? 我真的很感興趣。

暫無
暫無

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

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