1. 火柴数字问题解析
这个问题看似简单,却蕴含着几个有趣的算法挑战。我们需要用不超过n根火柴摆出最大的能被m整除的正整数。每个数字0-9都有对应的火柴棒数量,具体如下:
- 0:6根
- 1:2根
- 2:5根
- 3:5根
- 4:4根
- 5:5根
- 6:6根
- 7:3根
- 8:7根
- 9:6根
从火柴消耗来看,数字1只需要2根,是最经济的;数字7需要3根,次之。因此,要构造最大的数字,我们应该尽可能多地使用数字1,在火柴根数允许的情况下,适当使用数字7来增加数值大小。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路详解
2.1 数字构造策略
要构造最大的数字,我们需要考虑以下几点:
- 数字位数越多,数值越大(在相同火柴消耗下)
- 数字1消耗的火柴最少(2根),可以构造最多位数
- 当火柴根数为奇数时,可以用一个7(3根)替换一个1(2根),这样总消耗多1根,但数值会显著增大
具体构造方法:
- 如果n是偶数:全部用1,构造n/2个1
- 如果n是奇数:用一个7,剩下的用(n-3)/2个1
例如:
- n=6:111(3个1,6根)
- n=5:71(1个7和1个1,共5根)
2.2 倍数检查优化
构造出最大数字后,我们需要检查它是否能被m整除。如果不能,我们需要寻找下一个较小的数字。直接递减检查效率太低,我们可以采用以下优化:
- 从最大数字开始,每次减去m,检查火柴消耗是否符合要求
- 利用数字的火柴消耗特性,快速跳过不可能的数字
对于大数处理(当n=100时,数字可能有50位),我们需要特殊处理:
- 使用字符串表示大数
- 实现大数的模运算
3. 代码实现与解析
3.1 火柴消耗计算函数
cpp复制int countMatches(int num) {
int matches[] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
int total = 0;
if (num == 0) return matches[0];
while (num > 0) {
total += matches[num % 10];
num /= 10;
}
return total;
}
这个函数
