Leetcode 60. 第k个排列

断断续续地刷了两个月的leetcode,今天终于刷到了70道了,纪念一下,分享一道题。60. 第k个排列

这题以我的思路肯定是直接用递归把所有结果遍历出来啊,事实上,我也是这么做的,但是最后以超时告终。实际上,我在我的递归中用上了正确的思想,只不过不够彻底而已。这题的重点应该是在剪枝上,与寻常的剪枝不同,这题用的不是设置条件,而是通过数学的方法直接剔去没有计算价值的情况,其实在我自己的代码中,我也考虑到了这个办法,但是我只对第一位进行了剪枝,后面的没有进行剪枝,所以还是很无奈地超时了。

所以后来参考了别人的代码,才发现我离正确的办法其实也只有一步之遥了,先放代码。

class Solution {
public:
	string getPermutation(int n, int k) {
		vector<int> factorial(n + 1, 1);   //统计不同位数的方法总数
		for (int i = 2; i <= n; ++i)
			factorial[i] = i * factorial[i - 1];

		vector<int> nums;
		for (int i = 1; i <= n; ++i)       //所有元素
			nums.emplace_back(i);

		string res("");
		for (int i = 1; i <= n; ++i)
		{
			/* 找开始点 */
			int index = k / factorial[n - i];
			/* 如果非整除,加一 */
			if (k % factorial[n - i] != 0)
				++index;                   //因为index此时仍有余数,所以还需要再往后延一位
			res += (nums[index - 1] + '0');      //加到结果里的数应从nums数组中移除
			nums.erase(nums.begin() + index - 1);
			k = k - ((index - 1) * factorial[n - i]);
		}

		return res;
	}
};

 理解的关键在于我们的目标是把所有明显不可能的情况全部筛去,最后剩下的就是正确的答案了,k表示的是第k大的数,需要从第一位开始逐步确定。

例如题目的例子,当n=4,k=9时,[1,2,3,4]一共四位数字,第一位如果不确定,那么就有4!个组合,但是如果第一位确定了,那就只有3!个组合了。此时,如果选择1,则没有筛去任何比k小的情况,如果选择2,则筛去了3!个情况,如果选择3,则筛去了2×3!个情况,如果选择4,则筛去了3×3!个情况,因为k=9,3!=6,3!<k<2×3!,因此应该选择2,直接筛去前面的3!个情况,此时k=k-3!=9-3!=3,筛去了多少个情况,k就要减多少,而这个时候,因为选择了数字2,那就要把这个数字从数组中删去,不然后面会出现数字的重复现象。第二位,第三位同理,直到迭代结束,时间复杂度为O(n),比直接递归的时间复杂度O(n!)的时间性能强太多,但是这个方法如果不了解的话,自己独立想出来的可能性不高,所以题还是要接着刷,多了解一些解题思路总是好的。(PS:当n大于10的时候会出bug,因为int类型的数组储存的元素大小是有上下限的,10!已经超过了int的上界了)

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值