全排列问题

全排列问题

一、数组中不包含重复的数字

题目

在这里插入图片描述

思路

题目要求我们找出一个不包含重复数字的一个序列的全排列,对于全排列问题,我们可以这样进行思考:每一个位置所有数字都有可能进行选择,如:有数组[1, 2, 3]我们求它的全排列,对于第一个位置有:[1, ], [2, ], [3, ],对于第二个位置(我们要依据于第一个位置进行判断,因为我们最终的数是一个长度为3的序列)有:([1, 2], [1, 3]),([2, 1],[2, 3]),([3, 1],[3, 2]),对于第三个位置无疑是确定的(对于一个长度有限且已知的序列而言),那么最后的结果为:[1, 2, 3], [1, 3, 2],[2, 1, 3],[2, 3, 1],[3, 1, 2],[3, 2, 1],结果一共有6个不相同的排列。通过这个思路,我们可以设计出一个算法。

对于每一个位置,我们可以将当前位置和其之后位置的数进行填充,直到填充满位置

最简单的思路就是使用递归的思想,每次判断完成一个位置之后就进行递归判断下一个位置(需要注意的是,再进行递归之后还需要将位置进行换回来,保证这个位置的数字始终是和原来的数字进行做交换的)

为什么要换回来:

如1, 2, 3 在第一个位置的时候,循环的时候第一个数i = pos,首先pos会和自己进行交换,得到[1, ],这个位置不换回来不影响最后的结果,但是在第二个数的时候i = pos + 1,将pospos + 1进行了交换,如果不换回来,就会导致在第三个数的时候i = pos + 2pos + 1进行交换了,这并不是与第一个位置上的数进行了交换,会导致结果出现错误。

核心代码
vector<vector<int>> ans;  // 用于记录全排列的结果 
void fullyArranged(vector<int> nums, int pos){   // 参数解释:nums传递过来的数组,pos当前的位置 
	// 首先判断边界问题,如果填充满了,就加入到结果数组中去
	if(pos == int(nums.size() - 1)){
		// 将结果进行添加 
		ans.push_back(nums);
		return ;
	} 
	
	
	// 进行位置交换
	for(int i = pos + 1;i < nums.size();i ++){
		swap(nums[pos], nums[i]);  // 当前位置与之后的每一个位置进行交换 
		fullyArranged(nums, pos + 1);   //每一个位置进行交换之后就进行判断下一个位置的情况 
		swap(nums[pos], nums[i]);  // 交换之后还需要再交换回来 
	}
	
	return ;
}

代码

调试代码
// 全排列问题
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

vector<vector<int>> ans;  // 用于记录全排列的结果 

// 不去重的全排列
void fullyArranged(vector<int>& nums, int pos){   // 参数解释:nums传递过来的数组,pos当前的位置 
	// 首先判断边界问题
	if(pos == int(nums.size() - 1)){
		// 将结果进行添加 
		ans.push_back(nums);
		return ;
	} 
	
	// 进行位置交换
	for(int i = pos + 1;i < nums.size();i ++){
		swap(nums[pos], nums[i]);  // 当前位置与之后的每一个位置进行交换 
		fullyArranged(nums, pos + 1);   //每一个位置进行交换之后就进行判断下一个位置的情况 
		swap(nums[pos], nums[i]);  // 交换之后还需要再交换回来,以保证i始终是和num[pos]进行交换的。
	}
	
	return ;
}

// 查看全排列之后的结果
void Traverse(){
	for(auto r : ans){
		for(auto c : r) cout<<c<<' '; 
		cout<<endl;
	}
    //	for(int i = 0;i < ans.size();i++){
    //		for(int j = 0;j < ans[i].size();j++){
    //			cout<<ans[i][j]<<' '; 
    //		}
    //		cout<<endl;
    //	}
} 

// 解决方案
void solve(){
	// 举例:1,2,3的全排列
	vector<int> nums = {1, 2, 3};
	// 进行全排列
	fullyArranged(nums, 0);
	// 进行输出所有结果
	Traverse();
	
	return ;
} 


int main(){
	int t = 1;
	while(t--){
		solve();
	} 

	return 0;
} 
力扣提交代码
class Solution {
public:
    vector<vector<int>> ans;
    void fullArranged(vector<int> &nums, int pos){
        // 如果满了进行存储
        if(pos == nums.size() - 1){
            ans.push_back(nums);
            return ;
        }
        // 否则继续进行遍历
        for(unsignd i = pos;i < nums.size();i++){
            swap(nums[pos], nums[i]);
            fullArranged(nums, pos + 1);
            swap(nums[pos], nums[i]);
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        fullArranged(nums, 0);
        return ans;
    }
};

在这里插入图片描述


二、数组中含有重复的数字

题目

在这里插入图片描述

思路

包含重复数字的序列与不包含重复数字的序列的思想大体相同,只是在原有的基础上多进行判断了一次是否有重复数字。

解决方案:首先对序列进行排序,然后再每个位置进行判断的时候,都判断该位置之前是否有与之相同的数字进行过了一次交换,如果有:就进行跳过,否则:就进行交换

核心代码
vector<vector<int>> ans;  // 用于记录全排列的结果 
sort(nums.begin(), nums.end());
// 去重的全排列问题
void fullArrangedPro(vector<int>& nums, int pos){
	if(pos == int(nums.size() - 1)){
		ans.push_back(nums);
		return ;
	}
	for(int i = pos;i < nums.size();i++){
		bool flag = false;  // 设定一个标记,用于标记是否有重复数字进行了交换
		// 与之前交换过的所有数进行判断是否已经有相同的数进行了交换
		for(int j = pos;j < i;j ++){
			if(nums[j] == nums[i]){
				flag = true;
			}
		} 
        // 进行正常的交换
		if(!flag){
			swap(nums[pos], nums[i]);
			fullArrangedPro(nums, pos + 1);
			swap(nums[pos], nums[i]);
		}
	}
	
	return ;
}

代码

调试代码
// 全排列问题
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>

vector<vector<int>> ans;  // 用于记录全排列的结果 

// 去重的全排列问题
void fullArrangedPro(vector<int>& nums, int pos){
	if(pos == int(nums.size() - 1)){
		ans.push_back(nums);
		return ;
	}
	for(unsigned i = pos;i < nums.size();i++){
		bool flag = false;
		// 与之前交换过的所有数进行判断是否已经有相同的数进行了交换
		for(int j = pos;j < i;j ++){
			if(nums[j] == nums[i]){
				flag = true;
			}
		} 
		if(!flag){
			swap(nums[pos], nums[i]);
			fullArrangedPro(nums, pos + 1);
			swap(nums[pos], nums[i]);
		}
	}
	
	return ;
}


// 查看全排列之后的结果
void Traverse(){
	for(auto r : ans){
		for(auto c : r) cout<<c<<' '; 
		cout<<endl;
	}
} 

// 解决方案
void solve(){
	// 举例:1,2,3的全排列
	vector<int> nums = {1, 3, 1};
	// 进行全排列
//	fullyArranged(nums, 0);
	sort(nums.begin(), nums.end());
	fullArrangedPro(nums, 0);
	// 进行输出 
	Traverse();
	
	return ;
} 


int main(){
	int t = 1;
	while(t--){
		solve();
	} 

	return 0;
} 
力扣提交代码
class Solution {
public:
    // 可能包含重复数字
    vector<vector<int>> ans;
    void fullArrangedPro(vector<int>& nums, int pos){
        if(pos == nums.size() - 1){
            ans.push_back(nums);
            return ;
        }
        // 继续进行判断
        for(int i = pos;i < nums.size(); i++){
            // 设定一个标记用于标记是否已经有重复的数字进行标记过了
            bool flag = false;
            // 循环遍历已经交换过的部分,判断是否有重复的数字
            for(int j = pos;j < i;j ++){   // 注意这里不能再包含第i个数了,因为第i个数是需要判断的位置
                if(nums[j] == nums[i]){
                    flag = true;
                    break;
                }

            }
            // 如果没有重复的数,就对当前的位置进行交换位置
            if(!flag){
                swap(nums[pos], nums[i]);
                fullArrangedPro(nums, pos + 1);
                swap(nums[pos], nums[i]);
            }
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        fullArrangedPro(nums, 0);
        return ans;
    }
};

在这里插入图片描述

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值