491.递增子序列
本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。
一个是去重,一个是判断是否递增;去重发生在横向,递增发生在纵向。
横向去重需要额外构建一个集合。
Python:
python
class Solution:
def __init__(self):
self.result = []
self.path = []
def backtracking(self, nums, start_index):
if len(self.path)>=2:
self.result.append(self.path[:])
used_set = set()
for i in range(start_index, len(nums)):
if len(self.path)>=1 and nums[i]<self.path[-1]: # 纵向去重
continue
if nums[i] in used_set: # 横向去重
continue
used_set.add(nums[i])
self.path.append(nums[i])
self.backtracking(nums, i+1)
self.path.pop()
return
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
self.backtracking(nums, 0)
return self.result
C++:
cpp
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
if (path.size()>=2) result.push_back(path);
unordered_set<int> uset;
for (int i=startIndex; i<nums.size(); i++) {
if (uset.find(nums[i])!=uset.end()) continue;
if (!path.empty() && nums[i]<path.back()) continue;
uset.insert(nums[i]);
path.push_back(nums[i]);
backtracking(nums, i+1);
path.pop_back();
}
return;
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
backtracking(nums, 0);
return result;
}
};
46.全排列
本题重点感受一下,排列问题 与 组合问题,组合总和,子集问题的区别。 为什么排列问题不用 startIndex
视频讲解:组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列_哔哩哔哩_bilibili
Python:
python
class Solution:
def __init__(self):
self.result = []
self.path = []
def backtracking(self, nums, k):
if len(self.path)==k:
self.result.append(self.path[:])
for i in range(len(nums)):
self.path.append(nums[i])
new_nums = nums[:i] + nums[i+1:]
self.backtracking(new_nums, k)
self.path.pop()
return
def permute(self, nums: List[int]) -> List[List[int]]:
k = len(nums)
self.backtracking(nums, k)
return self.result
C++:
用指针实现标记是否使用过,更为节省内存和时间。
cpp
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, vector<bool>& used) {
if (path.size()==nums.size()) {
result.push_back(path);
return;
}
for (int i=0; i<nums.size(); i++) {
if (used[i] == true) continue;
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = false;
}
return;
}
vector<vector<int>> permute(vector<int>& nums) {
vector<bool> used(nums.size(), false);
backtracking(nums, used);
return result;
}
};
47.全排列 II
本题 就是我们讲过的 40.组合总和II 去重逻辑 和 46.全排列 的结合,可以先自己做一下,然后重点看一下 文章中 我讲的拓展内容。 used[i - 1] == true 也行,used[i - 1] == false 也行
Python:
python
class Solution:
def __init__(self):
self.result = []
self.path = []
def backtracking(self, nums, used):
if len(self.path) == len(nums):
self.result.append(self.path[:])
return
uset = set()
for i in range(len(nums)):
if used[i]: continue # 纵向去重
if nums[i] in uset: continue # 横向去重
uset.add(nums[i])
used[i] = True
self.path.append(nums[i])
self.backtracking(nums, used)
self.path.pop()
used[i] = False
return
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
nums.sort()
used = [False] * len(nums)
self.backtracking(nums, used)
return self.result
C++:
cpp
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, vector<bool>& used) {
if (path.size()==nums.size()) {
result.push_back(path);
}
unordered_set<int> uset;
for (int i=0; i<nums.size(); i++) {
if (uset.find(nums[i]) != uset.end()) continue;
if (used[i]==true) continue;
used[i] = true;
uset.insert(nums[i]);
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = false;
}
return;
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
vector<bool> used(nums.size(), false);
backtracking(nums, used);
return result;
}
};