数字分组求偶数和 | 青训营

169 阅读5分钟

问题描述

小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

解题思路

  • 要计算一个数字的各位之和是否为偶数,实际上只需要知道这个数字里有多少个奇数,如果奇数的个数为偶数个,数字和就为偶数
  • 可以这样理解:如果我们目前已知有a个偶数组合,b个奇数组合,在统计下一个’大‘数字时我们发现,这个数字里有c个偶数和d个奇数
  • 对于任意的偶数组合数,再增加任意一个偶数 组合数仍然为偶数
  • 对于任意的奇数组合数,再增加任意一个奇数 组合数就可以变为偶数
  • 那么 在增加了这一组数字之后偶数组合数的数量就变为a * c + b * d(偶数组合 * 偶数个数 + 奇数组合 * 奇数个数)
  • 反之 奇数组合数就为a * d + b * c(偶数组合 * 奇数个数 + 奇数组合 * 偶数个数)
  • 举个例子:我们已知有两个偶数组合 13 15 一个奇数组合 35 。发现下一组为1 3 4这三个数字,其中含有两个奇数和一个偶数。那么任意一个偶数组合增加任意一个偶数(也是该组唯一一个偶数)仍然是偶数,任意一个奇数组合增加任意一个奇数(1 3 都可以)即可变为偶数。偶数组合的数量从2变为2(偶数组合) * 1(偶数个数) + 1(奇数组合) * 2(奇数数量) = 4个(134 154 351 353)。

算法流程

1.初始化变量

1.evenNumber

该变量用来记录当前已经计算好的偶数组合数。 因为一个数也不选时,和为0为偶数,所以该变量应该初始化为1

2.oddNUmber

该变量用来记录当前已经计算好的奇数组合数

2.循环遍历每一个分组(数组中的每一个‘大’数字为一个分组)

1.循环遍历统计每一个分组中的奇数和偶数

这一步操作的目的是为了取出每一个分组中奇数和偶数的个数。我们分别选择用evenCount和oddCount两个变量来接收

1.遍历出数组中的每一个’大‘数字
2.遍历出每一个’大‘数字中的字符

这里我们选择使用strconv标准库中的Itoa函数将每一个大数字转换成一个字符串,再对字符串进行遍历,统计每一个分组中的奇数和偶数个数 注:这里不能直接使用int(digit)否则返回的是字符所对应的ASCII码,所以使用int(digit - '0')

3.动态规划维护变量

1.使用动态规划维护evenNumber和oddNumer

  1. newEvenNumber = evenNumber * evenCount + oddNumber * oddCount
  2. newOddNumber = evenNunber * oddCount + oddNumber + evenCount

2.对变量进行更新

更新evenNumber和oddNumber为newEvenNumber和NewOddNumber

代码展示

package main

import (
    "fmt"
    "strconv"
)

func solution(numbers []int) int {
    // 初始化两个变量 一个当前的偶数组合数 一个记录当前的奇数组合数
    evenNumber := 1 //用来记录当前的偶数组合数 一个数字也不选为0也为偶数 初始化为1
    oddNumber := 0  //用来记录当前的奇数组合数

    //循环遍历 统计每个分组(数组中的每一个数字为一个分组)中的奇数和偶数
    for _, group := range numbers {
       evenCount := 0 //统计偶数
       oddCount := 0  //统计奇数

       groupStr := strconv.Itoa(group)
       for _, digit := range groupStr {
          num := int(digit - '0') //修正数字转换 不然实际上返回的是ascii码
          if num%2 == 0 {
             evenCount++
          } else {
             oddCount++
          }
       }

       //如果当前组合数为偶数 再加上一个偶数仍然为偶数
       //如果当前组合数为奇数 再加上一个奇数即可变为偶数
       //所以新的偶数组合数应该为
       //当前偶数组合数 * 新增的偶数的个数 + 当前奇数组合数 * 新增的奇数的数量
       newEvenNumber := evenNumber*evenCount + oddNumber*oddCount
       //反之 新的奇数组合数应为
       //当前偶数组合数 * 新增的奇数的个数 + 当前奇数组合数 * 新增的偶数的数量
       newOddNum := evenNumber*oddCount + oddNumber*evenCount

       //更新当前的组合数
       evenNumber = newEvenNumber
       oddNumber = newOddNum
    }

    //返回偶数组合数
    return evenNumber
}

func main() {
    // You can add more test cases here
    fmt.Println(solution([]int{123, 456, 789}) == 14)
    fmt.Println(solution([]int{123456789}) == 4)
    fmt.Println(solution([]int{14329, 7568}) == 10)
}
```
```