全排列

全排列

1.无重复数字全排列

leetcode 46

题目:
Given a collection of distinct integers, return all possible permutations.

Example:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

思路:DFS深搜,每次从候选集中选择一个加入,创建visited数组存储该数字是否已被访问。

import java.util.ArrayList;
import java.util.List;

public class Solution {
    List<List<Integer>> list = new ArrayList<>();
    boolean[] visited;

    public List permute(int[] nums){
        if(nums.length == 0) return list;
        visited = new boolean[nums.length];
        List<Integer> temp = new ArrayList<>();
        helper(nums, temp);
        return list;
    }

    public void helper(int[] nums, List<Integer> temp){
        if(temp.size() == nums.length) {
            //new一个tmp用来加入list
            List<Integer> tmp = new ArrayList<>(temp);
            list.add(tmp);
            return;
        }
        for(int i = 0; i < nums.length; i++){
            if(visited[i])
                continue;
            temp.add(nums[i]);
            visited[i] = true;
            helper(nums, temp);
            temp.remove(temp.size()-1);
            visited[i] = false;
        }
    }
}

时间复杂度 O(N),空间复杂度 O(N)

2.有重复数字的全排列

leetcode 47

题目:

Given a collection of numbers that might contain duplicates, return all possible unique permutations.

Example:

Input: [1,1,2]
Output:
[
  [1,1,2],
  [1,2,1],
  [2,1,1]
]

思路:同DFS深搜,防止重复数字使结果重复要使同一个位置每个不同数字只选中1次。首先给数组排序,遇到连续相等数字跳过即可。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Solution {
    //DFS
    List<List<Integer>> list = new ArrayList<>();
    boolean[] visited;

    public List permute(int[] nums){
        if(nums.length == 0) return list;
        //数组排序
        Arrays.sort(nums);
        visited = new boolean[nums.length];
        List<Integer> temp = new ArrayList<>();
        helper(nums, temp);
        return list;
    }

    public void helper(int[] nums, List temp){
        if(temp.size() == nums.length){
            List<Integer> tmp = new ArrayList<>(temp);
            list.add(tmp);
            return;
        }
        for (int i = 0; i < nums.length; i++) {
            if(visited[i])
                continue;
            temp.add(nums[i]);
            visited[i] = true;
            helper(nums, temp);
            temp.remove(temp.size()-1);
            visited[i] = false;
            //相邻相同数字跳过
            while(i < nums.length-1 && nums[i] == nums[i+1])
                i++;
        }
    }
}

时间复杂度 O(N),空间复杂度 O(N)

3.全排列下一个

leetcode 31

题目:

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 and use only constant 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,31,3,2
3,2,11,2,3
1,1,51,5,1

思路:

假定一序列现在为<3, 5, 9, 7, 4>,其下一个全排列应为<3, 7, 4, 5, 9>。观察后三位<9, 7, 4>的逆序组合已经不能更大,因此要向前把5加入让序列变得更大,让比5大的最小数7与5互换位置,这时变为<3, 7, 9, 5, 4>可见后面仍然为逆序,要使得此序列在7以后为最小,故将逆序翻转即可。

import java.util.Arrays;

public class Solution {
    public void nextPermutation(int[] nums){
        if(nums.length <= 1) return;
        int i = nums.length - 2;
        //寻找逆序结束位置
        while(i >= 0 && nums[i] >= nums[i+1]){
            i--;
        }
        if(i >= 0){
            //寻找逆序中比i大的最小数与i互换位置
            int j = nums.length - 1;
            while(j > i && nums[j] <= nums[i]){
                j--;
            }
            swap(nums, i, j);
        }
        //若i<0说明整个数组为逆序,全部翻转输出最小值
        //逆序翻转
        reverse(nums, i+1, nums.length-1);
    }

    public void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public void reverse(int[] nums, int left, int right){
        while(left < right){
            swap(nums, left, right);
            left++;
            right--;
        }
    }

时间复杂度 O(N),空间复杂度 O(1)

4.全排列序列

leetcode 60

题目:

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 for n = 3:

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

Given n and k, return the kth permutation sequence.

Note:

  • Given n will be between 1 and 9 inclusive.
  • Given k will be between 1 and n! inclusive.

Example 1:

Input: n = 3, k = 3
Output: "213"

Example 2:

Input: n = 4, k = 9
Output: "2314"

思路:

假定现n=4, k=15, 输出应为 <3214>

将其分解成组:

第一组:1 + <234>的全排列

第二组:2 + <134>的全排列

第三组:3 + <124>的全排列

第四组:4 + <123>的全排列

因3个数的全排列个数为 3! = 6 个,利用取模的运算性质可以得到 k-1 / 6 = 2 mod 2 位于第三组。

将k重新赋值为余数2, 继续在 <124> 的全排列中找到下一个数字的过程即得到结果。

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public String getPermutation(int n, int k) {
        String ans = "";
        int mod = 1;
        //创建nums存储备选数字
        List<Integer> nums = new ArrayList<>();
        for(int i=1; i<=n; i++){
            mod *= i;
            nums.add(i);
        }
        //开始除法取模操作,先-1
        k--;
        for(int i=0; i<n; i++){
            mod = mod / (n-i);
            //在候选集中取出这一位的数字
            int turn = k / mod;
            k %= mod;
            ans += nums.get(turn);
            //将其从候选集中删除
            nums.remove(turn);
        }
        return ans;
    }
}

时间复杂度 O(N),空间复杂度 O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值