zoukankan      html  css  js  c++  java
  • LeetCode 46. Permutations

    问题链接

    LeetCode 46. Permutations

    题目解析

    求解一个无重复元素序列的全排列。

    解题思路

    什么是全排列?理解一下题意,简单来讲,就是求解序列中元素的所有排列方法,一共有A(n, n)=n!种排列。可以采用递归、非递归、插空等方法求解。

    求解全排列参考链接:数组的全排列

    注意:本题中已经说明没有重复元素,对于有重复元素的情况,将在47. Permutations II在给大家说明。

    DFS求解全排列

    采用DFS,大致算法如下:

    • 任意取一个元素放在第一个位置,则有n种选择;
    • 再剩下的n-1个元素中再取一个元素放在第二个位置则有n-1种选择,此时可以看做对n-1个元素进行全排列;
    • 重复第二步,直到对最后一个元素进行全排列,即最后一个元素放在最后一个位置,全排列结束。

    此算法容易理解,但是需要耗费大量的栈空间。每次通过交换nums[index]和nums[i],代表当前选择了nums[i],然后进行下一次选择(DFS),参考代码如下:

    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            vector< vector<int> > res;
            DFS(nums, 0, res);
            return res;
        }
        void DFS(vector<int> &nums, int index, vector< vector<int> > &res) {
            if(index >= nums.size()) res.push_back(nums);
            for(int i = index; i < nums.size(); i++) {
                swap(nums[index], nums[i]);
                DFS(nums, index+1, res);
                swap(nums[index], nums[i]);
            }
        }
    };
    

    非递归求解全排列

    还记得LeetCode 31. Next Permutation吗?这道题中求的是序列的下一个序列,本题中其实就是求所有的“下一个序列”。试想一下,如果我不断地求下一个排列,最终我就可以得到所有的排列。

    为了避免重复,先将数组排个序,当数组完全逆序时退出循环。关于如何求解全排列,在LeetCode 31. Next Permutation也有具体的过程,这里就不多说了。

    直接借用库函数,投机取巧之法:

    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            vector< vector<int> > res;
            sort(nums.begin(), nums.end());
            do {
                res.push_back(nums);
            }while(next_permutation(nums.begin(), nums.end()));
            return res;
        }
    };
    

    具体实现全排列,参考代码如下:

    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            vector< vector<int> > res;
            sort(nums.begin(), nums.end());
            while(1) {
                res.push_back(nums);
                int n = nums.size(), i = n-2, j = n-1;
                while(i >= 0 && nums[i] >= nums[i+1]) i--;
                if(i >= 0) {
                    while(nums[i] >= nums[j]) j--;
                    swap(nums[i], nums[j]);
                }
                else break;
                reverse(nums.begin()+i+1, nums.end());
            }
            return res;
        }
    };
    

    插空法求解全排列

    参考大神的帖子:Permutations。了解到这么一种巧妙的方法。

    • 当n=1时,数组中只有一个数a1,其全排列只有一种,即为a1;
    • 当n=2时,数组中此时有a1a2,其全排列有两种,a1a2和a2a1,那么此时我们考虑和上面那种情况的关系,我们发现,其实就是在a1的前后两个位置分别加入了a2;
    • 当n=3时,数组中有a1a2a3,此时全排列有六种,分别为a1a2a3, a1a3a2, a2a1a3, a2a3a1, a3a1a2和 a3a2a1。那么根据上面的结论,实际上是在a1a2和a2a1的基础上在不同的位置上加入a3而得到的。_ a1 _ a2 _ : a3a1a2, a1a3a2, a1a2a3。_ a2 _ a1 _ : a3a2a1, a2a3a1, a2a1a3。

    以此类推,可以求得任意n元素的全排列。代码中每次递归取出原数组第一个元素并删除之,利用words保存当前所有排列,然后每个排列中在各个位置插入该元素,参考代码如下:

    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            if(nums.empty()) return vector< vector<int> >(1, vector<int>());
            
            vector< vector<int> > res;
            int first = nums[0];
            nums.erase(nums.begin());
            vector< vector<int> > words = permute(nums);
            for(auto &a : words) {
                for(int i = 0; i <= a.size(); ++i) {
                    a.insert(a.begin() + i, first);
                    res.push_back(a);
                    a.erase(a.begin() + i);
                }
            }   
            return res;
        }
    };
    

    相似题目

    LeetCode 31. Next Permutation


    LeetCode All in One题解汇总(持续更新中...)

    本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.


  • 相关阅读:
    Spring MVC异常处理
    Spring MVC静态资源放行
    SpringMVC 接受前端传递的数据
    Eclipse+Maven构建SpringMVC+log4j2
    Eclipse+Maven构建SpringMVC项目
    log4j2
    Centos7 / RHEL 7 双网卡绑定
    CentOS7安装vncserver
    CentOS7修改ssh端口
    Linux配置Oracle 11g自动启动
  • 原文地址:https://www.cnblogs.com/AlvinZH/p/8673493.html
Copyright © 2011-2022 走看看