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


  • 相关阅读:
    part11-1 Python图形界面编程(Python GUI库介绍、Tkinter 组件介绍、布局管理器、事件处理)
    part10-3 Python常见模块(正则表达式)
    Cyclic Nacklace HDU
    模拟题 Right turn SCU
    状态DP Doing Homework HDU
    Dp Milking Time POJ
    区间DP Treats for the Cows POJ
    DP Help Jimmy POJ
    Dales and Hills Gym
    Kids and Prizes Gym
  • 原文地址:https://www.cnblogs.com/AlvinZH/p/8673493.html
Copyright © 2011-2022 走看看