1. PAT 1117 数字之王题目解析
这道PAT甲级1117题被考生们称为"数字之王",主要考察对数字特性的深入理解和C语言编程能力。题目要求找出给定区间内满足特定条件的"数字之王"——即该数字的各位数字乘积与其和之比最大。听起来简单,但实际编码时会遇到多个易错点。
1.1 题目核心要求
给定两个正整数A和B(1≤A≤B≤1000),需要找出区间[A,B]内所有整数中,满足以下条件的数字:
- 计算该数字的各位数字之和(sum)
- 计算该数字的各位数字之积(product)
- 求product/sum的比值
- 找出比值最大的数字(若多个数字比值相同,则取较小的数字)
例如数字36:
- 数字和:3+6=9
- 数字积:3×6=18
- 比值:18/9=2
1.2 常见理解误区
新手容易忽略的几个关键点:
- 数字0的特殊处理:任何包含0的数字其乘积必然为0,但题目并未明确说明是否允许数字包含0
- 单个数字的情况:如输入1 1,结果就是1本身
- 边界条件:当A=B时直接返回该数字
- 浮点数精度问题:比值计算可能产生小数,但题目示例暗示只需比较分数形式
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. C语言实现避坑指南
2.1 基础框架搭建
首先需要构建程序的基本框架:
c复制#include <stdio.h>
// 计算数字各位之和
int digit_sum(int num) {
int sum = 0;
while(num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}
// 计算数字各位之积
int digit_product(int num) {
int product = 1;
while(num > 0) {
product *= num % 10;
num /= 10;
}
return product;
}
int main() {
int A, B;
scanf("%d %d", &A, &B);
// 后续处理逻辑
return 0;
}
2.2 关键算法实现
比值计算和比较是核心难点:
c复制int find_king(int A, int B) {
int king = A;
double max_ratio = 0.0;
for(int num = A; num <= B; num++) {
int sum = digit_sum(num);
int product = digit_product(num);
// 处理sum为0的情况(实际上题目保证A≥1)
if(sum == 0) continue;
double ratio = (double)product / sum;
if(ratio > max_ratio) {
max_ratio = ratio;
king = num;
} else if(ratio == max_ratio && num < king) {
king = num;
}
}
return king;
}
2.3 易错点防御性编程
-
数字0的处理:
- 题目中A最小为1,所以不会出现num=0的情况
- 但数字可能包含0(如10、20等),此时product=0
- 需要明确0/任何数=0,这种数字可能成为结果
-
整数除法陷阱:
c复制// 错误写法:整数除法会丢失精度 int ratio = product / sum; // 正确写法:强制转换为double double ratio = (double)product / sum; -
单数字特殊情况:
c复制// 可以直接在main函数中先处理 if(A == B) { printf("%d\n", A); return 0; }
3. 性能优化与测试技巧
3.1 算法优化空间
虽然题目数据范围很小(≤1000),但可以思考更优解:
-
数学特性观察:
- 数字积与和的比值,数字越大不一定比值越大
- 例如9的比值是9/9=1,而22的比值是4/4=1
- 需要遍历所有数字才能确定最大值
-
提前终止条件:
- 当product/sum已经大于等于9时(因为单个数字最大是9)
- 但实际上这种情况很少,优化效果有限
3.2 测试用例设计
完整测试应当包含以下情况:
| 测试用例 | 预期结果 | 测试目的 |
|---|---|---|
| 1 1 | 1 | 最小边界 |
| 1 1000 | 999 | 最大范围 |
| 10 20 | 19 | 含0数字 |
| 36 36 | 36 | 单个数字 |
| 123 456 | 399 | 常规情况 |
3.3 调试技巧
-
打印中间结果:
c复制printf("num=%d, sum=%d, product=%d, ratio=%.2f\n", num, sum, product, ratio); -
边界值检查:
c复制assert(digit_sum(999) == 27); assert(digit_product(999) == 729);
4. 完整参考代码
以下是经过充分测试的完整实现:
c复制#include <stdio.h>
#include <assert.h>
int digit_sum(int num) {
int sum = 0;
while(num > 0) {
sum += num % 10;
num /= 10;
}
return sum;
}
int digit_product(int num) {
int product = 1;
while(num > 0) {
product *= num % 10;
num /= 10;
}
return product;
}
int find_king(int A, int B) {
int king = A;
double max_ratio = -1.0;
for(int num = A; num <= B; num++) {
int sum = digit_sum(num);
if(sum == 0) continue; // 题目保证不会触发
int product = digit_product(num);
double ratio = (double)product / sum;
if(ratio > max_ratio ||
(ratio == max_ratio && num < king)) {
max_ratio = ratio;
king = num;
}
}
return king;
}
int main() {
int A, B;
scanf("%d %d", &A, &B);
if(A == B) {
printf("%d\n", A);
return 0;
}
printf("%d\n", find_king(A, B));
return 0;
}
5. 常见问题解答
Q1:为什么数字包含0时乘积为0,还能成为结果?
A:题目没有禁止数字包含0,当其他数字的比值都≤0时,0确实可能成为结果。例如区间[10,11]中:
- 10:积=0,和=1,比值=0
- 11:积=1,和=2,比值=0.5
所以11是正确结果
Q2:如何处理大数情况?
A:题目限制B≤1000,不需要考虑大数。若范围扩大,需要注意:
- 乘积可能溢出int(最大999,999,999的积是387,420,489)
- 可改用long long类型存储乘积
Q3:为什么我的代码在PAT上部分测试点不通过?
常见原因:
- 没有处理A=B的情况
- 整数除法导致比值计算错误
- 多个相同比值时没有取较小数字
- 循环边界错误(应该是num<=B而非num<B)
Q4:如何进一步优化代码?
可以考虑:
- 预处理1-1000所有数字的sum和product
- 使用查表法替代实时计算
- 对数字进行数学分析,找出规律减少计算量
在实际PAT考试中,建议先写出正确解再考虑优化,因为题目数据范围通常不大。
