每周算法:找出指定求和的组合
leetcode第39题,难度为medium,考察回溯算法(backtracking)的使用。
Description
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
Example 1:
Input: candidates = [2,3,6,7], target = 7, A solution set is: [ [7], [2,2,3] ]
Example 2:
Input: candidates = [2,3,5], target = 8, A solution set is: [ [2,2,2,2], [2,3,3], [3,5] ]
Solution
Approach 1 brute force
使用暴力解法求解。
bool sumEqual(vector<int>& nums, int target) {
for (int n : nums) {
target -= n;
if (target < 0) {
return false;
}
}
return target == 0;
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
set<vector<int>> ans;
sort(candidates.begin(), candidates.end());
// 将所有可能的组合都列举出来
bool f = target%candidates.front() == 0;
int lenMax = target/candidates.front() + (f ? 0 : 1); // 可能的最大长度
list<vector<int>> bfs;
bfs.push_back(vector<int>());
while(!bfs.empty()) {
vector<int> temp = bfs.front();
bfs.pop_front();
if (temp.size() >= size_t(lenMax)) {
if (sumEqual(temp, target)) {
ans.insert(temp);
}
continue;
}
for (int n : candidates) {
if (!temp.empty() && temp.back() > n) {
if (sumEqual(temp, target)) {
ans.insert(temp);
}
continue;
}
temp.push_back(n);
bfs.push_back(temp);
temp.pop_back();
}
}
return vector<vector<int>>(ans.begin(), ans.end());
}
Approach 2 traceback
这道题使用回溯算法(backtraking)求解比较合适。
static void helper(const std::vector<int>& cand,
int target,
std::vector<std::vector<int>>& ans,
std::vector<int>& combi,
int sum,
int pos) {
if (sum > target) {
return;
}
else if (sum == target) {
ans.push_back(combi);
return;
}
for (size_t i=pos; i<cand.size(); ++i) {
combi.push_back(cand[i]);
helper(cand, target, ans, combi, sum+cand[i], i);
combi.pop_back();
}
}
std::vector<std::vector<int>> combinationSum(std::vector<int>& cand, int target) {
std::sort(cand.begin(), cand.end());
std::vector<std::vector<int>> ans;
std::vector<int> combi;
helper(cand, target, ans, combi, 0, 0);
return ans;
}
N-Queen problem
回溯算法的最典型的应用是八皇后问题,下面就是八皇后问题的解法代码。使用回溯算法求解N皇后问题的时间复杂度为 O(N!)
。
bool solveNQUtil(int board[N][N], int col) {
/* base case: If all queens are placed then return true */
if (col >= N)
return true;
/* Consider this column and try placing this queen in all rows one by one */
for (int i = 0; i < N; i++) {
/* Check if queen can be placed on board[i][col] */
if ( isSafe(board, i, col) ) {
/* Place this queen in board[i][col] */
board[i][col] = 1;
/* recur to place rest of the queens */
if ( solveNQUtil(board, col + 1) == true )
return true;
/* If placing queen in board[i][col] doesn't lead to a solution then remove queen from board[i][col] */
board[i][col] = 0; // BACKTRACK
}
}
}