蚂蚁金服两道编程题
说明:当时考试时长60分钟,没有做出来这两道题;是事后自己写出来的,不知道是否可以全部AC。
最少出牌次数
来源:阿里巴巴-蚂蚁金服
思路就是,共有1 2 3 4 5 6 7 8 9 10 这十种牌,输入的是每种牌的个数,每种牌个数在0-4之间,可以出的牌型有:
- 单排
- 对子
- 顺子 12345 34567 等
- 连对 112233 445566等。
输出最少出牌次数。
思路:首先,每次出什么牌可以自己做出选择,也就是每次都可以从4种牌型中出牌(前提是存在该牌型),因此可以使用深度优先搜索的方法,主要内容如下:
"""
2020-03-20:考试的最后时间想到思路
2020-03-21:今天解决了这个问题。
"""
def output_a(nums, a=1):
"""返回出单牌或者对子之后所有可能的结果"""
seqs = []
for i in range(len(nums)):
if nums[i] >= a:
temp_nums = nums[:]
temp_nums[i] -= a
seqs.append(temp_nums)
return seqs
def sequence_index(nums, a, b):
"""输出所有可以出的顺子或者连对的下标"""
n = len(nums)
seqs_index = []
i = 0
j = i + b
while j <= n:
if min(nums[i:j]) >= a:
# 此时说明区间i到j中存在顺子
seqs_index.append(list(range(i, j)))
i += 1
j = i+b
return seqs_index
def output_sequence(nums, a=1, b=5): # 默认情况下是输出顺子
"""返回出顺子之后的所有可能的结果"""
seqs_index = sequence_index(nums, a, b)
seqs = [] # 保存所有可能的出牌之后的序列
for seq_index in seqs_index:
temp_nums = nums[:]
for index in seq_index:
temp_nums[index] -= a
seqs.append(temp_nums)
return seqs
nums = [1, 1, 1, 2, 2, 2, 2, 2, 1, 1]
# 只有一张牌的情况
if sum(nums) == 1:
print(1)
# print(len(output_a(nums, a=1)))
counts = []
def DFS(nums, count=0):
# 深度优先搜索来遍历4种情况。
global counts
if sum(nums) == 0:
counts.append(count)
for i in ['aabbcc', 'abcde', 'aa','a']:
# 为了减少出牌的次数,应该首先出顺子或者连对,这样可以最大化的减少出牌的次数。
# 如果不使用这种方法,程序可能会迭代比较深,耗时很久才可能得到答案
seqs = output_sequence(nums, a=1, b=5)
if seqs:
for seq in seqs:
count += 1
DFS(seq, count)
count -= 1
continue
seqs = output_sequence(nums, a=2, b=3)
if seqs:
for seq in seqs:
count += 1
DFS(seq, count)
count -= 1
continue
if i == 'a':
# 考虑所有出单牌之后,剩余牌的结果,然后遍历所有的牌型,深度搜索。
seqs = output_a(nums)
if i == 'aa':
seqs = output_a(nums, a=2)
if i == 'abcde':
seqs = output_sequence(nums, a=1, b=5)
if i == 'aabbcc':
seqs = output_sequence(nums, a=2, b=3)
if seqs:
for seq in seqs:
count += 1
DFS(seq, count)
count -= 1
DFS(nums, 0)
print(min(counts))
关键:首先,明确这是一个深度优先搜索可以解决的问题,每次出牌有4种选择;接着,为了减少递归的次数,应该明确知道,每次出牌前先判断是否存在连对或者顺子,这样可以很大程度减少出牌次数;最后回溯的时候应该注意count值减少1.
合并最长连续子序列
来源:阿里巴巴-蚂蚁金服
已知有n个非递减序列,比如aaa, bcd, zzz, bcfg, 将这n个序列合并在一起构建一个最长的非递减序列,比如aaa, bcfg, zzz这3个可以构成 aaabcfgzzz长度为10的序列。
# """
# 思路:也可以使用深度递归的方法,遍历所有的可能,然后寻找出最合适的结果。
# """
def longest_sequence(st_list):
flag = [False for i in range(len(st_list))]
lengths = []
sts = []
min_all = None
max_all = None
def DFS(st):
nonlocal min_all
nonlocal max_all
if set(st) not in sts: # 转化为set来避免重复
# 这里需要注意,添加的st应该是st内容的拷贝,后续st的变化不再影响这里面的值。
# 如果写成st而不是st[:],那么后面st发生变化的时候,sts内容也会发生变化
sts.append(set(st[:]))
lengths.append(len(''.join(st[:])))
for i in range(len(st_list)):
if flag[i] == False:
# 获取当前序列的最小、最大值
min_alpha = st_list[i][0]
max_alpha = st_list[i][-1]
# 如果全局还没有最小和最大值,就使用第一个元素的最小和最大值来初始化。
if not min_all and not max_all:
min_all = min_alpha
max_all = max_alpha
st.append(st_list[i])
flag[i] = True
DFS(st)
flag[i] = False
st.pop()
min_all = None
max_all = None
continue
if min_alpha >= max_all:
max_all = max_alpha
st.append(st_list[i])
flag[i] = True
DFS(st)
flag[i] = False
st.pop()
if st:
max_all = max(''.join(st))
elif max_alpha <= min_all:
min_all = min_alpha
st.append(st_list[i])
flag[i] = True
DFS(st)
flag[i] = False
st.pop()
DFS([])
return lengths, sts
st_list = ['aaa','bcd','zzz','bcfg']
lengths, sts = longest_sequence(st_list)
print(max(lengths))
print(sts) 需要注意两点:
- 每次增加或者修改元素进行下一步递归的时候,当回溯的时候也要对应的修改状态、st以及min_all和max_all.
- 添加到sts中的元素应该是st[:],也就是st的内容拷贝,否则,在之后的代码中如果st发生了变化,那么sts也对应的会产生改变,从而造成错误。
上海得物信息集团有限公司公司福利 1166人发布