有重复元素的全排列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有重复元素的全排列相关的知识,希望对你有一定的参考价值。

这是我的代码: #include <stdio.h> #include "stdlib.h" inline void Swap(char& a, char& b) // 交换a和b char temp = a; a = b; b = temp; void Perm(char list[], int k, int m) //生成list [k:m ]的所有排列方式 int i; if (k == m) //输出一个排列方式 for (i = 0; i <= m; i++) putchar(list[i]); putchar('\n'); 为什么输出结果不是Sample Input 输入 4 aacc 输出 aacc acac acca caac caca ccaa 6
#include <stdio.h>
#include "stdlib.h"
inline void Swap(char& a, char& b)
// 交换a和b
char temp = a;
a = b;
b = temp;


void Perm(char list[], int k, int m)
//生成list [k:m ]的所有排列方式
int i;
if (k == m) //输出一个排列方式
for (i = 0; i <= m; i++)
putchar(list[i]);
putchar('\n');

else // list[k:m ]有多个排列方式
// 递归地产生这些排列方式
for (i=k; i <= m; i++)
if(list[k]!=list[i])
Swap (list[k], list[i]);
Perm (list, k+1, m);
Swap (list [k], list [i]);


int main()
int i,k,j;

scanf("%d",&i);

char s[i];
for(k=0;k<i;k++)
scanf("%c",&s[k]);
// char s[]="abc";

Perm(s, 0,j);

system("pause");

return 0;

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
// 字符串最大长度
#define MAX_STRING_LENGTH 50
// 全排列顺序。TRUE:按字母序升序;FALSE:按字母序降序。
#define PERMUTATION_ASSCENDING_ORDER TRUE
// qsort 函数使用的比较函数
int compare(const void *a, const void *b)

return PERMUTATION_ASSCENDING_ORDER
? *((char*)a) - *((char*)b)
: *((char*)b) - *((char*)a);

/*
无重复全排序。
参数:
str 要进行无重复全排序的字符串。
字符串内字符必须已经排序过(升序或降序都可以)

isUsed 如果 isUsed[i] = TRUE 表示 str[i] 已经加入当前排列中

p 当前排列中已经存在的字符数

buffer 当前的排列。
buffer[0]~buffer[p-1] 是 str 中已经加入排列的字符。

返回:
无重复全排序的总数。
*/
int Perm(char str[],int isUsed[],int p ,char buffer[])

int len=strlen(str),i,j,total=0;

if(p == len)
// 输出一个全排列
printf("%s\n",buffer);
return 1;


for(i=0;i<len;i++)

if(!isUsed[i])

// 查询当前字符的后面,是否已经有和当前字符相同的字母加入了全排序中。
for(j=i+1;j<len;j++)
if(str[i]==str[j] && isUsed[j])
break;

if(j == len)
// 当前字符的后面,没有和当前字符相同的字母加入了全排序中。
// 当前字符可以加入全排序

isUsed[i] = TRUE;
buffer[p] = str[i];
total += Perm(str,isUsed,p+1,buffer);
isUsed[i] = FALSE;



return total;


int main(int argc, char *argv[])

char str[MAX_STRING_LENGTH]="aacc";
char buffer[MAX_STRING_LENGTH]=0;
int isUsed[MAX_STRING_LENGTH]=0;

while(scanf("%s",str)!=EOF)

// 先按字母序排序
qsort(str,strlen(str),sizeof(str[0]),compare);
// 全排列
printf("Total %d\n\n",Perm(str,isUsed,0,buffer));

return 0;
参考技术A 代码不全!~ 没有主函数。
把函数改成:
void Perm(char list[], int k, int m)
//生成list [k:m ]的所有排列方式
int i;
if (k == m) //输出一个排列方式
for (i = 0; i <=m; i++)
putchar(list[i]);
putchar('\n');

else // list[k:m ]有多个排列方式
// 递归地产生这些排列方式
for (int t,i=k; i <=m; i++)
//查找以前是否出现过
for(t=k;t<i;t++)

if(list[t]==list[i])
break;

if(t==i)

Swap (list[k], list[i]);
Perm (list, k+1, m);
Swap (list [k], list [i]);




另外主函数测试可写成:
int main() int i,k,j;
//scanf("%d",&i);
//for(k=0;k<i;k++)
//scanf("%c",&s[k]);
char s[]="aacc";

Perm(s, 0,4-1);
system("pause");
return 0;

递归与回溯14:排列问题,有重复元素的全排列

LeetCode47,与前面的不同是给定的数字序列可能有重复,请你返回全排列结果。例如:

输入:nums = [1,1,2]
输出: [[1,1,2], [1,2,1], [2,1,1]]

为了方便去重一定要对元素经行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。

我以示例中的 [1,1,2]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:

 图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。一般来说:组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。

class Solution 
    //存放结果
    List<List<Integer>> result = new ArrayList<>();
    //暂存结果
    List<Integer> path = new ArrayList<>();

    public List<List<Integer>> permuteUnique(int[] nums) 
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);
        Arrays.sort(nums);
        backTrack(nums, used);
        return result;
    

    private void backTrack(int[] nums, boolean[] used) 
        if (path.size() == nums.length) 
            result.add(new ArrayList<>(path));
            return;
        
        for (int i = 0; i < nums.length; i++) 
            // used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过
            // used[i - 1] == false,说明同⼀层nums[i - 1]使⽤过
            // 如果同⼀层nums[i - 1]使⽤过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) 
                continue;
            
            //如果同⼀树⽀nums[i]没使⽤过开始处理
            if (used[i] == false) 
                used[i] = true;//标记同⼀树⽀nums[i]使⽤过,防止同一树支重复使用
                path.add(nums[i]);
                backTrack(nums, used);
                path.remove(path.size() - 1);//回溯,说明同⼀树层nums[i]使⽤过,防止下一树层重复
                used[i] = false;//回溯
            
        
    

以上是关于有重复元素的全排列的主要内容,如果未能解决你的问题,请参考以下文章

全排列:不含重复元素和含重复元素的全排列

作业2.有重复全排列和无重复全排列的区别

递归与回溯14:排列问题,有重复元素的全排列

力扣:包含重复元素的全排列问题

Concise and clear CodeForces - 991F(dfs 有重复元素的全排列)

刷题——有重复元素的全排列(Permutations II)