【LeetCode】Permutations 解题报告

全排列问题。常用的排列生成算法有序数法、字典序法、换位法(Johnson(Johnson-Trotter)、轮转法以及Shift cursor cursor* (Gao & Wang)法。

【题目】

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

【暴力递归】

这是比较直观的思路。但是也有要注意的地方,刚开始写的时候,没有注意到list是共用的,所以前面得到的答案后面会改掉而导致错误。

public class Solution {
    List<List<Integer>> ret = new ArrayList<List<Integer>>();

    public List<List<Integer>> permute(int[] num) {
        int len = num.length;
        if (len == 0) return ret;

        List<Integer> list = new ArrayList<Integer>();
        run(list, num);
        return ret;
    }

    public void run(List<Integer> list, int[] num) {
        if (list.size() == num.length) {
            //注意这里要重新new一个list,要不然后面会被修改
            List<Integer> res = new ArrayList<Integer>();
            res.addAll(list);
            ret.add(res);
            return;
        }
        for (int i = 0; i < num.length; i++) {
            if (list.contains(num[i])) {
                continue;
            }
            list.add(num[i]);
            run(list, num);
            list.remove(list.indexOf(num[i])); //不要忘记这一步
        }
    }
}

【字典序法】

C++的STL库里面有nextPermutation()方法,其实现就是字典序法。

下图简单明了地介绍了字典序法

归纳一下为:

例如,1234的全排列如下:

【代码实现】

由于Java的list传参传的是地址,所以每次添加时都要记得重新new一个新的list添加到结果集中,否则添加到结果集中的原list会被后面的操作改变。

public class Solution {
    public List<List<Integer>> permute(int[] num) {
        List<List<Integer>> ret = new ArrayList<List<Integer>>();

        int len = num.length;
        if (len == 0) return ret;

        Arrays.sort(num); //字典序法需先对数组升序排序

        //数组转为list
        List<Integer> list0 = new ArrayList<Integer>();
        for (int i = 0; i < len; i++) {
            list0.add(num[i]);
        }

        //把原始数组对应的list添加到结果中,不能直接添加list0,因为后面它会一直变化
        List<Integer> ll = new ArrayList<Integer>();
        ll.addAll(list0);
        ret.add(ll);

        //逐次找下一个排列
        for (int i = 1; i < factorial(len); i++) {
        	ret.add(nextPermutation(list0));
        }
        return ret;
    }

    /***字典序法生成下一个排列***/
    public List<Integer> nextPermutation(List<Integer> num) {
        //找到最后一个正序
        int i = num.size()-1;
        while(i > 0 && num.get(i-1) >= num.get(i)){
            i--;
        }

        //找到最后一个比num[i-1]大的数
        int j = i;
        while(j < num.size() && num.get(j) > num.get(i-1)) {
            j++;
        }

        //交换num[i-1]和num[j-1]
        int tmp = num.get(i - 1);
        num.set(i - 1, num.get(j - 1));
        num.set(j - 1, tmp);

        //反转i以后的数
        reverse(num, i, num.size()-1);

        List<Integer> ret = new ArrayList<Integer>();
        ret.addAll(num);
        return ret;
    }

    public void reverse(List<Integer> list, int begin, int end) {
        for(int i = begin, j = end; i < j; i++) {
            list.add(i, list.remove(j));
        }
    }

    public int factorial(int n) {
        return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
    }
}

上面的实现需要先对原数组升序排序,下面对nextPermutation(List<Integer> num)改进后就不用对num排序了。

    /***字典序法生成下一个排列***/
    public List<Integer> nextPermutation(List<Integer> num) {
        //找到最后一个正序
        int i = num.size()-1;
        while(i > 0 && num.get(i-1) >= num.get(i)){
            i--;
        }

        //有了这个判断就不用num最初是按升序排好的了
        if (i == 0) {
            reverse(num, 0, num.size()-1);
            List<Integer> ret = new ArrayList<Integer>();
            ret.addAll(num);
            return ret;
        }

        //找到最后一个比num[i-1]大的数
        int j = i;
        while(j < num.size() && num.get(j) > num.get(i-1)) {
            j++;
        }

        //交换num[i-1]和num[j-1]
        int tmp = num.get(i - 1);
        num.set(i - 1, num.get(j - 1));
        num.set(j - 1, tmp);

        //反转i以后的数
        reverse(num, i, num.size()-1);

        List<Integer> ret = new ArrayList<Integer>();
        ret.addAll(num);
        return ret;
    }

欢迎高人对上述代码继续优化!

时间: 2024-08-05 04:48:23

【LeetCode】Permutations 解题报告的相关文章

LeetCode: Permutations 解题报告

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]. SOLUTION 1: 经典的递归回溯题目,一次ACCEPT. 请也参考上一个题目LeetCode: Combination

[LeetCode]3Sum,解题报告

题目 Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero. Note: Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) The so

[LeetCode]Candy, 解题报告

前言 回学校写论文差不多快二周的时间了,总结一句话,在学校真舒服.花了7天时间搞定了毕业论文初稿(之所以这么快肯定跟我这三年的工作量相关了),不过今天导师批复第二章还是需要修改.此外,最近迷上打羽毛球,确实很爽,运动量仅此于篮球,可以场地有限,哎,且打且珍惜吧. 题目 There are N children standing in a line. Each child is assigned a rating value. You are giving candies to these chi

Single Number | LeetCode OJ 解题报告

题目网址:https://oj.leetcode.com/problems/single-number/ 题目描述: Given an array of integers, every element appears twice except for one. Find that single one. Note: Your algorithm should have a linear runtime complexity. Could you implement it without usin

Add Two Numbers | LeetCode OJ 解题报告

题目网址:https://oj.leetcode.com/problems/add-two-numbers/ 题目描述: You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return i

Two Sum | LeetCode OJ 解题报告

题目网址:https://oj.leetcode.com/problems/two-sum/ 题目描述: Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, whe

LeetCode: isSameTree1 解题报告

isSameTree1 Given two binary trees, write a function to check if they are equal or not. Two binary trees are considered equal if they are structurally identical and the nodes have the same value. SOLUTION 1 & SOLUTION 2: 以下是递归及非递归解法: 1. 递归解法就是判断当前节点是

LeetCode: Subsets 解题报告

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

LeetCode: solveSudoku 解题报告

Sudoku SolverWrite a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by the character '.'. You may assume that there will be only one unique solution. SOLUTION: ref: http://blog.csdn.net/fightforyourdream/articl