最近从《编程谜题》上面看到一道很有意思的题目,这里摘录一下大意:
题目概述:
有n组数据,每组数据给出m和m个数(每个数之间用空格隔开),这m个数组成一个m位数,请你求出下一个比当前m位数大的排列组成的m位数
若是没有,请输出-1
输入样例:
2
4
1 2 3 4
3
3 2 1
输出样例:
1243
-1
还是那句话:看到这里请自行思考10分钟左右。
解法
1.暴力
思路:求出这m个数的全排列,然后找到给定的数据,下一个就是答案了
这里设定一个标记变量flag,如果都没有找到就输出-1。
时间复杂度:省去常数复杂度 O(n!)
代码这里就不贴了,想写的童鞋可以自己练练手
好像还可以有一个递归检索法(我自己发明的【笑】)
就是对于每一位数都可以通过递归找到全排列中的位置
2.“数学解法”
这里还是一个所谓的数学解法
这里比较玄学,我尽量讲明白吧。
先来看解题步骤,最后再解释:
拿序列3 4 2 1举例子
1.从右往左找到第一个反递增的数a,将这个数所在的位置(下标)记为pos
在这个例子里头,a=3,pos=1
2.从右到左找到比a大的第一个数b
在这里,b=4
3.交换a和b
例子中的序列就变成了:4 3 2 1
4.将pos右边的所有数都翻转(最后一位变为第一位,倒数第二位变为第二位……)
例子中的序列就变成了4 1 2 3
此时的序列就是所求的解
怎么样,玄学吧【笑】
看到这里,还是请自行思考5~10分钟
一步一步理解(也可以画图,也可以论证,理解就行)
我的理解
我理解了蛮久,大概也是10min这样才看懂。
第一步,找到a和pos
我们反过来理解,a是右到左反递增数,那么说,从右到左在pos之前的一直都是保持递增的序列
ps:如果没找到就直接输出-1,自己想想为什么
第二步,找到b
这一步还是要连着第三步一起讲
第三步:交换a和b
这一步就是使新得到的序列比原序列大,连第二步来说,就是让新的到的序列在其他比原序列大的序列中尽可能小,因为b是第一个比a大的数
第四步:pos后面的翻转
因为pos后的都是递增,翻转后就也是递增,不过方向不一样,翻转后的递增是使b为关键的序列最小
我尽力解释清楚了
如果不相信诸位可以自己再试试
代码太简单也不贴了