数组的全排列

Leetcode 46. Permutations 数组的全排列

· TotalAccepted: 160245
· TotalSubmissions: 378230
· Difficulty: Medium
· Contributor: LeetCode
Given a collection of distinct 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],
[3,2,1]
]
法一:使用回溯法,先固定一个字符不变,然后全排列后面的字符;使用后面的一个字符替换固定的字符,再求一次后面的全排列。
比如123,先固定1,求23的全排列(固定2,求3的全排列;2和3交换,固定3,求2的全排列) ;1和2交换,固定2,求13的全排列(固定1,求3的全排列…)…

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
    List<List<Integer>> result = new ArrayList<List<Integer>>();
    perm(result,nums,0,nums.length-1);
    return result;
}
public static void perm(List<List<Integer>> result, int[] nums, int start, int end){
    if(start==end){
        Integer[] ele = new Integer[nums.length];
        for(int i=0; i<nums.length; i++){
            ele[i] = nums[i];
        }
        result.add(Arrays.asList(ele));
    }
    else{
        for(int i=start; i<=end; i++){
            int temp = nums[start];
            nums[start] = nums[i];
            nums[i] = temp;
            perm(result, nums,start+1,end);

            temp = nums[start];
            nums[start] = nums[i];
            nums[i] = temp;
        }
    }
}
}

按照法1的思路还有另外一种写法(效率稍微差一点,但是可以对于下一题代码的理解有帮助作用。)

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        List<Integer> list = new ArrayList<Integer>();
        boolean[] used = new boolean[nums.length];
        perm(result,nums,list,used);
        return result;
    }
    public void perm(List<List<Integer>> res,int[] nums,List<Integer> list,boolean[] used){
        if(list.size() == nums.length){
            List<Integer> temp = new ArrayList<Integer>(list);
            res.add(temp);
        }
        else{
            for(int i = 0; i < nums.length; i++){
                if(used[i]) continue;
                used[i] = true;
                list.add(nums[i]);
                perm(res,nums,list,used);
                used[i] = false;
                list.remove(list.size()-1);
            }
        }
    }
}

法2:和法1类似,但是我感觉比第一种方法更好理解一点,可以叫他插入法,也是使用回溯的思想。
还拿123来举列子,先插入1,然后2的位置可以在1之前也可以在1之后:把2插入在1之前(21),然后3的插入有3中位置,先插入到最前面得到321,然后移除3,插入到中间231,移除3,插入到最后213,移除3之后回溯到插入2的步骤,移除2,把2插入到1的后面就变成了12,再插入3(也是3种情况312,132,123)…

public class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        List<Integer> list = new ArrayList<Integer>();
        perm(result,nums,0,list);
        return result;
    }
    public void perm(List<List<Integer>> res,int[] nums,int end,List<Integer> list){
        if(end == nums.length){
            List<Integer> temp = new ArrayList<Integer>(list);
            res.add(temp);
        }
        else{
            for(int i = 0; i <= end; i++){
                list.add(i,nums[end]);
                perm(res,nums,end+1,list);
                list.remove(i);
            }
        }
    }
}

Leetcode 47. Permutations II 数组的全排列2
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
For example,
[1,1,2] have the following unique permutations:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
主要的思想其实和上一题的第一种方法差不多,也是固定一个然后求后面的全排列,对于相同数字的处理,比如说1,1,2,就是已经固定过一个1,求12的全排列了,那么下一个1就不进行固定求全排列的流程了,直接continue,固定下一个字符。理解者有困难的话可以看上一道题法1的第二个版本,这个是在那个版本的基础上修改的。

public class Solution {
    public List<List<Integer>> permuteUnique(int[] nums) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        List<Integer> list = new ArrayList<Integer>();
        boolean[] used = new boolean[nums.length]; 
        Arrays.sort(nums);
        perm(nums,list,res,used);
        return res;
    }
    public void perm(int[] nums,List<Integer> list,List<List<Integer>> res,boolean[] used){
        if(list.size() == nums.length){
            res.add(new ArrayList<Integer>(list));
        }
        else{
            for(int i = 0; i < nums.length; i++){
                //已经被使用过了
                if(used[i]) continue;
                //和前一个一样,并且前一个没有被使用,前一个现在没有被使用
                //其实就是代表着已经在上一轮是用过了,
                //那么与他相同的字符这一轮在使用就和上一轮得到的效果应该完全相同,所以直接continue
                if(i > 0 && nums[i-1] == nums[i] && !used[i-1]) continue;
                used[i] = true;
                list.add(nums[i]);
                perm(nums,list,res,used);
                used[i] = false;
                list.remove(list.size() - 1);
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在C语言中实现数组全排列,可以使用递归方法。以下是两种不同的实现方法: 方法一: ```c #include <stdio.h> #include <stdlib.h> void swap(int arr[], int a, int b) { int temp = arr[a]; arr[a = arr[b]; arr[b = temp; } void perm(int a[], int begin, int n) { if (begin == n) { for (int i = 0; i <= n; i++) { printf("%d ", a[i]); } printf("\n"); } else { for (int k = begin; k <= n; k++) { swap(a, begin, k); perm(a, begin + 1, n); swap(a, begin, k); } } } int main() { int* a; int n; scanf("%d", &n); a = (int*)calloc(n, sizeof(int)); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } perm(a, 0, n - 1); free(a); return 0; } ``` 方法二: ```c #include <stdio.h> void Permutation(int m, int n, int arr[], int temp[]) { if (m >= n) { for (int i = 0; i < n-1; i++) { printf("%d ", arr[i]); } printf("%d\n", arr[n-1]); } else { for (int i = 0; i < n; i++) { if (temp[i == 0) { temp[i = 1; arr[m = i + 1; Permutation(m + 1, n, arr, temp); temp[i = 0; } } } } int main() { int arr = 0; } Permutation(0, n, arr, temp); return 0; } ``` 以上是两种C语言实现数组全排列的方法,你可以根据需要选择其中的一种方法来使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [排列组合之——全排列(c语言)](https://blog.csdn.net/m0_74820906/article/details/127779230)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [C语言实现排列组合(全排列)](https://blog.csdn.net/weixin_45652695/article/details/104212424)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值