【小白题解笔记】4.数字分组求偶数和

237 阅读3分钟

题目链接

问题描述

小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)