数据结构和算法:从0到1系列 回溯小专题
深度优先搜索DFS | 回溯算法:力扣46. 全排列
result = []
def backtrack(选择列表,路径):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(选择列表,路径)
撤销选择
# 做选择
将该选择从选择列表移除
路径.add(选择)
# 撤销选择
路径.remove(选择)
将该选择再加入选择列表
解决一个回溯问题,实际上就是一个决策树的遍历过程:
1、路径:也就是已经做出的选择。
2、选择列表:也就是你当前可以做的选择。
3、结束条件:也就是到达决策树底层,无法再做选择的条件。
当然本题在for循环里剪枝,画一个多叉树,可以发现,在多叉树最开始的分支里,如果遇到相同的数,就剪枝,当然之后的每个分支也是一样,如果在同一层遇到相同的开始,就剪枝。
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
#回溯
res = []
visited = [False for _ in range(len(nums))]
def backtrack(nums,path,visited):
if len(path) == len(nums):
if path not in res:
res.append(path[:])
return
for i in range(len(nums)):
if not visited[i]:
if i > 0 and nums[i] == nums[i-1] and not visited[i-1]: #剪枝
continue
path.append(nums[i])
visited[i] = True
backtrack(nums,path,visited)
visited[i] = False
path.pop()
backtrack(nums,[],visited)
return res
C++实现:
class Solution {
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
// 回溯
vector<vector<int>> res;
vector<int> path;
int n = nums.size();
vector<int> visited(n);
sort(nums.begin(),nums.end());
backtrack(nums,path,visited,res);
return res;
}
void backtrack(vector<int>& nums,vector<int>& path,vector<int>& visited,vector<vector<int>>& res){
if (nums.size() == path.size()){
res.push_back(path);
return;
}
for (int i=0;i < nums.size();i++){
if (!visited[i]){
if (i > 0 && nums[i] == nums[i-1] && !visited[i-1]){
continue;
}
path.push_back(nums[i]);
visited[i] = 1;
backtrack(nums,path,visited,res);
visited[i] = 0;
path.pop_back();
}
}
}
};