组合算法

常用的排列数组合数、子集的个数问题

leetcode 46题 [1,2,3] 所有的全排列问题
这是一个不需要去重的全排列问题.
拿[1,2,3]举例子, 1,2,3 接着是 1,3,2 2,1,3 2,3,1 可以找出规律 2,3交换生成3,2....

每次交换 然后接着下一次进行

 class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result=new ArrayList<>();
        permuteReclusive(result,nums, 0, nums.length-1);
    return result;
    }


    public void permuteReclusive(List<List<Integer>> result, int[] nums, int start, int end){

        if(start==end+1){ // 长度
         List<Integer> param=new ArrayList<Integer>();
            for(int i=0;i<nums.length;i++){
                param.add(nums[i]);
            }
            result.add(param);
            return ;
        }

        for(int i=start;i<=end;i++){
            if(i!=start){ // 交换
                int tmp=nums[i];
                nums[i]=nums[start];
                nums[start]=tmp;
            }
          // 接着下一波的数据 
            permuteReclusive(result, nums, start+1,end);
            if(i!=start){ // 交换回来
             int tmp=nums[i];
                nums[i]=nums[start];
                nums[start]=tmp;
            }
        }
    }
}

对于leetcode 31 本质上也是求全排列中的某个排列下的下一个排列

主要思路是先从尾部到头部找出nums[i]>nums[i-1]的第一次出现的位置设为d=i-1;
接着从尾部到头部找出大于nums[d]的第一个元素出现的位置, m. 把nums[m]和nums[d]交换, 然后再把d+1开始的数据逆序. 我们可以通过这种方法实现全排列问题.代码如下

class Solution {

    public List<List<Integer>> permute(int[] nums) {

        List<List<Integer>> result = new ArrayList<>();
        int[] copy = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            copy[i] = nums[i];
        }
        boolean istart = true;
        while (istart || isSame(copy, nums)) {
            istart = false;
            List<Integer> param = new ArrayList<Integer>();
            for (int i = 0; i < nums.length; i++) {
                param.add(nums[i]);
            }
            result.add(param);

            nextPermute(nums);
        }

        return result;
    }


    public boolean isSame(int[] copy, int[] nums) {

        for (int i = 0; i < nums.length; i++) {

            if (copy[i] != nums[i]) return true;
        }

        return false;
    }

    public void nextPermute(int[] nums) {
        int d = -1; // 表示分割点
        int m = -1; // 表示大于点
        int len = nums.length;
        for (int i = len - 2; i >= 0; i--) {

            if (nums[i + 1] > nums[i]) {
                d = i;
                break;
            }
        }
        if (d == -1) {
            for (int i = 0; i < (len - 1) / 2; i++) {
                int tmp = nums[i];
                nums[i] = nums[len - 1 - i];
                nums[len - 1 - i] = tmp;
            }
            return;
        }
        for (int i = len - 1; i >= 0; i--) {
            if (nums[i] > nums[d]) {
                m = i;
                break;
            }
        }
        int tmp = nums[d];
        nums[d] = nums[m];
        nums[m] = tmp;
        // 逆序
        int dest = (len - 1 + d + 1) / 2;
        for (int i = d + 1; i <= dest; i++) {
            tmp = nums[i];
            nums[i] = nums[len - 1 - i + d + 1];
            nums[len - 1 - i + d + 1] = tmp;
        }
    }

}

实现全排列代码
class Solution {

public List<List<integer>> permute(int[] nums) {</integer>

    List<List<Integer>> result = new ArrayList<>();
    int[] copy = new int[nums.length];
    for (int i = 0; i < nums.length; i++) {
        copy[i] = nums[i];
    }
    boolean istart = true;
    while (istart || isSame(copy, nums)) {
        istart = false;
        List<Integer> param = new ArrayList<Integer>();
        for (int i = 0; i < nums.length; i++) {
            param.add(nums[i]);
        }
        result.add(param);

        nextPermute(nums);
    }

    return result;
}


public boolean isSame(int[] copy, int[] nums) {

    for (int i = 0; i < nums.length; i++) {

        if (copy[i] != nums[i]) return true;
    }

    return false;
}

public void nextPermute(int[] nums) {
    int d = -1; // 表示分割点
    int m = -1; // 表示大于点
    int len = nums.length;
    for (int i = len - 2; i >= 0; i--) {

        if (nums[i + 1] > nums[i]) {
            d = i;
            break;
        }
    }
    if (d == -1) {
        for (int i = 0; i <=(len - 1) / 2; i++) {
            int tmp = nums[i];
            nums[i] = nums[len - 1 - i];
            nums[len - 1 - i] = tmp;
        }
        return;
    }
    for (int i = len - 1; i >= 0; i--) {
        if (nums[i] > nums[d]) {
            m = i;
            break;
        }
    }
    int tmp = nums[d];
    nums[d] = nums[m];
    nums[m] = tmp;
    // 逆序
    int dest = (len - 1 + d + 1) / 2;
    for (int i = d + 1; i <=dest; i++) {
        tmp = nums[i];
        nums[i] = nums[len - 1 - i + d + 1];
        nums[len - 1 - i + d + 1] = tmp;
    }
}

}
leetcode 47 Permutations II 去重之后的全排列个数

这道题有两种解法

  1. 在46题基础上加一个判断是否已经存在相同元素, 存在就没必要再次交换。
public List<List<Integer>> permuteUnique(int[] nums) {    List<List<Integer>> result=new ArrayList<>();        
        permuteReclusiveUnique(result, nums, 0);

        return result;
    }

public void permuteReclusiveUnique(List<List<Integer>>result, int[]nums, int start){        
        if(start==nums.length){
            // 数据保存
            List<Integer>params=new ArrayList<>();
            for(int i=0;i<nums.length;i++){
                params.add(nums[i]);
            }
            result.add(params);
        }


        for(int i=start;i<nums.length;i++){


            if(!isOk(nums, start, i)){
                continue;
            }

            if(i!=start){
                int tmpt=nums[i];
                nums[i]=nums[start];
                nums[start]=tmpt;
            }

            permuteReclusiveUnique(result, nums, start+1);

            if(i!=start){

                int tmpt=nums[i];
                nums[i]=nums[start];
                nums[start]=tmpt;
            }


        }

    }
    public boolean isOk(int[]nums, int start, int end){
        for(int i=start;i<end;i++){
            if(nums[i]==nums[end]) return false;
        }
       return true;
    }
  1. 在31题基础上直接获取所有可能情况, 直到等于原来的情况.
    public List<List<integer>> permuteUnique(int[] nums) {</integer>

     List<List<Integer>> result = new ArrayList<>();
     int[] copy = new int[nums.length];
     for (int i = 0; i < nums.length; i++) {
         copy[i] = nums[i];
     }
     boolean istart = true;
     while (istart || isSame(copy, nums)) {
         istart = false;
         List<Integer> param = new ArrayList<Integer>();
         for (int i = 0; i < nums.length; i++) {
             param.add(nums[i]);
         }
         result.add(param);
    
         nextPermute(nums);
     }
    
     return result;

    }

public boolean isSame(int[] copy, int[] nums) {

    for (int i = 0; i < nums.length; i++) {

        if (copy[i] != nums[i]) return true;
    }

    return false;
}

public void nextPermute(int[] nums) {
    int d = -1; // 表示分割点
    int m = -1; // 表示大于点
    int len = nums.length;
    for (int i = len - 2; i >= 0; i--) {

        if (nums[i + 1] > nums[i]) {
            d = i;
            break;
        }
    }
    if (d == -1) {
        for (int i = 0; i <=(len - 1) / 2; i++) {
            int tmp = nums[i];
            nums[i] = nums[len - 1 - i];
            nums[len - 1 - i] = tmp;
        }
        return;
    }
    for (int i = len - 1; i >= 0; i--) {
        if (nums[i] > nums[d]) {
            m = i;
            break;
        }
    }
    int tmp = nums[d];
    nums[d] = nums[m];
    nums[m] = tmp;
    // 逆序
    int dest = (len - 1 + d + 1) / 2;
    for (int i = d + 1; i <=dest; i++) {
        tmp = nums[i];
        nums[i] = nums[len - 1 - i + d + 1];
        nums[len - 1 - i + d + 1] = tmp;
    }
}

leetcode 78题 求所有子集

思路 本质上是每个元素取或者不取两种情况

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> results=new ArrayList<>();
        List<Integer> param=new ArrayList<>();
        ReclusiveTheSubSet(results, param, nums, 0);
        return results;
    }

    public void ReclusiveTheSubSet(List<List<Integer>> results,List<Integer> param, int[] nums, int start){

        results.add(new ArrayList<>(param));
        for(int i=start;i<nums.length;i++){
            param.add(nums[i]);  // 取这个元素
            ReclusiveTheSubSet(results, param, nums, i+1);
            param.remove(param.size()-1); // 不取这个元素
        }
    }
}

leetcode 90 subset去重

class Solution {

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>>results=new ArrayList<>();
        // 必须先排序
        Arrays.sort(nums);
        List<Integer> param=new ArrayList<>();
        ReclusiveTheSubset(results, param, nums, 0);
        return results;
    }


    public void ReclusiveTheSubset(List<List<Integer>> results, List<Integer>param, int[]nums, int start){
        results.add(new ArrayList<>(param));
        for(int i=start;i<nums.length;i++){
             // 去重操作
            if(isOk(nums, start, i)){continue;}
            param.add(nums[i]);
            ReclusiveTheSubset(results, param, nums, i+1);
            param.remove(param.size()-1);
        }
    }

    public boolean isOk(int[]nums, int start, int end){
        for(int i=start;i<end;i++){
            if(nums[i]==nums[end]) return true;
        }
        return false;
    }

}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务