Java大神快来帮助我解决这个递归的问题啊~

「已注销」 2016-10-19 10:07:35
今天忽然觉得黑洞数有点意思,就想写个程序能任意输入一个数字,就能得到相同位数的黑洞数。
所谓黑洞数,参见某百科:


以下为程序中用到的相关方法:

/**
* calculate black hole number
*/
public int getSubBlackHoleNum(int i) {
t=0;
int n = getCountOfNum(i);
println("length:"+n);
// 由高到低取出被计算数各位并存入数组
int arr[] = new int[n];
for (int j = 0; j < n; j++) {
int tmp = (int) Math.pow(10, n - j - 1);
if (j == 0) {
arr[j] = i / tmp;
} else {
arr[j] = i / tmp % 10;
}
}
//条件check,要求各个位不能全部相等
boolean bool= true;
for(int m = 0;m<arr.length-1;m++){
if(arr[m]!=arr[m+1]){
bool = false;
}
}
if(!bool){
// 对数组进行升序排序
ArrayList<Integer> list1 = bubbleSortAsc(arr);
// 将位还原成数min
int min = 0;
for (int k = 0; k < list1.size(); k++) {
int q = list1.get(k);
int p = (int) Math.pow(10, list1.size() - k - 1);
min += q * p;
}
print("min:" + min+" ");

// 对数组进行降序排序
ArrayList<Integer> list2 = bubbleSortDesc(arr);
// 将位还原成数max
int max = 0;
for (int k = 0; k < list2.size(); k++) {
int q = list2.get(k);
int p = (int) Math.pow(10, list2.size() - k - 1);
max += q * p;
}
print("max:" + max+" ");
int result = max-min;
println("result:"+result);
if(result==getSubBlackHoleNum(result)){
return result ;
}
}
return 0;
}

/**
* count the length of a number
*
*/
int t = 0;
public int getCountOfNum(int i){
if(i/10!=0){
t++;
getCountOfNum(i/10);
}
return t+1;
}

/**
* Bubble sort By asc
*
* @param arr
* @return
*/
public ArrayList<Integer> bubbleSortAsc(int arr[]) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
// println("j:"+j);
int tmp = 0;
if (arr[j] > arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
// println("i:"+i);
}
ArrayList<Integer> list = new ArrayList<Integer>(arr.length);
for (int i = 0; i < arr.length; i++) {
list.add(arr[i]);
}
return list;
}

/**
* Bubble sort By desc
*
* @param arr
* @return
*/
public ArrayList<Integer> bubbleSortDesc(int arr[]) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - i - 1; j++) {
// println("j:"+j);
int tmp = 0;
if (arr[j] < arr[j + 1]) {
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
// println("i:"+i);
}
ArrayList<Integer> list = new ArrayList<Integer>(arr.length);
for (int i = 0; i < arr.length; i++) {
list.add(arr[i]);
}
return list;
}


这是UT代码 :

public void testGetSubBlackHoleNum(){
print(mu.getSubBlackHoleNum(1245));
}

我用debug跑了几个循环,不能直接跑,不然后面都是死循环,会崩溃的

在49行递归调用的时候出现问题,java.lang.stackoverflowerror:


我的想法是,在算出一次的结果后,把该结果作为参数放到下一次计算,然后比较两次的计算结果,如果相同,便是黑洞数,返回该数字。然而事实却不是这样的,当我计算到黑洞数时,就会无限递归,导致内存溢出。归根到底还是黑洞数的本质啊,不然怎么叫黑洞[无奈摊手],大家能不能给一个简单可行的方法能够返回这样一个值而不报错。
...全文
562 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2016-10-21
  • 打赏
  • 举报
回复
引用 11 楼 bree06 的回复:
min和max可以一次计算出来没必要进行两次排序, 从1->n为升序的话那从n->1就是降序. 另外int的最大长度为10, 所以没有必要使用不定长的List, 直接定义为int[10]数组就行. 为什么不参照4楼的做法呢? 更好理解
是的,一次排序后只要对其再做字符串反转就可以了,我java还比较菜,对这些方法不太熟悉 然后自己方法也写出来了,就懒得改。。。所以代码显得有点冗长
bree06 2016-10-21
  • 打赏
  • 举报
回复
min和max可以一次计算出来没必要进行两次排序, 从1->n为升序的话那从n->1就是降序. 另外int的最大长度为10, 所以没有必要使用不定长的List, 直接定义为int[10]数组就行. 为什么不参照4楼的做法呢? 更好理解
bree06 2016-10-20
  • 打赏
  • 举报
回复
按照定义3位数中有很多的黑洞数为0, 比如100, 101, 111很多, 因为大小排完之后他们的最大值和最小值相等. 相减就为0了. 另外5位数及以上会出现无限循环的情况, 比如35559, 最大95553, 重排之后最小45559最大95554,然后重排之后最小又为35559,最大又为45559无限循环下去. 这样的数还很多.
public static void main(String[] args) {
    int num = 1245, v, count = 100;  // 这里为了防止无限循环设置了阀值. 5位数及以上会出现无限循环.
    while ((v = sub(num)) != num && count-->0) {
        num = v;
    }
    System.out.println(v);
}

static int sub(int num) {
    int[] _v = new int[10];
    int len = 0;
    while (num > 0) {
        _v[len++] = num % 10;
        num /= 10;
    }
    int[] v = Arrays.copyOf(_v, len);
    Arrays.sort(v);
    int max = 0, min = 0;
    for (int i = 0; i < len; i++) {
        min = min * 10 + v[i];
        max = max * 10 + v[len - i - 1];
    }
    return max - min;
}
ITjavaman 2016-10-20
  • 打赏
  • 举报
回复

public class Main {

	public static void main(String[] args) {
		// 这里还有个不能是全部相同的数字判断,就不写了
		System.out.println(returnblacknum("2884", 0));
	}

	// 如果超过7次或者排列后只差等于自身,返回
	private static String returnblacknum(String s, int count) {
		if ((count > 7) || cut(s).equals(Integer.parseInt(s))) {
			return s;
		}
		return returnblacknum(cut(s), count + 1);
	}

	// 排列后两个数的差
	private static String cut(String s) {
		int max,min;
		String[] ss = s.split("");
		Arrays.sort(ss);
		s = "";
		for (String s1 : ss) {
			s = s + s1;
		}
		min = Integer.parseInt(s);
		max = Integer.parseInt(new StringBuilder(s).reverse().toString());
		return new StringBuilder().append(max - min).toString();
	}
}

nikyotensai 2016-10-20
  • 打赏
  • 举报
回复
你加个count,黑洞数第n次出现的时候跳出。n为你可以确定是黑洞数时循环次数
「已注销」 2016-10-20
  • 打赏
  • 举报
回复
package com.wgp.util;

import java.util.ArrayList;
import java.util.Scanner;

public class BlackNumUtil {

	static String LINE = "--------------------------------------------------------------";
	
	/**
	 * 全局变量cutList,用于存放最终的黑洞数
	 */
	static ArrayList<Integer> cutList = new ArrayList<Integer>();
	
	/**
	 * 全局变量t,用于计算输入值位数
	 */
	static int t = 0;
	
	/**
	 * 全局变量id,显示计算次数
	 */
	static int id = 1;
	
	/**
	 * create a new line
	 */
	public static void println() {
		System.out.println();
	}

	/**
	 * create the content with a new line
	 *
	 * @param o
	 */
	public static void println(Object o) {
		System.out.println(o);
	}

	/**
	 * create the content without a new line
	 *
	 * @param o
	 */
	public static void print(Object o) {
		System.out.print(o);
	}

	/**
	 * 获取数字位数
	 * @param i
	 * @return
	 */
	public static int getCountOfNum(int i) {
		if (i / 10 != 0) {
			getCountOfNum(i / 10);
			t++;
		}
		return t + 1;
	}

	/**
	 * 正序冒泡排序
	 *
	 * @param arr
	 * @return list
	 */
	public static ArrayList<Integer> bubbleSortAsc(int arr[]) {
		for (int i = 0; i < arr.length - 1; i++) {
			for (int j = 0; j < arr.length - i - 1; j++) {
				int tmp = 0;
				if (arr[j] > arr[j + 1]) {
					tmp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tmp;
				}
			}
		}
		ArrayList<Integer> list = new ArrayList<Integer>(arr.length);
		for (int i = 0; i < arr.length; i++) {
			list.add(arr[i]);
		}
		return list;
	}

	/**
	 * 倒序冒泡排序
	 *
	 * @param arr
	 * @return list
	 */
	public static ArrayList<Integer> bubbleSortDesc(int arr[]) {
		for (int i = 0; i < arr.length - 1; i++) {
			for (int j = 0; j < arr.length - i - 1; j++) {
				int tmp = 0;
				if (arr[j] < arr[j + 1]) {
					tmp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tmp;
				}
			}
		}
		ArrayList<Integer> list = new ArrayList<Integer>(arr.length);
		for (int i = 0; i < arr.length; i++) {
			list.add(arr[i]);
		}
		return list;
	}

	/**
	 * 将传入参数做数字正排列(有小到大 :min值)和倒排列(由大到小:max值),计算差值max-min
	 *
	 * @param i
	 * @return 
	 */
	public static int cut(int i) {
		print("id:"+id+"   ");
		id++;
		print("initial value:" + i + "   ");
		t = 0;
		int n = getCountOfNum(i);
		// 由高到低取出被计算数各位并存入数组
		int arr[] = new int[n];
		for (int j = 0; j < n; j++) {
			int tmp = (int) Math.pow(10, n - j - 1);
			if (j == 0) {
				arr[j] = i / tmp;
			} else {
				arr[j] = i / tmp % 10;
			}
		}
		//判断数字的每一位是否相等
		Boolean bool = true;
		for (int m = 0; m < arr.length - 1; m++) {
			if (arr[m] != arr[m + 1]) {
				bool = false;
			}
		}
		if (!bool) {
			// 对数组进行升序排序
			ArrayList<Integer> list1 = bubbleSortAsc(arr);
			// 将数组计算为数字min
			int min = 0;
			for (int k = 0; k < list1.size(); k++) {
				int q = list1.get(k);
				int p = (int) Math.pow(10, list1.size() - k - 1);
				min += q * p;
			}
			print("min:" + min + "   ");
			// 对数组进行降序排序
			ArrayList<Integer> list2 = bubbleSortDesc(arr);
			// 将数组计算为数字max
			int max = 0;
			for (int k = 0; k < list2.size(); k++) {
				int q = list2.get(k);
				int p = (int) Math.pow(10, list2.size() - k - 1);
				max += q * p;
			}
			print("max:" + max + "   ");
			int cut = max - min;
			println("max-min=" + cut);
			return cut;
		}
		println();
		return 0;
	}

	/**
	 * 将cut值放入全局变量cutList中
	 * @param cut
	 * @return cutList
	 */
	public static ArrayList<Integer> setCutToList(int cut) {
		cutList.add(cut);
		return cutList;
	}

	/**
	 * 递归计算,直到出现这样一个值,它在这样一个集合之中(这个集合就是每一次递归计算的max-min的合集),递归结束后返回这个值
	 *
	 */
	public static int getSameValInList(int i) {
		int cut = cut(i);
		ArrayList<Integer> ct = setCutToList(cut);
		if (ct.get(ct.size()-1) == 0) {
			println();
			print("不能输入各位完全相同的数字!");
			return 1;
		}
		for (int j = 0; j < ct.size() - 1; j++) {
			if (cut == ct.get(j)) {
				return i;
			}
		}
		return getSameValInList(cut);
	}

	/**
	 * 得到最终的黑洞数集合
	 * @param i
	 * @return li
	 */
	public static ArrayList<Integer> getFinalList(int i) {
		getSameValInList(i);
		ArrayList<Integer> li = new ArrayList<Integer>();
		int lastIndex = cutList.size() - 1;
		int last = cutList.get(lastIndex);
		int firstIndex = cutList.indexOf(last);
		for (int j = firstIndex; j < lastIndex; j++) {
			li.add(cutList.get(j));
		}
		return li;
	}

	/**
	 * 可以循环计算
	 */
	public static void roopCount(){
		while (true) {
			t=0;
			cutList.clear();
			Scanner input = new Scanner(System.in);
			println("请输入任意一个正整数(退出请输0):");
			int a = input.nextInt();
			if(a==0){
				print("Exit!");
				break;
			}
			int n = getCountOfNum(a);
			if(n<=2){
				println("输入的值必须为三位数以上且各位不能全部相等!");
				println(LINE);
				continue;
			}
			ArrayList<Integer> li = getFinalList(a);
			println();
			int size = li.size();
			if (size != 0 ) {
				println(n + "位的黑洞数或黑洞数集合是:" + li);
			}
			println(LINE);

		}
	}
	/**
	 * main 方法
	 * @param args
	 */
	public static void main(String args[]) {
		roopCount();
	}
}
「已注销」 2016-10-20
  • 打赏
  • 举报
回复
多谢各位的指点,我解决了昨天的问题。然后在楼上代码中总结了一下,今天上班之余完善了自己的代码。


现在我对多了一些黑洞数的思考(我的程序中暂且不考虑一位或者两位的情况,一位时候正序和倒序都是自己,怎么减都是0 = =、两位时候正序和倒序怎么减都是9,下一次运算时候参数9也成了一位,所以我觉得考虑三位以下的情况意义不大),在三位或者四位数的时候,黑洞数姑且是一个定值(495和6174),但是五位数以后,黑洞数往往是一组数据。如果不做流程的控制,也是会死循环的。那么,我能不能在程序中把这些循环的数据输出来?


比如我随意输出一个数字:456131
根据程序打印的数据:
id:1 initial value:456131 min:113456 max:654311 max-min=540855
id:2 initial value:540855 min:45558 max:855540 max-min=809982
id:3 initial value:809982 min:28899 max:998820 max-min=969921
id:4 initial value:969921 min:126999 max:999621 max-min=872622
id:5 initial value:872622 min:222678 max:876222 max-min=653544
id:6 initial value:653544 min:344556 max:655443 max-min=310887
id:7 initial value:310887 min:13788 max:887310 max-min=873522
id:8 initial value:873522 min:223578 max:875322 max-min=651744
id:9 initial value:651744 min:144567 max:765441 max-min=620874
id:10 initial value:620874 min:24678 max:876420 max-min=851742
id:11 initial value:851742 min:124578 max:875421 max-min=750843
id:12 initial value:750843 min:34578 max:875430 max-min=840852
id:13 initial value:840852 min:24588 max:885420 max-min=860832
id:14 initial value:860832 min:23688 max:886320 max-min=862632
id:15 initial value:862632 min:223668 max:866322 max-min=642654
id:16 initial value:642654 min:244566 max:665442 max-min=420876
id:17 initial value:420876 min:24678 max:876420 max-min=851742
我们发现从第10行和第17行的计算结果是一致的,那么不难想象,从id=17往后,会重复id=10到id=16的数据。
那么我就要打印出这样的一组数据。
以下为我的程序运行的截图:




稍后我把整个程序贴出来,大家改一下包名和类名就可以运行,如有不正悉听建议!
anlian523 2016-10-20
  • 打赏
  • 举报
回复
不明觉厉,,,
rage_coder 2016-10-20
  • 打赏
  • 举报
回复
把System.out.println("times:" + count);这行注释掉 运行结果如下: 结果:495 结果:6174 结果:549945 结果:631764
rage_coder 2016-10-20
  • 打赏
  • 举报
回复
上面那个因递归太深会导致内存溢出,可稍作修改,如下: package com.test; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @Description : 求取黑洞数 * * @author : sino * * @Date : 2016年10月20日 */ public class BlankHN { public boolean isBHN(Long num, Integer count) { count++; if(count > 7) return false; System.out.println("times:" + count); List<Integer> nums = getNums(num); if(nums != null && validNum(nums)) { Long max = getMax(nums); Long min = getMin(nums); long num2 = max - min; if(num.compareTo(num2) == 0) { return true; } isBHN(num2, count); } return false; } private boolean validNum(List<Integer> nums) { Set<Integer> set = new HashSet<Integer>(nums); if(set.size() > 1) { return true; } return false; } /** * 该数字大于1位数且各位上数字不能都相等 * @return */ private List<Integer> getNums(Long num) { List<Integer> list = new ArrayList<Integer>(); String s = String.valueOf(num); char[] chars = s.toCharArray(); for (char c : chars) { list.add((int) c); } return list; } private Long getMax(List<Integer> sourceNums) { List<Integer> nums = new ArrayList<Integer>(); Collections.addAll(nums, new Integer[sourceNums.size()]); Collections.copy(nums, sourceNums); boolean flag = true; double n = 0d; while (flag) { if(nums.size() > 0) { Integer max = Collections.max(nums); n += max * Math.pow(10d, nums.size() - 1); nums.remove(max); } else { flag = false; } } return (long) n; } private Long getMin(List<Integer> sourceNums) { List<Integer> nums = new ArrayList<Integer>(); Collections.addAll(nums, new Integer[sourceNums.size()]); Collections.copy(nums, sourceNums); boolean flag = true; double n = 0d; while (flag) { if(nums.size() > 0) { Integer min = Collections.min(nums); n += min * Math.pow(10d, nums.size() - 1); nums.remove(min); } else { flag = false; } } return (long) n; } }
rage_coder 2016-10-20
  • 打赏
  • 举报
回复
package com.test; /** * @Description : * * @author : sino * * @Date : 2016年10月20日 */ public class RunBlankHN { public static void main(String[] args) { BlankHN blankHN = new BlankHN(); for (Long i = 100l; i < 1000000; i++) { if(blankHN.isBHN(i)) { System.out.println("结果:" + i); } } } } package com.test; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @Description : 求取黑洞数 * * @author : sino * * @Date : 2016年10月20日 */ public class BlankHN { public boolean isBHN(Long num) { List<Integer> nums = getNums(num); if(nums != null && validNum(nums)) { Long max = getMax(nums); Long min = getMin(nums); long num2 = max - min; if(num.compareTo(num2) == 0) { return true; } isBHN(num2); } return false; } private boolean validNum(List<Integer> nums) { Set<Integer> set = new HashSet<Integer>(nums); if(set.size() > 1) { return true; } return false; } /** * 该数字大于1位数且各位上数字不能都相等 * @return */ private List<Integer> getNums(Long num) { List<Integer> list = new ArrayList<Integer>(); String s = String.valueOf(num); char[] chars = s.toCharArray(); for (char c : chars) { list.add((int) c); } return list; } private Long getMax(List<Integer> sourceNums) { List<Integer> nums = new ArrayList<Integer>(); Collections.addAll(nums, new Integer[sourceNums.size()]); Collections.copy(nums, sourceNums); boolean flag = true; double n = 0d; while (flag) { if(nums.size() > 0) { Integer max = Collections.max(nums); n += max * Math.pow(10d, nums.size() - 1); nums.remove(max); } else { flag = false; } } return (long) n; } private Long getMin(List<Integer> sourceNums) { List<Integer> nums = new ArrayList<Integer>(); Collections.addAll(nums, new Integer[sourceNums.size()]); Collections.copy(nums, sourceNums); boolean flag = true; double n = 0d; while (flag) { if(nums.size() > 0) { Integer min = Collections.min(nums); n += min * Math.pow(10d, nums.size() - 1); nums.remove(min); } else { flag = false; } } return (long) n; } }
「已注销」 2016-10-19
  • 打赏
  • 举报
回复

50,530

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧