题目来源:牛客,阿里巴巴编程题(2星),第2题
题目描述
题解
法一:很绕的想法
自认为本质是实现n进制的加法,但觉得很难实现,便借助了进制转换。
思想:以n=8,m=5为例。最小的输出(minn)肯定是“1 2 3 4 5”,最大的输出(maxn)是“4 5 6 7 8”。为了计数方便,借助了映射转换:
minn其实可以映射为“0 0 0 0 0”,而maxn可以映射为“3 3 3 3 3”,映射到4进制空间。
所以,输出其实可以看做5位(m位)4进制(n-m+1进制)数,即“a0 a1 a2 a3 a4”。
接下来要做的就是:
非十进制的递增遍历(加法),和,输出映射。
1)为了实现n-m+1进制的递增遍历,我借助了十进制。十进制的递增遍历很简单,+1即可,所以,我先将n-m+1进制的maxn转换成十进制,以此作为上限。而后,十进制每进行一次+1,就进行一次进制转换,得到对应的n-m+1进制数。
2)映射,通过nums实现。nums是m*(n-m+1)维,第一层包含m个list,即m位数,每位数(每个list)都有n-m+1个待选项,对应于n-m+1进制中的0~n-m。
以n=8,m=5为例,nums=[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7],[5,6,7,8]]。
具体代码如下:
def trans(x): #进制转换
global base,m
ans,tmpy = [],base
while x!=0:
y = x%base
# 注意,这里需要筛除0010这类数,以保证位数递增
if tmpy<y:
return []
else:
tmpy = y
x = x // base
ans.insert(0,y)
ans = [0]*(m-len(ans))+ans
return ans
def main():
global trans,base,m
n,m = map(int,input().split())
if n==m: # 特殊情况,这时无需进行进制转换
print(' '.join('%s' %id for id in range(1,m+1)))
return
# 以下三行用于构造nums
nums = [[i for i in range(1,n-m+2)]]
for i in range(m-1):
nums.append([j+1 for j in nums[-1]])
# 进制数
base = n-m+1
# base进制下的maxn转换为十进制下的maxn
maxn = int(str(n-m)*m,base)
# 开始遍历
for i in range(maxn+1):
ind = trans(i)
if len(ind)>0:
obj = [nums[j][ind[j]] for j in range(m)]
print(' '.join('%s' %id for id in obj))
return
if __name__=='__main__':
main()
方法是蠢了些,就这还花了1h才写出来,很难不emo。。。
法二:递归
就很像地图填色,递归的参数分别是:num为当前要填充的数字的最小值;obj为目标数组。
当obj长度为m时,就print,并return【无意间发现,这里不return也能过】
当obj还没填满时,开始逐一添加元素,每次添加的元素的起始值都比上一位大1【保证递增】
注意,这里统一限制填充的元素的最大值为n,这样做并不会出错,例如,虽然第一位数字的最大值应该是n-m+1,但由于该位还没到填充n-m+2时obj的长度就已经到m了,所以 for循环执行不到n-m+2。
def recursion(num,obj):
if len(obj)==m:
print(' '.join('%s'%id for id in obj))
for i in range(num,n+1):
obj.append(i)
recursion(i+1, obj)
obj.pop() # 和地图填色一样,当该值填充过后,需要pop,进行下一个
return
def main():
global n,m
n,m = map(int,input().split())
if m == n:
print(' '.join('%s'%id for id in range(1,m+1)))
return
recursion(1,[])
return
if __name__=='__main__':
main()
小总结
虽然法一很绕,但还是需要总结一下很多遗忘的知识:
- list转str:
''.join(list)
,但需要注意的是,如果list中的元素是int型,则需要用''.join('%s'%id for id in list)
- str转list:
list(str)
,但这种方法需要import string;某些情况下,用split也行 - 进制转换:
- int(str,base)可以将base进制的str转成十进制数
- bin(intNum) // 返回10进制的intNum 的2进制表示字符串
- oct(intNum) // 返回10进制的intNum 的8进制表示字符串
- hex(intNum) // 返回10进制的intNum 的16进制表示字符串
- ord(character) // 返回character 所对应的字符在unicode编码的顺序
- 十进制转n进制:
def trans(n,base):
#n为待转换的十进制数,base为进制,取值为2-16
## 由于十进制以上需要用到字母,所以用maplist做一个映射
maplist=[0,1,2,3,4,5,6,7,8,9,'A','b','C','D','E','F']
ans=[]
if n==0:
return 0
while n!=0:
y=n%x # 余数
n=n//x # 商
ans.insert(0,y) # 注意这里需要逆序插入
ans = [maplist[i] for i in ans]
return ''.join('%s'%id for id in ans)
每日一emo