|
发表于 2019-11-23 21:47:09
|
显示全部楼层
本帖最后由 Unicorn# 于 2019-11-24 00:11 编辑
来了
思路来自以前学排列组合时发现的逆序对规律
这种方法泛用性很强,用于:查找一个组合在全排列中的位置 和 用全排列中的位置找到一个组合
①题中的十进制可以换成任意进制,甚至其他数据类型
②这种思路还可以解决 比这个数小的中第二大的数、第三大的数,比这个数大的第1134个数....这样的问题
加了注释,因为这个思路实在难懂
- def solve(s):
- s = list(map(lambda x:int(x), str(s)))
- n = len(s)
- #units:单位数列units[i] = i!
- #代表i位元素的全排列数
- units = [1]
- for i in range(1, n):
- units.append(i*units[-1])
- units.reverse()
- #进制转换函数(正向)
- #由10进制数转换为 用逆序对数表示的新数(新索引):new_num
- #逆序对:在数列a中,每一对后项比前向小的数对组成一对逆序对
- #new_num 由每一位 与其后元素 能组成逆序对的对数组成
- #如 513 -> [5, 1, 3] -> [(5>1, 5>3), None, None] -> [2, 0, 0]
- #记 所有原有元素全排列 按有小到大顺序 组成集合为 M
- #new_num 点乘 units 就能得到原数s在M中的索引值
- def numeration_transformer(num):
- index = 0
- for i in range(n):
- for j in range(i+1, n):
- if num[i] > num[j]:
- index += units[i]
- return index
- new_index = numeration_transformer(s)
- if new_index == 0:
- return -1
-
- next_index = new_index - 1
- #这里不再需要原数s,把它修改为所有元素的顺序排列,以便查找
- s.sort()
- #进制转换函数(逆向)
- def anti_numeration_transformer(index):
- #首先找到index对应的new_num
- new_num = []
- for unit in units:
- new_num.append(index//unit)
- index %= unit
- num = [0]*n
- #由new_num还原num
- #观察到这样一个规律,num[i] = s[new_num[i]]
- #原理:从最高位起,除自己外所有元素都会排在自己后面,所以
- # 其他任何一个比它小的元素都一定会与它形成逆序对,也
- # 就是说,它的逆序对数刚好就对应它在有序元素集s中的索
- # 引。依次类推
- for i in range(n):
- num[i] = s[new_num[i]]
- del s[new_num[i]]
- return num
- res_s = anti_numeration_transformer(next_index)
- #如果0在首位,这个数不合要求。且在它之后的每一个数都会一定以0为首
- if res_s[0] == 0:
- return -1
-
- res = int(''.join(map(lambda x:str(x), res_s)))
- return res
复制代码
又找到一种思路,简单暴力但只局限于这道题
- def solve(s):
- s = list(map(lambda x:int(x), str(s)))
- n = len(s)
- p = -1
- for i in range(n-2, -1, -1):
- if s[i] > s[i+1]:
- p = i
- break
- if p == -1:
- return -1
-
- res = [0]*n
- res[:p] = s[:p]
- temp = s[p:]
- temp.sort()
- t = temp.index(s[p])
- head = temp.pop(t-1)
- temp.reverse()
- temp = [head] + temp
- res = s[:p] + temp
- return int(''.join(map(lambda x:str(x), res))) if res[0] != 0 else -1
复制代码 |
评分
-
查看全部评分
|