多位水仙花数算法

来源:互联网 发布:江苏甲子网络 编辑:程序博客网 时间:2024/05/23 19:01

多位水仙花数算法

1.递归(用时16-20s;写起来非常方便,非常爽):

import java.math.BigInteger;import java.util.ArrayList;/** * 三位的水仙花数共有4个:153,370,371,407;  四位的水仙花数共有3个:1634,8208,9474;   五位的水仙花数共有3个:54748,92727,93084;   六位的水仙花数只有1个:548834;   七位的水仙花数共有4个:1741725,4210818,9800817,9926315;   八位的水仙花数共有3个:24678050,24678051,88593477  * @author Administrator *ps : 把new BigInteger(),改为BigInteger.valueof(); 把运行时间从35秒减低到20秒 */public class FlowerNumber_simple {private int size;private ArrayList<BigInteger> resultLists;private int[] base_num_count;private BigInteger[] subResult;public FlowerNumber_simple(int size){this.size = size;resultLists = new ArrayList<BigInteger>();base_num_count = new int[10];subResult = new BigInteger[10];/*for(int i=0;i<10;i++){subResult[i] = new BigInteger(i+"").pow(size);}*/for(int i = 0; i < 10; ++i){//subResult[i] = BigInteger.valueOf(i).pow(this.level);subResult[i] = BigInteger.ONE;for(int j = 0; j < size; ++j){subResult[i] = subResult[i].multiply(BigInteger.valueOf(i));}}}public static void main(String[] args) {FlowerNumber_simple fn = new FlowerNumber_simple(21);long start = System.currentTimeMillis();fn.backTracking(0, 0);for(BigInteger b : fn.resultLists){System.out.println(b);}long times = System.currentTimeMillis()-start;System.out.println(times/1000+"秒");}private void backTracking(int level,int current_index){if(level>=size){getresult();return ;}for(int i=current_index;i < 10;i++){base_num_count[i] ++;backTracking(level+1, i);base_num_count[i] --;}}private void getresult() {BigInteger result = BigInteger.ZERO;for(int i=0;i<10;i++){if(base_num_count[i]!=0){//result = result.add(subResult[i].multiply(new BigInteger(base_num_count[i]+""))  );result = result.add(subResult[i].multiply(BigInteger.valueOf(base_num_count[i])));}}String result_str = result.toString();if(result_str.length()== size){int[] same_num_count = new int[10];for(int i =0 ;i<size;i++){same_num_count[result_str.charAt(i)-'0'] ++;}for(int i=0;i<10;i++){if(same_num_count[i] != base_num_count[i])return ;}resultLists.add(result);}}}



2.栈回溯(用时1s-3s;极速):

import java.math.BigInteger;import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;import java.util.Hashtable;import java.util.Set;/** * 寻找水仙花数问题 * @author lixinji * 从三方面优化循环*0.把常用的大数都缓存在数组。(21位水仙花数,缓存和不缓存时间相差10s到30s之间) * 1.循环对象优化:利用组合来穷举,例如0个9,1个9....9个9循环所有的可能性。只要这个组合不符合,那么可以排除很多数 * 2.上下限优化:在特定的组合下,计算最小值,最大值,然后和最小值常量,最大值常量比较,如果超出那么立马排除 * 3.组合违背优化: 在特定的组合下,比较最小值和最大值高位相同的部分,如果出现与特定组合的情况,排除。(例如组合假定只有2个9,而最小大值高位相同部分计算结果有3个,很明显不符合) */public class FlowerNumber {private int size; //位数private  BigInteger MIN_CONSTANT; //最小数常量private  BigInteger MAX_CONSTANT;//最大数常量private Hashtable<String, BigInteger> ht;  //存放常用的大数,用hashtable是未了提高效率private Set<BigInteger> resultsets = new HashSet<BigInteger>(); //存放结果集合private int index;//索引,其中9-index代表基数private int[] base_num_count;// base_num_count[index] 表示当前基数的组合个数private int[] sum_num_count;//sum_num_count[index] 表示当前循环总基数的组合个数private BigInteger[] totalResult;//sum_num_count[index]  代表当前循环基数的总结果public FlowerNumber(int size) {this.size = size;int s = size<10?10:size;base_num_count = new int[s];sum_num_count = new int[s];totalResult = new BigInteger[s];ht = new Hashtable<String, BigInteger>();for(int i=0;i<=s;i++){ //存放基数,位数的大数字ht.put("n_"+i, new BigInteger(i+""));}for(int i=0;i<=10;i++){ //存放基数的size次方结果ht.put("p_"+i, new BigInteger(i+"").pow(size));}MIN_CONSTANT=N(10).pow(size-1);MAX_CONSTANT=P(10).subtract(N(1));}private BigInteger N(int i){return ht.get("n_"+i);}private BigInteger P(int i){return ht.get("p_"+i);}public static void main(String[] args) {FlowerNumber fn =new FlowerNumber(21); //这里更改位数int s = fn.MAX_CONSTANT.divide(fn.P(9)).intValue();//求出P(9)的除数for(int i=0;i<=s;i++){fn.find(i);}BigInteger[] results =new BigInteger[fn.resultsets.size()];fn.resultsets.toArray(results);Arrays.sort(results);for(BigInteger bi : results){System.out.println(bi);}}// 检查组合是否合格,如果组合位数未满,或者组合匹配正确返回真;不合格,返回假。private boolean checkCombination(){BigInteger minVal = totalResult[index];BigInteger maxVal = totalResult[index].add(P(9-index).multiply(N(size-sum_num_count[index])));//检查是否违反上下限if(minVal.compareTo(MAX_CONSTANT)>0) return false;if(maxVal.compareTo(MIN_CONSTANT)<0) return false;String minStr = minVal.toString();String maxStr = maxVal.toString();char c;int sameCount[] = new int[10];for(int i=0;i<size;i++){if((c = minStr.charAt(i)) == maxStr.charAt(i)){sameCount[c-'0']=sameCount[c-'0']+1;}else{ break;}}//检查是否违反组合设定for(int i =0;i<index;i++){if(base_num_count[i]<sameCount[9-i]){return false;}}if(sum_num_count[index] == size){BigInteger result = BigInteger.ZERO;String totalStr = totalResult[index].toString(); for(int i=0;i<size;i++){int j=totalStr.charAt(i)-'0';result = result.add(P(j));}return totalResult[index].compareTo(result) == 0;}return true;}private void setValue(int num){  //num 代表当前index(基数为9-index) 的组合个数;totalResult[index-1]永远是指前一个基数的总和base_num_count[index] = num;if(index == 0){sum_num_count[index]=num;totalResult[index] = P(9-index).multiply(N(num));}else{sum_num_count[index] = sum_num_count[index-1]+num;totalResult[index] = totalResult[index-1].add(P(9-index).multiply(N(num)));}}private void find(int i) {index =0;int startValue=i;setValue(startValue);while(true){if(checkCombination()){if(sum_num_count[index]==size){resultsets.add(totalResult[index]);//System.out.println(totalResult[index]);if(back()) break;}//组合基数递减并全部填充;当基数为0时,证明尾数已经循环完了,不进入改分支if(index !=9 ){index ++;setValue(size-sum_num_count[index-1]);continue;}}//基数数目减少一个if(back()){break;}}}private boolean back() {if(checkEnd()) return true;if(base_num_count[index] ==0){while(base_num_count[index] == 0){if(index > 0)index --;else return true;}}//如果当前基数不是9,那么当前基数数目减1,设回原来的值if(index >0){setValue(base_num_count[index]-1);return false;}else{return true;}}private boolean checkEnd(){for(int i=0;i<=9;i++){if(base_num_count[i] !=0)return false;}return true;}}



0 0
原创粉丝点击