[Leetcode]Permutations && Permutations II

Given a collection of numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:

[1,2,3][1,3,2][2,1,3][2,3,1][3,1,2], and [3,2,1].

组合的题目,第一题无重复,第二题有重复。

自我感觉最常规的方法就是回溯法,两道题都试用。第一道没有重复的情况下还可以有更取巧的办法,第二题貌似只能用回溯法。

先看第一题。

用回溯法,假设一共n个数字,对结果中的每一位元素i,都要把所有数字带进去试一下,只要不和前面的数字重复就OK。

 class Solution {
 public:
	 vector<vector<int> > result;
	 vector<vector<int> > permute(vector<int> &num) {
		 int n = num.size();
		 vector<int> oneAnswer;
		 searchAnswer(oneAnswer,num,n,0);
		 return result;
	 }
	 void searchAnswer(vector<int> &oneAnswer,vector<int> num,int n,int index){
		 for (int i = 0; i < n;i++){
			 if (!repeat(oneAnswer,num[i])){
				 oneAnswer.push_back(num[i]);
				 if (oneAnswer.size() == n){
					 result.push_back(oneAnswer);
					 oneAnswer.pop_back();
					 return;
				 }
				 searchAnswer(oneAnswer,num,n,index+1);
				 oneAnswer.pop_back();
			 }
		 }
	 }
	 bool repeat(vector<int> oneAnswer,int x){
		 for (int i = 0; i < oneAnswer.size(); i++){
			 if (x == oneAnswer[i]){
				 return true;
			 }
		 }
		 return false;
	 }
 };
还有一种方法就是类似建立一个树。

最后排列的结果,第一个元素可能有四种情况,那就将1、2、3、4个元素分别和第一个元素交换位置,每个元素交换位置之后为了方便下一个元素交换,要先把位置换回去,也就是回到数组的初始状态。然后是第二个元素和后面的元素交换。 

class Solution{
public:
    vector<vector<int> > permute(vector<int> &num){
        vector<vector<int> > result;
        dfs(result,num,0);
        return result;
    }
    void dfs(vector<vector<int> > &result,vector<int> &num,int cur){
        if(cur == num.size()){
            result.push_back(num);
        }
        else{
            for(int i = cur;i < num.size();i++){
                swap(num[i],num[cur]);
                dfs(result,num,cur+1);
                swap(num[i],num[cur]);
            }
        }
    }
};

然后是第二题。

[1,1,2] have the following unique permutations:
[1,1,2][1,2,1], and [2,1,1].

第二题数组中有重复元素,那就不能像第一题那样使用回溯条件了。

1、在每一步迭代(或者说结果的每一个位置上)中,出现过的元素就不能再出现了。比如说上边的例子,第一个位置是元素第一个1,那么第二个1就不能出现在这个位置上。因此,我们给每一位设置一个出现过的元素数组vector<int> used,来保存已经出现的元素,这些元素是不能再一次出现在这个位置上的。
2、在上面条件满足的基础上,不同位置上是可以出现重复元素的,因此不能像第一题中那样再去检查元素是否重复了。元素可以重复,但是他们的下标是不能重复的。因此我们在用一个vector<int> indexUsed,来保存出现过的元素下标就可以了。

class Solution {
public:
	vector<vector<int> > result;
	vector<vector<int> > permuteUnique(vector<int> &num) {
		int n = num.size();
		vector<int> oneAnswer;
		vector<int> indexUsed;
		searchAnswer(oneAnswer, num, indexUsed, n, 0);
		return result;
	}
	void searchAnswer(vector<int> &oneAnswer, vector<int> num,vector<int> indexUsed, int n, int index){
		vector<int> used;
		for (int i = 0; i < n; i++){
			if (!repeat(used, num[i])&&!repeat(indexUsed,i)){
				used.push_back(num[i]);
				oneAnswer.push_back(num[i]);
				indexUsed.push_back(i);
				if (oneAnswer.size() == n){
					result.push_back(oneAnswer);
					oneAnswer.pop_back();
					indexUsed.pop_back();
					return;
				}
				searchAnswer(oneAnswer, num, indexUsed, n, index + 1);
				oneAnswer.pop_back();
				indexUsed.pop_back();
			}
		}
	}
	bool repeat(vector<int> oneAnswer, int x){
		for (int i = 0; i < oneAnswer.size(); i++){
			if (x == oneAnswer[i]){
				return true;
			}
		}
		return false;
	}
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值