图解LeetCode:如何生成数字全排列

本文通过图解方式介绍如何生成数字全排列,以LeetCode第46题为例,讲解了从简单情况出发,逐步利用上一步计算结果生成全排列的策略,并提供了C++代码实现。
摘要由CSDN通过智能技术生成

化蛹为蝶,祝大家新年更上一层楼

这是LeetCode的第46号题目Permutations,也就是排列的意思,给定一个数字集,比如[1,2,3],让我们返回这些数字全排列。

全排列的概念我们都很熟悉,高中数学时没少受排列组合问题的折磨。

给定[1,2,3],相比你能轻松的计算出其全排列是:

123,132,213,132,312,321

你可能觉得这也太简单了吧,简直一眼就能看出答案,但是,这里给定的数字集就三个,如果给你一个[1,2,3,4,5,6,7,8,9]这样的数字集答案还明显吗,你能一下说出[1,2,3,4,5,6,7,8,9]这九个数字的全排列是什么吗?

聪明的你肯定意识到了这不那么容易的事情,显然,9个数字的全排列组合个数是9!,也就是有362880个排列组合,我们人类的大脑天生不适合处理这种机械式的问题,因为这非常繁琐,但是,这一切对于计算机来说不是问题。

那么你该怎么告诉计算机求出一个数字集的全排列呢?

我的思路

很显然,你需要某种策略,这种策略能明确的告诉计算机——也就是利用算法,每一步该如何处理直到计算出所有的全排列,那么这种策略是什么呢?

和之前一样,如果你一下想不出这个策略是什么的话,那么我们还是从最简单的情况下说起。

在最简单的情况下,数字集中只有一个数字,比如1,那么对于1来说全排列非常简单,就是1,这样我们解决了这个问题的第一步。

接下来我们来到了第二步,此时多了一个数字2,在第一步中我们已经知道了1的全排列是什么,那么我们该如何利用这一信息呢?

对于1来说形成的全排列就是:

1

此时再给你一个数字2,那么就会有两种可能:

  • 把2放到1的开头,从而形成21

  • 把2放到1的结尾,从而形成12

这个过程如图所示:

就这样我们处理完了第二个数字。

怎么样,现在你看明白这个策略了吧,也就是我们利用上一步的计算结果把当前的数字放到上一个全排列的数字串的各个位置上就可以了。

接下来我们来到了数字3,在上一步中我们得到了{12,21},在这一部中我们继续利用上一步的结果,我们首先来看上一步中的12,这时我们可以:

  • 把3放到12的开头,从而形成312;

  • 把3放到12的中间,从而形成132;

  • 把3放到12的结尾,从而形成123;

这个过程如图所示:

利用完了上一步中的12,接下来就是21,基于同样的道理,我们可以得到:321、231以及213,如图所示:

至此,我们计算出了{1,2,3}这个数据集的全排列,这些全排列就位于数的最后一层,如图所示:

现在你应该明白这个策略了吧,那就是不断利用上一步的计算结果形成加入当前数字的全排列,直到所有数字用完为止。

实际上上面这句话就是解决该问题的算法啦。

接下来我们就把上面这句中文翻译成C++代码。

代码实现

这里唯一需要说明的是,上面生成排列的方法涉及到字符串的拼接,因此使用list这种数据结构加快速度。

void getpermutation(vector<vector<int>> &r,
                    int n, vector<int>& nums, list<int>&l){
    if (n == nums.size()){
        vector<int> t;
        for (auto i : l)
            t.push_back(i);
        r.push_back(t);
        return;
    }
    l.push_front(nums[n]);
    getpermutation(r, n+1, nums, l);
    l.pop_front();
    l.push_back(nums[n]);
    getpermutation(r, n+1, nums, l);
    l.pop_back();
    for(int i=1;i<l.size();i++){
      auto it = l.begin();
      advance(it, i);
      l.insert(it,nums[n]);
      getpermutation(r, n+1, nums, l);
      it = l.begin();
      advance(it, i);
      l.erase(it);
    }
}
vector<vector<int>> permute(vector<int>& nums) {
    vector<vector<int>> r;
    int len = nums.size();
    if (len == 0)
        return r;
    vector<vector<int>> q;
    list<int>l = {nums[0]};
    getpermutation(r, 1,nums,l);
    return r;
}

总结

在这个问题中我们依然从最简单的情况着手,逐步增加问题难度,最终我们发现了解决问题的策略,最关键的值,这种清晰描述的策略不但程序员能明白,CPU也能理解,这样我们才有可能将我们人类理解的事情告诉计算机,这里再一次体现了如果作为程序员你不能清晰的描述你对一个问题的理解,那么想写出能正确运行的程序是不可能的

当然,如果真正的人工智能能够实现的话当我没说 :)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值