Постановка задачи
Имея набор номеров кандидатов (candidates) и целевое число (target), найдите все уникальные комбинации в candidates, где сумма номеров кандидатов равна цель.
Каждое число в кандидатах может использоваться только один раз в комбинации.
Примечание. Набор решений не должен содержать повторяющихся комбинаций.
Пример 1:
Input: candidates = [10, 1, 2, 7, 6, 1, 5], target = 8
Output:
[
[1, 1, 6],
[1, 2, 5],
[1, 7],
[2, 6]
]
Пример 2:
Input: candidates = [2, 5, 2, 1, 2], target = 5
Output:
[
[1, 2, 2],
[5]
]
Ограничения:
- 1 <= candidates.length <= 100
- 1 <= candidates[i] <= 50
- 1 <= target <= 30
Объяснение
Возвращение
Задачу можно решить, используя аналогичный подход, который мы использовали в нашем последнем блоге Сумма комбинаций. Единственное отличие состоит в том, что каждый элемент в candidates может использоваться только один раз. Использование каждого элемента только один раз может быть достигнуто путем перехода к следующему индексу при рекурсивном вызове функции.
Еще одно отличие состоит в том, что наш набор решений не должен содержать повторяющихся комбинаций. В постановке задачи не упоминается, что массив отсортирован. Чтобы избежать дублирования наборов результатов, нам нужно отсортировать массив и избегать использования одних и тех же элементов.
Сначала проверим алгоритм.
- initialize the result as a 2D array initialize current as an array
// n = index, at start it will be 0. // sumTillNow = sum of the current elements in the array, at the start it will be 0 // current = current list of elements in the array, at the start it will be an empty array [] - call combinationSum2Util(result, candidates, current, n, sumTillNow, target)
- return result
// combinationSum2Util function - if sumTillNow == target // append current to result - result.push_back(current)
- if sumTillNow > target - return
- set prev = -1
- loop for i = n; i <= candidates.size() - 1; i++ - if prev != candidates[i] // append candidates array ith element to the current array - current.push_back(candidates[i])
- sumTillNow += candidates[i]
// call the function recursively - combinationSumUtil(result, candidates, i, target, sumTillNow, current)
- sumTillNow -= current[current.size() - 1]
// remove the last element from the array - current.pop_back()
- prev = candidates[i] - end of if
Давайте проверим наши решения на C++, Golang и Javascript.
С++ решение
class Solution { public: void combinationSum2Util(vector<vector<int>> &result, vector<int>& candidates, vector<int>& current, int index, int sumTillNow, int target) { if(sumTillNow == target) { result.push_back(current); return; }
if(sumTillNow > target) { return; }
int prev = -1;
for(int i = index; i <= candidates.size() - 1; i++) { if(prev != candidates[i]) { current.push_back(candidates[i]); sumTillNow += candidates[i];
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target); sumTillNow -= current[current.size() - 1];
current.pop_back(); prev = candidates[i]; } } }
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { vector<vector<int>> result; vector<int> current;
sort(candidates.begin(), candidates.end()); combinationSum2Util(result, candidates, current, 0, 0, target); return result; } };
Голанг решение
func combinationSum2Util(result *[][]int, candidates, current []int, index, sumTillNow, target int) { if sumTillNow == target { *result = append(*result, append([]int{}, current...)) return }
if sumTillNow > target { return }
prev := -1
for i := index; i < len(candidates); i++ { if prev != candidates[i] { current = append(current, candidates[i]) sumTillNow += candidates[i]
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target) sumTillNow -= current[len(current) - 1] current = current[:len(current) - 1] prev = candidates[i] } } }
func combinationSum2(candidates []int, target int) [][]int { result := make([][]int, 0)
sort.Ints(candidates) combinationSum2Util(&result, candidates, []int{}, 0, 0, target)
return result }
Javascript-решение
var combinationSum2 = function(candidates, target) { let result = []; candidates.sort(function(a, b){ return a - b });
const combinationSum2Util = (candidates, current, index, sumTillNow, target) => { if( sumTillNow == target ) { result.push([...current]); return; }
if( sumTillNow > target ) { return; }
let prev = -1;
for(let i = index; i < candidates.length; i++) { if(prev != candidates[i]) { current.push(candidates[i]); sumTillNow += candidates[i];
combinationSum2Util(candidates, current, i + 1, sumTillNow, target);
sumTillNow -= current[current.length - 1]; current.pop();
prev = candidates[i]; } } }
combinationSum2Util(candidates, [], 0, 0, target);
return result; };
Давайте запустим наш алгоритм.
Input: candidates = [2, 5, 2, 1, 2] target = 5
// combinationSum function Step 1: vector<vector<int>> result vector<int> current
Step 2: sort(candidates.begin(), candidates.end() [1, 2, 2, 2, 5]
Step 3: combinationSum2Util(result, candidates, current, 0, 0, target)
// combinationSum2Util function Step 4: if sumTillNow == target 0 == 5 false
if sumTillNow > target 0 > 5 false
prev = -1
loop for int i = index; i <= candidates.size() - 1 i = 0 0 <= 5 - 1 true
- if prev != candidates[i] -1 != 1 true
current.push_back(candidates[i]) current.push_back(candidates[0]) current.push_back(1) current = [1]
sumTillNow += candidates[i] = sumTillNow + candidates[0] = 0 + 1 = 1
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target) combinationSum2Util([][], [1, 2, 2, 2, 5], [1], 1, 1, 5)
Step 5: if sumTillNow == target 1 == 5 false
if sumTillNow > target 1 > 5 false
prev = -1
loop for int i = index; i <= candidates.size() - 1 i = 1 1 <= 5 - 1 true
- if prev != candidates[i] -1 != 2 true
current.push_back(candidates[i]) current.push_back(candidates[1]) current.push_back(2) current = [1, 2]
sumTillNow += candidates[i] = sumTillNow + candidates[1] = 1 + 2 = 3
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target) combinationSum2Util([][], [1, 2, 2, 2, 5], [1, 2], 3, 3, 5)
Step 6: if sumTillNow == target 3 == 5 false
if sumTillNow > target 3 > 5 false
prev = -1
loop for int i = index; i <= candidates.size() - 1 i = 2 2 <= 5 - 1 true
- if prev != candidates[i] -1 != 2 true
current.push_back(candidates[i]) current.push_back(candidates[1]) current.push_back(2) current = [1, 2, 2]
sumTillNow += candidates[i] = sumTillNow + candidates[1] = 3 + 2 = 5
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target) combinationSum2Util([][], [1, 2, 2, 2, 5], [1, 2, 2], 3, 5, 5)
Step 7: if sumTillNow == target 5 == 5 true
result.push_back(current) result = [[1, 2, 2]]
return
we backtrack to step 6 and continue
Step 8: combinationSumUtil([][], [1, 2, 2, 2, 5], [1, 2, 2], 3, 5, 5) sumTillNow = sumTillNow - current[current.size() - 1] = 5 - current[3 - 1] = 5 - current[2] = 5 - 2 = 3
current.pop_back() current = [1, 2]
prev = candidates[i] = candidates[2] = 2
i++ i = 3
loop for int i = index; i <= candidates.size() - 1 i = 3 3 <= 5 - 1 true
- if prev != candidates[3] 2 != 2 false
i++ i = 4
loop for int i = index; i <= candidates.size() - 1 i = 3 4 <= 5 - 1 true
- if prev != candidates[4] 2 != 5 true
current.push_back(candidates[i]) current.push_back(candidates[4]) current.push_back(5) current = [1, 2, 5]
sumTillNow += candidates[i] = sumTillNow + candidates[4] = 3 + 5 = 8
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target) combinationSum2Util([][], [1, 2, 2, 2, 5], [5], 5, 8, 5)
Step 9: if sumTillNow == target 8 == 5 false
if sumTillNow > target 8 > 5 true return
we backtrack to step 5 and continue
Step 10: combinationSum2Util([][], [1, 2, 2, 2, 5], [1, 2], 3, 3, 5) sumTillNow = sumTillNow - current[current.size() - 1] = 3 - current[2 - 1] = 3 - current[1] = 3 - 2 = 1
current.pop_back() current = [1]
prev = candidates[i] = candidates[1] = 2
i++ i = 2
loop for int i = index; i <= candidates.size() - 1 i = 2 2 <= 5 - 1 true
- if prev != candidates[3] 2 != 2 false
i++ i = 3
loop for int i = index; i <= candidates.size() - 1 i = 3 3 <= 5 - 1 true
- if prev != candidates[3] 2 != 2 false
i++ i = 4
loop for int i = index; i <= candidates.size() - 1 i = 4 4 <= 5 - 1 true
- if prev != candidates[4] 2 != 5 true
current.push_back(candidates[i]) current.push_back(candidates[4]) current.push_back(5) current = [1, 5]
sumTillNow += candidates[i] = sumTillNow + candidates[4] = 1 + 5 = 6
combinationSum2Util(result, candidates, current, i + 1, sumTillNow, target) combinationSum2Util([][], [1, 2, 2, 2, 5], [1, 5], 5, 6, 5)
Step 11: if sumTillNow == target 6 == 5 false
if sumTillNow > target 6 > 5 true return
we backtrack to step 4 and continue
We similarly iterate from index 2, backtrack, and then reach the last index.
We return the answer as [ [1, 2, 2], [5] ]
Первоначально опубликовано на https://alkeshghorpade.me.