491非递减子序列
力扣题目链接
题目描述:
给你一个整数数组 nums
,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
示例 1:
输入:nums = [4,6,7,7] 输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
示例 2:
输入:nums = [4,4,3,2,1] 输出:[[4,4]]
代码:
用哈希表
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1) {result.push_back(path);}int used[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]for (int i = startIndex; i < nums.size(); i++) {if ((!path.empty() && nums[i] < path.back())|| used[nums[i] + 100] == 1) {continue;}used[nums[i] + 100] = 1; // 记录这个元素在本层用过了,本层后面不能再用了path.push_back(nums[i]);backtracking(nums, i + 1);path.pop_back();}}
public:vector<vector<int>> findSubsequences(vector<int>& nums) {result.clear();path.clear();backtracking(nums, 0);return result;}
};
不用哈希表,用set
class Solution {
private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {if (path.size() > 1) {result.push_back(path);// 注意这里不要加return,要取树上的节点}unordered_set<int> uset; // 使用set对本层元素进行去重for (int i = startIndex; i < nums.size(); i++) {if ((!path.empty() && nums[i] < path.back())|| uset.find(nums[i]) != uset.end()) {continue;}uset.insert(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了path.push_back(nums[i]);backtracking(nums, i + 1);path.pop_back();}}
public:vector<vector<int>> findSubsequences(vector<int>& nums) {result.clear();path.clear();backtracking(nums, 0);return result;}
};
46全排列
力扣题目链接
题目描述:
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1] 输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1] 输出:[[1]]
代码:
class Solution {
public: // 存储所有不重复的全排列结果 vector<vector<int>> result; // 当前构建的全排列路径 vector<int> path; // 回溯函数 void backtracking(vector<int> nums, vector<bool> &used) { // 基本情况:当路径的长度与 nums 的长度相等时,说明现有排列已完整 if (path.size() == nums.size()) { result.push_back(path); // 将当前排列加入结果集中 return; // 结束当前递归 } // 遍历所有元素,用于构建全排列 for (int i = 0; i < nums.size(); i++) { // 如果当前元素未被使用 if (used[i] == false) { used[i] = true; // 标记当前元素为已使用 path.push_back(nums[i]); // 将当前元素加入路径 // 递归调用回溯函数,继续构建下一个元素 backtracking(nums, used); // 回溯:撤销选择,恢复状态 path.pop_back(); // 从路径中移除当前元素 used[i] = false; // 将当前元素标记为未使用 } } } // 主函数,接收输入并返回所有不重复的全排列 vector<vector<int>> permute(vector<int>& nums) { result.clear(); // 清空结果集 path.clear(); // 清空当前路径 vector<bool> used(nums.size(), false); // 初始化使用标记数组,初始时都未使用 backtracking(nums, used); // 调用回溯函数开始生成全排列 return result; // 返回生成的所有不重复全排列 }
};
47全排列||
题目题目链接
题目描述:
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2] 输出: [[1,1,2],[1,2,1],[2,1,1]]
示例 2:
输入:nums = [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
class Solution {
private: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++) {// used[i - 1] == true,说明同一树枝nums[i - 1]使用过// used[i - 1] == false,说明同一树层nums[i - 1]使用过// 如果同一树层nums[i - 1]使用过则直接跳过if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {continue;}if (used[i] == false) {used[i] = true;path.push_back(nums[i]);backtracking(nums, used);path.pop_back();used[i] = false;}}}
public:vector<vector<int>> permuteUnique(vector<int>& nums) {result.clear();path.clear();sort(nums.begin(), nums.end()); // 排序vector<bool> used(nums.size(), false);backtracking(nums, used);return result;}
};
-
去重的核心逻辑:
- 这里的去重逻辑比较巧妙:
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) { continue; }
i > 0
:确保不是第一个元素。nums[i] == nums[i - 1]
:检查当前元素和前一个元素是否相同(即为重复)。used[i - 1] == false
:确保只有在前一个相同元素未被使用时,当前元素才会被考虑。所以只在使用前一个相同元素的情况下,才会使用当前元素,避免生成重复的排列。
- 这里的去重逻辑比较巧妙:
意思就是,在已经确定了第二个元素时(也就是当前元素是true)而前一个元素是false时说明前一个元素肯定已经考虑过了,因为遍历是从左往右遍历,此时如果不进行continue,就会重复考虑相同元素,所以当used[i - 1] == false
:时就cotinue
-
标记使用状态:
- 在选择某个元素之后,将其标记为已使用:
used[i] = true; path.push_back(nums[i]);
- 进入递归调用,生成剩下的排列。
- 递归完成后,回退状态:
path.pop_back(); used[i] = false;
- 在选择某个元素之后,将其标记为已使用:
-
主函数
permuteUnique
:- 初始化
result
和path
,并创建一个布尔数组used
来跟踪元素使用状态,调用backtracking
函数。
- 初始化