有重复元素的全排列问题

有重复元素的全排列问题
只是在没有重复的全排列问题上去除重复的部分即可

思想方法:递归
例如
s[4]=aacc

  1. s[0] 作为head 全排列剩下的三个
  2. s[1] 与s[0] 交换 由于s[1]==s[0] 不交换
    如果交换,那么全排列剩下的三个,剩下的三个依然是acc 与情况一相同,我们不能出现重复的,所以不能交换
  3. s[2] 与s[0] 交换,由于前面并没有出现过c所以可以交换
  4. s[3] 与s[0] 交换,由于s[2]==s[3] 不交换
    如果交换,那么和情况3重复,解释与2相同
  5. 交换过后的字符串就可以根据递归的方式递归计算剩下 的三个元素的全排列,两个元素的全排列,直到只剩一个元素的全排列,就说明已经没有元素了,就可以输出了

如何去掉重复的元素
判断需要交换的元素是否在前面出现过,如果出现过就返回false,不能交换,如果没有出现过就可以交换
可以看下图,从begin开始到p-1,因为我们可以发现已经有一个c了,如果交换,就会出现重复的现象,所以在这里beigin和p不能交换
在这里插入图片描述
下面的代码是一个没有输出的解决重复元素全排列的问题

//判断是否可以交换
bool isSwap(string str,int begin,int p)
{
	//是否可以交换,就是看是交换的元素和前面的那些元素有没有重复
	for(int i=begin;i<p;i++)
	{
		if(str[p]==str[i])
		return false;
	}
	return true;
}


void Per(string str,int begin,int end)   //从begin开始到end结尾的str的带有重复元素的全排列
{
//位置1
	for(int i=begin;i<=end;i++)
	{
		/*如果begin可以和i交换就交换,不可以那么就继续循环*/
		if(isSwap(str,begin,i))
		{
			swap(str[begin],s[i]);
			//确定好了头元素,那么就可以排列剩下的了
			//位置2
			per(str,begin+1,end);
			//位置3
			swap(str[begin],s[i]);
			//位置4
		}
	}
}

重复的全排列就是比没有重复元素的多了个比较

如果需要输出,在什么情况下进行输出呢?
因为如果交换一次,那么就会产生一个新的序列,所以我尝试了在位置2进行元素的输出,结果是错误的
位置2虽然进行了一次交换,但是这个序列的交换并没有完成一次的遍历,只有完成一次的遍历才能算作是一次排列
就例如对aacc进行排列,第一次一定是s[0]与s[0]进行交换,这样才能完成后面s[1]-s[3]的全排列,如果在这个时候进行输出,将相当于s[1]-s[3]没有进行排列就会输出一次aacc,接下来就会进行s[1]与s[1]的交换,又会输出aacc,所以这个地方是不正确的

那么在全排列之后进行输出总可以吧,这也是不可以的,这个是在每次全排列之后进行输出,也就是当aacc中s[4]与s[3]进行返回后会输出aacc,然后又会在s[3]-s[3]进行返回后,输出aacc依次类推,所以是不正确的

位置4是第二次交换,会回到原来的位置也不正确

位置1,可以判断当一次排列排到最后也就是begin==end的时候,进行输出

牛客网
有重复项数字的全排列

vector<vector<int> > answer;
    set<vector<int> > ans;
    
    bool iSwap(vector<int> num, int begin,int position)   //就是看他卡面有没有相同的
    {
        
        for(int i=begin;i<position;i++)
        {
            if(num[i]==num[position])
                return false;
        }
        return true;       
    }
    
    void bfs(vector<int> &num, int begin, int endi)
    {
        
         if(begin==endi)
         { ans.insert(num);
          return;
         }
       for(int i=begin;i<=endi;i++)
       {
           if(iSwap(num,begin,i))
           {
               //把begin和i进行交换
               swap(num[begin],num[i]);
               //对剩下的元素进行排序
               bfs(num,begin+1,endi);
               swap(num[begin],num[i]);
           }
       }
    }
    
    vector<vector<int> > permuteUnique(vector<int> &num) {
        sort(num.begin(),num.end());
        bfs(num,0,num.size()-1);
        for(auto iter=ans.begin();iter!=ans.end();iter++)
        {
            answer.push_back(*iter);
        }
        return answer;
    }

如何进行升序排列输出
这道题有一个特别的要求,需要按升序进行排列输出,这里使用set进行存储,set本身就是按照升序进行排列的

递归排序练习
字符串的排序

  • 15
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
重复元素全排列流程图如下: 1. 首先将字符串按照字典序排序,以便后续判断重复元素。 2. 从第一个元素开始,依次与后面的元素交换位置,直到最后一个元素。 3. 在交换过程中,判断是否有重复元素即将被交换,如果有则跳过这次交换。 4. 交换完成后,将当前元素与下一个元素交换位置,重复步骤3。 5. 当交换到最后一个元素时,输出当前排列结果。 举个例子,对于字符串"abb"的全排列流程如下: 1. 首先将字符串按照字典序排序,得到"abb"。 2. 从第一个元素"a"开始,依次与后面的元素交换位置,得到"bab"和"bba"。 3. 在交换过程中,判断是否有重复元素即将被交换,发现"b"即将与"b"交换,跳过这次交换。 4. 将当前元素"b"与下一个元素"b"交换位置,得到"abb"。 5. 交换到最后一个元素,输出当前排列结果"abb"。 6. 从第二个元素"b"开始,依次与后面的元素交换位置,得到"bab"和"bba"。 7. 在交换过程中,发现"b"即将与"a"交换,跳过这次交换。 8. 将当前元素"b"与下一个元素"b"交换位置,得到"abb"。 9. 交换到最后一个元素,输出当前排列结果"abb"。 10. 从第三个元素"b"开始,依次与后面的元素交换位置,得到"abb"和"abb"。 11. 在交换过程中,发现"b"即将与"b"交换,跳过这次交换。 12. 将当前元素"b"与下一个元素"b"交换位置,得到"abb"。 13. 交换到最后一个元素,输出当前排列结果"abb"。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值