花朵数

花朵数求解方法(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的递归出口写在后面和写在前面的结果是不一样的,再各种调试,最终发现了这个问题。(有时候官方的代码不一定可信)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值