[英]Adding sets of integers to an array decreasing size of each set added by half
[英]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 的答案相似。 它實現了檢查selectedTotal
和discardedTotal
的(小)優化以在超過目標時中止分支(注意,這假設所有值都是正的;如果不是這種情況,最小值是,例如, 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.