Project_Euler-04 题解与优化
今天带来欧拉计划的第4题的程序分析与优化。
题目
如何判断回文数
int is_reverse(int n){
int x = n, sum = 0;
while (x){
sum = sum * 10 + x % 10;
x /= 10;
}
return sum == n;
}
如果为回文数,返回1,否则返回0.
暴力破解
两个循环依次遍历三位数:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
int is_reverse(int n){
int x = n, sum = 0;
while (x){
sum = sum * 10 + x % 10;
x /= 10;
}
return sum == n;
}
int main(){
int ans = 0;
for(int a = 100; a < 1000; a++){
for(int b = 100; b < 1000; b++){
if (is_reverse(a * b) && ans < a * b) ans = a * b;
}
}
printf("%d\n", ans);
return 0;
}
优化1
在内存循环暴力b时,重复了a的值,可以优化掉:
// 将100 改为 a
for(int b = a; b < 1000; b++){
if (is_reverse(a * b) && ans < a * b) ans = a * b;
}
优化2
内存循环中的if判断条件可以改为非值判断,减少计算次数:
for(int a = 100; a < 1000; a++){
for(int b = a; b < 1000; b++){
// 如果不是回文数继续判断下一个
if (!is_reverse(a * b))continue;
ans = a * b;
}
}
优化三,b的再调整
我们发现,ans的值除以a的值就是b的值,因此在一轮新的外层循环开始时,我们可以根据这个特性迅速找到有可能出现使得a * b
的结果大于当前ans值的b的值。
因为a是不断增长的,在a增长的过程中,肯定已经出现过由a * b出现的ans值,且这个值是不断变大的,当a开始新的一轮循环时,b不必从a开始,而是从 ans / a 开始,这样可以加快程序速度。
for(int a = 100; a < 1000; a++){
for(int b = (ans / a >= 100 ? ans / a + 1 : a); b < 1000; b++){
if (!is_reverse(a * b))continue;
ans = a * b;
printf("%d * %d = %d\n", a, b, ans);
}
}
最终代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
int is_reverse(int n){
int x = n, sum = 0;
while (x){
sum = sum * 10 + x % 10;
x /= 10;
}
return sum == n;
}
int main(){
int ans = 0;
for(int a = 100; a < 1000; a++){
for(int b = (ans / a >= 100 ? ans / a + 1 : a); b < 1000; b++){
if (!is_reverse(a * b))continue;
ans = a * b;
printf("%d * %d = %d\n", a, b, ans);
}
}
printf("%d\n", ans);
return 0;
}