LeetCode 数组排列组合问题汇总:

本文汇总了LeetCode上的数组排列组合问题,包括全排列(考虑重复元素)、子集生成,以及下一个排列和第K个排列的解题思路。通过递归和回溯方法解决,涉及排列组合的去重和顺序处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       字符的排列组合问题,使用递归+回溯方法。对于有重复元素或者需要组合的元素具有一定顺序,需要先进行排序。

        排列问题因为对所有元素进行排列,判断是否为结果的条件是list的大小和数组的长度相同,否则,依次将没有排列的元素添加到list中,结束一次排列后需要回溯;对于数组元素唯一,只需要在循环中判断list中是否包含该元素,不包含,进行添加,否则,跳过。对于数组元素不唯一,设置Boolean数组来标记是否访问过,并对重复出现的组合去重。

        组合问题相当于对N个元素,挑选M个元素进行全排列,需要将M作为参数进行传递 ,并设置当m==0时结束一次组合,m<0时返回。对于非递减组合,需要事先对数组进行排序,如果结果需要按照size的大小进行排序输出,可以在排列时通过for循环传入m的值,对于数组元素不唯一,可在将元素添加到list中时进行判断,由于已经进行排序,所以,只需要判定当前值与前一个元素不同即可,保证同一层搜索时只选一次一个相同的数。

     常见题解答(均已AC):

 

1.数组元素唯一的全排列:(LeetCode :permutations)

        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].

import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer>> result  = new ArrayList<ArrayList<Integer>>();
    public ArrayList<ArrayList<Integer>> permute(int[] num) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        dfs(num,list);
        return result;
    }
     public void dfs(int[] num ,ArrayList<Integer> list) {
         if(list.size() == num.length){
            result.add(new ArrayList<Integer>(list));
         }else{
             for(int i = 0 ;i<num.length;i++){
                 if(list.contains(num[i]))
                     continue;
                 list.add(num[i]);
                 dfs(num,list);
                 list.remove(list.size()-1);
             }
         }
     }
}

 

2.数组元素不唯一的全排列:(LeetCode:permutations-ii)

         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], and[2,1,1].

import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
    public ArrayList<ArrayList<Integer>> permuteUnique(int[] num) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        boolean visited[] = new boolean[num.length];
        Arrays.sort(num);
        dfs(num,list,visited);
        return result;
    }
    public void dfs(int[] num,ArrayList<Integer> list ,boolean visited[] ){
        if(list.size()==num.length){
            result.add(new ArrayList<Integer>(list));
            return;
        }else{
            for(int i =0;i<num.length;i++){
                if(visited[i])
                    continue;
                if(i>0 && num[i]==num[i-1] && !visited[i-1])
                    continue;//112,在对第二个1进行排列时
                list.add(num[i]);
                visited[i]= true;
                dfs(num,list,visited);
                visited[i]= false;
                list.remove(list.size()-1);
            }
        }
    }
}

 

3.数组元素唯一的组合:(LeetCode:subsets)

Given a set of distinct integers, S, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,
If S =[1,2,3], a solution is:

[

  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

   题意:数组元素唯一的数组,求其不递减子数组集合

import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> list = new ArrayList<Integer>();
    public ArrayList<ArrayList<Integer>> subsets(int[] S) {
        Arrays.sort(S);
        int len = S.length;
        for(int i = 0 ;i<=len;i++){
            find(S,0,i);
        }
        return result;
    }
    public void find(int[] S,int start,int m) {
        if(m<0){
            return;
        }else if(m==0){
            result.add(new ArrayList<Integer>(list));
        }else{
            for(int i = start;i<S.length;i++){
                list.add(S[i]);
                find(S,i+1,m-1);
                list.remove(list.size()-1);
            }
        }
    }
}

 

4.数组元素不唯一的组合:(LeetCode:subsets-ii)

Given a collection of integers that might contain duplicates, S, return all possible subsets.

Note:

  • Elements in a subset must be in non-descending order.
  • The solution set must not contain duplicate subsets.

For example,If S =[1,2,2], a solution is:

[

  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]

题意:数组元素不唯一的数组,求其不递减子数组集合

import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer>>  result = new  ArrayList<ArrayList<Integer>>();
    ArrayList<Integer> list = new ArrayList<Integer>();
    public ArrayList<ArrayList<Integer>> subsetsWithDup(int[] num) {
        Arrays.sort(num);
        int len = num.length;
        dfs(num,0);
        return result;
    }
    public void dfs(int[] num,int start){
         result.add(new ArrayList<Integer>(list));
         for(int i = start;i<num.length;i++){
            if(i>start && num[i]==num[i-1])
                 continue;
            list.add(num[i]);
            dfs(num,i+1);
            list.remove(list.size()-1);
        }
    }
}

 

5.下一个排列:(LeetCode:next-permutation)     

         Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).The replacement must be in-place, do not allocate extra memory.Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3→1,3,2
3,2,1→1,2,3
1,1,5→1,5,1

    题意:下一个排列是指按词典序的下一个排列。降序的排列已经是按词典序的最大的排列了,所以它的下一个就按升序排列。

    解题:找到第一个逆序的地方,如果找不到,重新对num进行排序,如果可以找到,保存具体位置pos,并从num的尾部开始找到第一个大于pos位置的数字,进行交换,并将pos以后的数字进行排序。

import java.util.*;
public class Solution {
    public void nextPermutation(int[] num) {
        int len = num.length;
        int j = len-2;
        boolean flag = false;
        for(int k = len-1;k>=0;k--){
           while(j>=0){
               if(num[len-1]>num[j]){
                   int t = num[len-1];
                   num[len-1] = num[j];
                   num[j]= t;
                   flag = true;
                   if(len-j>2)
                        Arrays.sort(num,j+1,len);
                    break;
                }
                j--; 
          }
          if(!flag){
               Arrays.sort(num);
               break;
          }
        }
    }
}

 

6.第K个排列:(LeetCode:permutation-sequence)

        The set[1,2,3,…,n]contains a total of n! unique permutations.By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

Given n and k, return the k th permutation sequence.

Note: Given n will be between 1 and 9 inclusive.

       题意:返回已知数组的全排列中的第K个排列。

        利用康托公式,康托展开的实质是计算当前排列在所有由小到大全排列中的顺序。X=a[n]*(n-1)!+a[n-1]*(n-2)!+…+a[i]*(i-1)!+…+a[1]*0! ,a[m]代表比在第m位的数字小并且没有在第m位之前出现过的数字的个数(以个位数为第1位),x代表比这个数小的数的个数,所以这个数的顺序就是x+1

https://blog.youkuaiyun.com/scarecrow398966925/article/details/25543587

        对于解码,需要先将k-1,然后依次除以阶乘获得商和余数,商表示有多少个比该位小的数字,从而确定该位的数字,然后利用余数除以下一个阶乘,获得下一位的数字,使用list来保存剩余的可选数字,每次确定一位数字后添加到结果中,并将list中的数字删除。

import java.util.*;
public class Solution {
    public String getPermutation(int n, int k) {
       StringBuffer sb = new StringBuffer();
       ArrayList<Integer> list = new ArrayList<Integer>(); 
       int [] mul = new int[n+1];
       mul[0] = 1;
       for(int i =1;i<=n;i++){
           mul[i]= mul[i-1]*i;
           list.add(i);
       }
       k--;
       boolean [] flag = new boolean[n+1]; 
       for(int i = n-1;i>=0;i--){
           int s = k/mul[i];
           int y = k%mul[i];
           sb.append(list.get(s));
           list.remove(list.get(s));
           k = y;
       }
        return sb.toString();
    }
}

另:

对于寻找第K个的问题:

1. 寻找无序数组中的第k小的数字(快排) ---剑指offer 40

import java.util.*;
  public class Solution {
      public int Partition(int [] input, int start, int end) {
        int flag = input[start];
        int first = start;
        start++;
        while(start<end){           
           while(input[end]>flag && start<=end)
               end--;
           while(input[start]<flag && start<=end)
               start++; 
            if(start<end){
                int temp =  input[end];
                input[end] = input[start];
                input[start] = temp;
            }
          }
       input[first] = input[end];
       input[end] =flag;
       return end;
    }

    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> result = new ArrayList<Integer>();
        if(input.length<k || input.length==0 || k==0)
            return result;
        int start = 0;
        int end = input.length-1;
        int index = Partition(input,start,end);
        while(index!=k-1){
            if(index<k-1){
                start = index+1;
                index =  Partition(input,start,end);
            }
             if(index>k-1){
                 end= index-1;
                 index =  Partition(input,start,end);
             }
        }
        for(int i =0;i<k;i++)
            result.add(input[i]);
        return result;
    }
  }

2. 寻找链表中的倒数第K个结点(快慢指针)---剑指offer 22

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/

public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(head==null || k==0)
            return null;
        ListNode listNode = head;
        for(int i = 1 ;i<k;i++){
            if(head.next!=null){
                head = head.next;
            }else
                return null;
        }
        while(head.next!=null){
            head = head.next;
            listNode = listNode.next;
        }
        return listNode;
    }
}

3. 寻找二叉搜索树的第K大结点 (中序遍历) -- 剑指offer 54

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    //中序遍历
    int index = 0;
    TreeNode KthNode(TreeNode pRoot, int k){
        TreeNode target  = null;
        if(pRoot!=null){
           if(pRoot.left!=null)
               target = KthNode(pRoot.left,k);
           if(target!=null)
               return target;
            //左子树中没有
            index++;
            if(index==k)
                return pRoot;
            target = KthNode(pRoot.right,k);
            if(target!=null)
                return target;
           }
        return null;
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值