题目链接 易
问题描述
小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。
numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。
例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369。
测试样例
样例1:
输入:
numbers = [123, 456, 789]
输出:14
样例2:
输入:
numbers = [123456789]
输出:4
样例3:
输入:
numbers = [14329, 7568]
输出:10
直观的方法就是把每个情况都遍历一遍,但这不现实,肯定耗时很久。
这题可以想到,统计numbers每个数组项的奇偶数量,然后想法子用这两数量直接弄出结果。这方法是什么,很关键。因为这就是个排列组合的问题,要考虑哪些组合能得到偶数。但头疼的是没给numbers的项数。
要是给了项数就可以直接算所有可能性了:第一项取奇数,第二项取偶数,第三···每个组合判断也很简单,用异或。
之前一直对动态规划不熟悉,只知道列出状态方程和终止情况,不知道具体啥情况用,没深刻理解。经过ai提醒,知道这题可以用。原来碰到这种有各种组合不好统计总数量的情况很合适动态规划。
怎么用:不要聚焦在宏观数量,聚焦在每一步之间的推进,也就是弄出状态方程。终止情况很简单,就是把数组遍历完,得到最终偶数和数量。
这里用一个数组f=[0,0],表示目前和是偶数的数量f[0]、和是奇数的数量f[1],当然我们最后只要f[0]。跟着numbers遍历一遍,就能得到最后的f[0]了。每一步之间的推进,就是更新f[0],f[1],也就是统计 加上本项之后的f[0]和f[1]。
本项有什么东西吗?有,看本项每一位是奇数还是偶数,得到偶数的个数和奇数的个数,用c[0]和c[1]表示。状态方程(也就是怎么更新f[0],f[1])是什么呢?经ai提醒,偶数和f[0]的是f[0]*c[0]+f[1]*c[1]。奇数和f[1]的是f[0]*c[1]+f[1]*c[0]。挺好理解的,偶数只有偶偶奇奇,奇数只有奇偶偶奇。下面是偶偶的解释。
f[0]*c[0]:前面和是偶数,本项也是偶数。很容易理解,注意是有序的,我一开始以为是乱序的,可以把本项往前面插。要真是乱序得再乘个f[0]
然后就没什么了,最后返回个f[0]就结束。
完整代码:
#动态规划
def solution(numbers):
# Please write your code here
f=[1,0]
for ia in numbers:
c=[0,0]
for ch in str(ia):
c[int(ch)%2]+=1
f=[f[0]*c[0]+f[1]*c[1],f[0]*c[1]+f[1]*c[0]]
return f[0]
if __name__ == "__main__":
# You can add more test cases here
print(solution([123, 456, 789]) == 14)
print(solution([123456789]) == 4)
print(solution([14329, 7568]) == 10)