回溯算法--全排列

  • 输入: [1,2,3]
  • 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

注意

  1. 不是组合问题,{1, 2}, {2, 1}是不一样的,因此不可以使用startIndex
  2. 也无关层之间去重,没有重复的元素。
  3. 需要考虑的是选完一个元素后,往下递归还能继续选择前面的元素。

used: 一个标记数组,记录哪些元素在当前路径中已经被使用了,即可解决问题3

代码

cpp 复制代码
class Solution {
private:
	vector<vector<int>> result; 
	vector<int> path;           
	
	// 核心回溯函数
	// nums: 原始数组
	// used: 一个标记数组,记录哪些元素在当前路径中已经被使用了
	void backtracking(const vector<int>& nums, vector<bool>& used) {
		// 1. 递归终止条件
		// 当 path 的长度等于 nums 的长度时,说明找到了一个完整的全排列
		if(path.size() == nums.size()){
			result.push_back(path); // 将当前路径加入结果集
			return;                 // 结束当前递归分支
		}
		
		// 2. 单层搜索逻辑
		// 遍历 nums 中的每一个元素,尝试将其加入当前路径
		for(int i = 0; i < nums.size(); i++){
			// 如果 nums[i] 已经被使用过(在当前 path 中),则跳过,避免重复
			if(used[i])
				continue;
			
			// 3. 处理节点(做选择)
			used[i] = true;         // 标记当前元素已使用
			path.push_back(nums[i]); // 将当前元素加入路径
			
			// 4. 递归调用
			// 进入下一层决策树,继续填下一个位置的数
			backtracking(nums, used);
			
			// 5. 回溯(撤销选择)
			// 当从递归返回时,说明当前分支已经探索完毕
			// 需要将状态恢复到进入递归之前,以便尝试 for 循环中的下一个数字
			used[i] = false;        // 撤销标记
			path.pop_back();        // 将当前元素移出路径
		}
	}
	
public:
	vector<vector<int>> permute(vector<int>& nums) {
		result.clear();
		path.clear();
		// 初始化 used 数组,大小与 nums 相同,初始全为 false
		vector<bool> used(nums.size(), false);
		
		backtracking(nums, used);
		return result;
	}
};

变形--全排列II

  • 输入:nums = [1,1,2]
  • 输出: [[1,1,2], [1,2,1], [2,1,1]]
  • nums无序

这个就很简单了,加上层之间的去重就可以了,但是需要注意层去重有两种,有序和无序。

这里的nums无序只能使用unordered_set。单层循环逻辑里面加入去重即可。

cpp 复制代码
unordered_set<int> uset;
		for(int i = 0; i < nums.size(); i++){
			if(used[i] || uset.find(nums[i]) != uset.end())
				continue;
			
			uset.insert(nums[i]);
			used[i] = true;         // 标记当前元素已使用
			path.push_back(nums[i]); // 将当前元素加入路径
			
			backtracking(nums, used);
			
			used[i] = false;        // 撤销标记
			path.pop_back();        // 将当前元素移出路径
		}
相关推荐
DeeplyMind13 分钟前
少儿科技启蒙教材:《数据结构启蒙》
数据结构·计算机科学·少儿科技读物·蓝桥杯青少组
近津薪荼15 分钟前
递归专题(2)——合并链表
c++·学习·算法·链表
Asher阿舍技术站16 分钟前
【数字通信理论系列】四、载波相位同步
算法·载波同步
圣保罗的大教堂17 分钟前
leetcode 3013. 将数组分成最小总代价的子数组 II 困难
leetcode
划破黑暗的第一缕曙光20 分钟前
[数据结构]:6.二叉树链式结构的实现2
c语言·数据结构·二叉树
-Try hard-20 分钟前
队列 | 二叉树
算法
maplewen.21 分钟前
C++11 std::function
开发语言·c++
Sagittarius_A*22 分钟前
灰度变换与阈值化:从像素映射到图像二值化的核心操作【计算机视觉】
图像处理·人工智能·opencv·算法·计算机视觉·图像阈值·灰度变换
水饺编程31 分钟前
第4章,[标签 Win32] :文本尺寸的度量
c语言·c++·windows·visual studio
Nie_Xun31 分钟前
卡尔曼滤波(EKF/IEKF)与非线性优化(高斯-牛顿法)的统一关系
算法