60.Permutation Sequence 序列排序

这题不好理解,参考[1]mark一下。
分析:
这道题是让求出n个数字的第k个排列组合,由于其特殊性,我们不用将所有的排列组合的情况都求出来,然后返回其第k个,我们可以只求出第k个排列组合即可,那么难点就在于如何知道数字的排列顺序,可参见网友喜刷刷的博客,首先我们要知道当n = 3时,其排列组合共有3! = 6种,当n = 4时,其排列组合共有4! = 24种,我们就以n = 4, k = 17的情况来分析,所有排列组合情况如下:
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2

2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1

3 1 2 4
3 1 4 2
3 2 1 4
3 2 4 1
3 4 1 2 <— k = 17
3 4 2 1

4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1

我们可以发现,每一位上1,2,3,4分别都出现了6次,当最高位上的数字确定了,第二高位每个数字都出现了2次,当第二高位也确定了,第三高位上的数字都只出现了1次,当第三高位确定了,那么第四高位上的数字也只能出现一次,下面我们来看k = 17这种情况的每位数字如何确定,由于k = 17是转化为数组下标为16:

最高位可取1,2,3,4中的一个,每个数字出现3!= 6次,所以k = 16的第一位数字的下标为16 / 6 = 2,在 “1234” 中即3被取出。这里我们的k是要求的坐标为k的全排列序列,我们定义 k ′ k^{&#x27;} k 为当最高位确定后,要求的全排序列在新范围中的位置,同理, k ′ ′ k^{&#x27;&#x27;} k为当第二高为确定后,所要求的全排列序列在新范围中的位置,以此类推,下面来具体看看:

第二位此时从1,2,4中取一个,k = 16,则此时的 k ′ k^{&#x27;} k= 16 % (3!) = 4,如下所示,而剩下的每个数字出现2!= 2次,所以第二数字的下标为4 / 2 = 2,在 “124” 中即4被取出。

3124
3142
3214
3241
3412 <— k ′ k^{&#x27;} k= 4
3421

第三位此时从1,2中去一个,k’ = 4,则此时的 k ′ ′ k^{&#x27;&#x27;} k = 4 % (2!) = 0,如下所示,而剩下的每个数字出现1!= 1次,所以第三个数字的下标为 0 / 1 = 0,在 “12” 中即1被取出。

3412 <— k ′ ′ k^{&#x27;&#x27;} k= 0
3421

第四位是从2中取一个, k ′ ′ k^{&#x27;&#x27;} k = 0,则此时的 k ′ ′ ′ k^{&#x27;&#x27;&#x27;} k= 0 % (1!) = 0,如下所示,而剩下的每个数字出现0!= 1次,所以第四个数字的下标为0 / 1= 0,在 “2” 中即2被取出。

3412 <— k ′ ′ ′ k^{&#x27;&#x27;&#x27;} k = 0

那么我们就可以找出规律了
a 1 = k / ( n − 1 ) ! a_{1} = k / (n - 1)! a1=k/(n1)!
k 1 = k {{k}_{1}}={{k}} k1=k% ( n − 1 ) ! (n-1)! (n1)!

a 2 = k 1 / ( n − 2 ) ! a_{2} = k_{1} / (n - 2)! a2=k1/(n2)!
k 2 = k 1 {{k}_{2}}={{k}_{1}} k2=k1% ( n − 2 ) ! (n-2)! (n2)!

a n − 1 = k n − 2 / ( 1 ) ! a_{n-1} = k_{n-2} / (1)! an1=kn2/(1)!
k n − 1 = k n − 2 {{k}_{n-1}} = {{k}_{n-2}} kn1=kn2% 1 ! 1! 1!

a n = k n − 1 / ( 0 ) ! a_{n} = k_{n-1} / (0)! an=kn1/(0)!
k n = k n − 1 {{k}_{n}} = {{k}_{n-1}} kn=kn1% 0 ! 0! 0!

class Solution {
  public:
	  //please write the logic of your code in English.
	  //you should learn Chinese then
	  string getPermutation(int n, int k) {
		  string res;
		  vector<int>factor(n,1);
		  vector<char>num(n,1);
		  for (int i = 1; i < n; i++)
			  factor[i] = factor[i - 1] * i;//save n-1!

		  for (int i = 0; i < n; i++)
			  num[i] =char( i+1 + '0');//n numbers

		  k--;//from 0 start
		  for (int i = n; i >= 1; i--)
		  {
			  int j = k / factor[i - 1];
			  k %= factor[i - 1];//next k_th sequence
			  res.push_back(num[j]);
			  num.erase(num.begin() + j);
		  }
		  return res;
	  }
  };
 static const auto kSpeedUp = []() {
	 std::ios::sync_with_stdio(false);
	 std::cin.tie(nullptr);
	 return nullptr;
 }();

[1]https://www.cnblogs.com/grandyang/p/4358678.html
[2]https://bangbingsyb.blogspot.com/2014/11/leetcode-permutation-sequence.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值