花朵数求解方法(java)
题目
一个N位的十进制正整数,如果它的每个位上的数字的N次方的和等于这个数本身,则称其为花朵数。
例如:
当N=3时,153就满足条件,因为 1^3 + 5^3 + 3^3 = 153,这样的数字也被称为水仙花数(其中,“^”表示乘方,5^3表示5的3次方,也就是立方)。
当N=4时,1634满足条件,因为 1^4 + 6^4 + 3^4 + 4^4 = 1634。
当N=5时,92727满足条件。
实际上,对N的每个取值,可能有多个数字满足条件。
程序的任务是:求N=21时,所有满足条件的花朵数。注意:这个整数有21位,它的各个位数字的21次方之和正好等于这个数本身。
解题思路
要求一个数各个位置上的21次方和等于其本身,用暴力破解即遍历的方法肯定是行不通的,数字太大。
我们可以先不考虑数的顺序,只考虑0-9各个数字出现的次数,最多一个数出现21次,再将其各种出现的次数的情况进行验证,即求出21次方和,先排除不是21位数的情况,再排除相加后各个数字出现次数和相加前出现次数不一致的情况
** 上代码 **
package demo;
public class waterflower {
// 花朵数,统计每个数出现的次数,并保到一个数组中
// 3次方的花朵数
public static int[] base = new int[10];
public static int cal_3(int a) {
int s = 1;
for (int i = 0; i < 3; i++) {
s = s * a;
}
return s;
}
public static void test(int[] a) {
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum = sum + a[i] * base[i];
}
// java中将int型转化为String类型的方法:
// 1 String.valueof(int);
// 2 Integer.toString(int);
String s = String.valueOf(sum);
// System.out.println("看看:");
// for (int i = 0; i < a.length; i++) {
// System.out.print(a[i]);
// }
// System.out.println();
if (s.length() != 3) {
return;
}
int[] b = new int[10];
for (int i = 0; i < 3; i++) {
b[s.charAt(i) - '0']++;
}
for (int i = 0; i < 10; i++) {
if (b[i] != a[i]) {
return;
}
}
System.out.println(sum);
}
public static void find(int[] a, int k, int sum) {
if (sum == 0) {
test(a);
return;
}
if (k == a.length - 1) {
a[k] = sum;
test(a);
a[k] = 0;// 千万要记得回溯,否则代码顺序交换了可能会影响最终的结果
return;
}
for (int i = 0; i <= sum; i++) {
a[k] = i;
find(a, k + 1, sum - i);
a[k] = 0;
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
base[i] = cal_3(i);
}
int[] a = new int[10];
find(a, 0, 3);
}
}
注意find方法里面的test后要使a[k]=0,即进行回溯,否则得不到正确的结果
用心的读者可以试着把if条件里a[k]=0这句话去掉,看下是什么结果
笔者在看视频教程的时候发现他们写的加法中都没有这个回溯语句,求21位花朵数的时候可以得到正确答案,而求其他的花朵数的时候却是错误的,进而又尝试两个if的顺序,发现sum=0的递归出口写在后面和写在前面的结果是不一样的,再各种调试,最终发现了这个问题。(有时候官方的代码不一定可信)