求全排列、组合、子集,C++程序总结

在力扣上刷到的这类题,做一个总结。思路相似,都可以用回溯(决策树)解决。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;


// 全排列-------------------------------------------------------------------------------------------------------------
// 问题:给定数组nums,求集合nums的全排列
void back_track1(vector<int>& nums, vector<int>& track, vector<vector<int>>& res);	// 先声明回溯函数,函数定义在后面

vector<vector<int>> permute(vector<int>& nums) {
	vector<vector<int>> res;			 // 保存答案        
	vector<int> track;					 // 路径:在决策树中已经做出的选择
	back_track1(nums, track, res);       // 回溯算法
	return res;
}

void back_track1(vector<int>& nums, vector<int>& track, vector<vector<int>>& res) {
	// 递归结束条件:路径大小==nums大小,到达决策树底层
	int nums_siz = nums.size();
	if (track.size() == nums_siz) {
		res.push_back(track);
		return;
	}

	for (int i = 0; i < nums_siz; ++i) {
		// 做选择
		auto iter = find(track.begin(), track.end(), nums[i]);
		if (iter != track.end()) {
			continue;
		}			
		track.push_back(nums[i]);
		back_track1(nums, track, res);
		// 撤销选择
		track.pop_back();
	}
}



// 组合--------------------------------------------------------------------------------------------------------
// 问题:1~n共n个数,求k个数的所有组合
void back_track2(int n, int k, int start, vector<int>& track, vector<vector<int>>& res);
vector<vector<int>> combine(int n, int k) {
	vector<vector<int>> res;	
	vector<int> track;					 // 路径:在决策树中已经做出的选择
	back_track2(n, k, 1, track, res);
	return res;
}

void back_track2(int n, int k, int start, vector<int> &track, vector<vector<int>> &res) {
	// 递归结束条件:路径大小==k,到达决策树底层
	if (track.size() == k) {
		res.push_back(track);
		return;
	}
	
	// i 从 start 开始递增
	for (int i = start; i <=n; i++) {
		// 做选择
		track.push_back(i);
		// 回溯
		back_track2(n, k, i+1, track, res);
		// 撤销选择
		track.pop_back();
	}
}



// 子集--------------------------------------------------------------------------------------------------------
// 问题:给定数组nums,求集合nums的所有子集
// 方法一:
// 空集的子集:{}
// 有一个元素的集合{a}的子集:{}、{a}
// 有两个元素的集合{a,b}的子集:{}、{a}    、{b}、{a,b}
// 集合每增加一个元素,其子集为:原集合子集、原集合的每个子集中加上新增加的这个元素
// 递归程序:
vector<vector<int>> subsets(vector<int>& nums) {
	// 递归结束条件:nums为空,返回一个空集。
	if (nums.empty()) return { {} };
	
	int n = nums.back();	// 把nums最后一个元素拿出来
	nums.pop_back();
	vector<vector<int>> res = subsets(nums);	// 前面元素的所有子集
	
	// 然后在 前面元素的所有子集 后增加这个元素
	int siz = res.size();
	for (int i = 0; i < siz; i++) {
		res.push_back(res[i]);
		res.back().push_back(n);
	}
	return res;
}

// 子集
// 方法二:回溯
void back_track3(vector<int>& nums, int start, vector<int>& track, vector<vector<int>>& res);

vector<vector<int>> subset_method2(vector<int>& nums) {
	vector<vector<int>> res;         // 保存答案
	vector<int> track;               // 路径:在决策树中已经做出的选择	
	back_track3(nums, 0, track,res);
	return res;
}

void back_track3(vector<int>& nums, int start, vector<int>& track, vector<vector<int>> &res) {
	res.push_back(track);
	// i 从 start 开始递增
	int siz = nums.size();
	for (int i = start; i <siz; i++) {
		// 做选择
		track.push_back(nums[i]);
		// 回溯
		back_track3(nums, i + 1, track,res);
		// 撤销选择
		track.pop_back();
	}
}

// 控制台输出二维数组
void print(vector<vector<int>> &res) {
	for (auto it : res) {
		for (auto i : it) {
			cout << i << "  ";
		}
		cout << "  ;  ";
	}
}

int main()
{
   
    vector<int> nums{ 1,2,3 };
	// 全排列	
	vector<vector<int>> res=permute(nums);
	cout << endl << "全排列:";
	print(res);

	// 子集
	vector<vector<int>> res1=subset_method2(nums);
	cout << endl << "子集,方法二:";
	print(res1);
	vector<vector<int>> res2 = subsets(nums);
	cout << endl << "子集,方法一:";
	print(res2);

	// 组合
	vector<vector<int>> res3 = combine(5, 2);
	cout << endl << "组合:";
	print(res3);

   cout << "\n";
}

程序运行示例结果如下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章