算法Week08.04 - LeetCode 46. Permutations

题意大意

给定一组互不相同的数字,返回所有可能的排列。

难度

Medium

个人题解

方法一

stl 算法库已经提供了排列相关的算法next_permutation 以及prev_permutation ,所以首先想到的方法是使用next_permutation 试试规模如何。

next_permutation 从当前排列产生下一个排列需要如下4步:

  1. 从后往前,找到第一个连续的顺序对 (a, b);

  2. 从后往前,找到第一个比 a 大的数 c;

  3. 交换 a 和 c;

  4. 反转介于 a 和 c 之间的数。

时间复杂度为 O(n)。

全排列一共有 n! 种,产生每种排列的复杂度为 O(n),因而总时间复杂度为 O(n*n!)。需要特别注意的是,next_permutation 是按顺序进行的,所以只有初始状态最小才可能产生所有的排列;因而需要先对序列进行排序或者综合使用 next_permutation 以及 prev_permutation

方法二

使用深度优先搜索,开一个与序列元素一一对应的布尔数组unsel[] ,如果序列中某一个元素已经被选择过了,那么对应的布尔值为false ,否则为true

那么对于一个长度为n 的序列,其搜索树每一层的节点数分别为:1、n、n * (n - 1)、n * (n - 1) * (n - 2)、...、n!、n!,边数分别为:n、n * (n - 1)、n * (n - 1) * (n - 2)、...、n!、n!,每一个叶子节点导出一种排列。在布尔数组的基础上建立链表,将所有值为true 的节点连接起来,那么从一个节点转移到下一个节点的复杂度为 O(1),因而时间复杂度为 (1 + 2 * (n + n * (n - 1) + ... + n! + n!)) * O(1) = (1 + 2e * n!) * O(1) = O(n!)。

源代码

方法一

 
 
 
#include <algorithm>
class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        std::sort(nums.begin(), nums.end());
        vector< vector<int> > out;
        out.push_back(nums);
        while (std::next_permutation(nums.begin(), nums.end())) {
            out.push_back(nums);
        }
        return out;
    }
};

方法二

 
 
 
class Solution {
public:
    struct MyBool {
        bool val;
        short idx;
        MyBool * next;
    };
    
    vector< vector<int> > permute(vector<int>& nums) {
        vector< vector<int> > out;
        if (!nums.size()) {
            out.push_back(nums);
            return out;
        }
        
        vector<int> ele;
        MyBool * un_sel = new MyBool[nums.size()];
        for (int i = 0; i < nums.size(); i++) {
            un_sel[i].val = true;
            un_sel[i].idx = i;
            un_sel[i].next = un_sel + i + 1;
        }
        un_sel[nums.size() - 1].next = NULL;
        MyBool * head = un_sel;
        dfs(nums, ele, out, un_sel, head);
        return out;
    }
    static void dfs(const vector<int>& nums, vector<int>& ele, vector< vector<int> > &out, MyBool * un_sel, MyBool * head) {
        if (!head) out.push_back(ele);
        else {
            MyBool * cur = head;
            MyBool * prev = NULL;
            cur->val = false;
            ele.push_back(nums[cur->idx]);
            dfs(nums, ele, out, un_sel, cur->next);
            ele.pop_back();
            cur->val = true;
            prev = cur;
            cur = cur->next;
            
            while (cur) {
                prev->next = cur->next;
                cur->val = false;
                
                ele.push_back(nums[cur->idx]);
                dfs(nums, ele, out, un_sel, head);
                ele.pop_back();
                cur->val = true;
                prev->next = cur;
                prev = cur;
                cur = cur->next;
            }
        }
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值