2次幂的表示(递归)

1. 问题描述:

  任何一个正整数都可以用2进制表示,例如:137的2进制表示为10001001。
  将这种2进制表示写成2的次幂的和的形式,令次幂高的排在前面,可得到如下表达式:137=2^7+2^3+2^0
  现在约定幂次用括号来表示,即a^b表示为a(b)
  此时,137可表示为:2(7)+2(3)+2(0)
  进一步:7=2^2+2+2^0 (2^1用2表示)
  3=2+2^0 
  所以最后137可表示为:2(2(2)+2+2(0))+2(2+2(0))+2(0)
  又如:1315=2^10+2^8+2^5+2+1
  所以1315最后可表示为:
  2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

输入格式

  正整数(1<=n<=20000)

输出格式

  符合约定的n的0,2表示(在表示中不能有空格)

样例输入

137

样例输出

2(2(2)+2+2(0))+2(2+2(0))+2(0)

样例输入

1315

样例输出

2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

提示

  用递归实现会比较简单,可以一边递归一边输出

 

2. 思路分析:

① 分析题目可以知道最后要把所有的大于等于次幂的式子使用2和2的0次幂来表示,即最后一次幂的话表示成2,零次幂的话表示成2(0)

对于这样的例子我们先可以对给出的测试用例进行简单的分析,可以知道137第一次的时候可以分解成7,3,0的幂,表示成137=2^7+2^3+2^0,而对于7这个幂我们又可以再次进行分解,对于3这个幂我们又可以再一次分解,对于0不能够分解了那么写成上面的2(0)就可以了,分析到这里我们可以知道这个是一个递归的过程,因为可以看到对于数字的分解都是一样的处理方式,而且数据规模在不断地进行缩小,这个也是能够使用递归求解的一个特点:对于问题的求解方式是一样的,并且每一步我把自己的任务处理好然后交给下一层去处理,问题规模在不断缩小

② 我们知道了使用递归求解之后需要确定递归求解的过程,可以知道先要分解成若干个2的幂,而这些幂恰恰是二进制中当前位是1表示的二进制处于的第几位,例如2的7次幂表示二进制串上的第七位是1,所以我们就可以将当前的数字先转化为二进制字符串来进行处理,使用一个循环来遍历字符串,在循环中判断二进制串是否为1,假如是1我们才可以对于当前的二进制位上的循环变量进行递归分解,不是1的话直接跳过,for循环中的循环变量假如从零开始的话那么当前是1的位数需要使用二进制串的长度 - 当前的循环变量i的值 - 1,然后进行递归分解

③ 递归分解的过程中我们需要使用到之前递归调用的返回值所以定义的递归方法是具有返回值的,返回类型是一个字符串,在循环中判断当前为是1那么进行递归调用,并且当前的数字应该减去当前二进制位上的权重,因为下一次分解的是剩下来的二进制串表示的值,假如当前将137分解了2^7,那么接下来就需要分解的数字是137 - 2^7,对于2^7我们又是进行递归求解的,所以这样问题就会变得简单了

④ 对于这道问题来说需要注意的是其中的细节的处理,因为涉及到加上(和2和2(0)的问题所以我们需要分情况进行讨论,这个是能否完全正确解出来这道题目的关键,我们知道2要加上左括号那么当前数字n的值肯定是大于等于4的因为有一种情况是2(2)

所以需要判断当前的n是否大于等于了4假如是我们需要添加左括号然后进行递归调用,我们需要对递归调用的是进行拼接,所以加上递归的方法就好了,然后当前n大于等于了4的情况调用完需要拼接上左括号,这些细节都是可以对照137分解的例子进行想象的,因为我是递归调用填加了左括号那么当前的递归调用完了肯定要添加有括号

⑤ 此外还需要判断是否要加上"+"的问题,我们知道当当前的数字n大于等于了2我们才可以加上"+"号,因为有一种情况是最后n剩下了2所以需要加上"+"

⑥ 对于剩下来的情况我们需要判断n是否等于了3,假如是那么需要将当前的字符串加上"2+"即可,因为3 = 2 + 2(0),此外进行递归调用这个时候需要在递归调用之后将n的值置为零,n等于2的情况也是一样,2 = 2 将n的值置为零

最后千万别忘了还有一个是n等于1的情况的判断,因为假如是5这种情况我们分解成5 = 2(2)+ 剩下来1的分解,但是5经过是n大于等于4的递归调用之后再次进入循环那么不满足任何一个条件所以1的情况的分解就为空了,所以最后需要判断n是否等于1的情况,还有一个点就是上面判断n等于3(n == 2的时候不用将n重置为零因为2递归分解之后最后一位不是1但是3的分解是有可能最后一位分解是1的情况)的情况我们需要将n置为零是因为我们在递归调用

⑦ 这些细节都是需要自己经过比较简单的例子发现错误然后推断出哪里出现了错误然后修改代码得到的,我们对于自己出现的错误可以将简单例子在脑海中结合代码代入去检查来判断代码的哪些部分出现了错误,哪些需要加上某些符号这些都是都要结合具体的例子代入思考得到的

⑧ 这个例子对于递归的思想的形成也是非常有帮助的,因为体现了递归求解问题的特点,而且其中涉及到比较多的细节,需要做够一定的题目这种递归的思维才能够形成的,而且在思考递归题的时候需要进行全局考虑,把任务进行一步步地进行分解,自己的任务先完成一部分然后剩下的部分交给下一层去解决,我需要等待的是下一层处理之后得到的结果然后把结果拼接来,最后返回来的就是最后问题求解之后的结果

⑨ 我们在写递归代码的时候先要把递归求解的那部分先写出来比如分析到137=2^7+2^3+2^0求解出7,3,0幂的时候那么我们递归求解剩下来的时候先把递归代码先写出来

⑩ 调试的时候将测试用例进行测试如果发现那里少了分解的,肯定是括号里面的某一些逻辑是没有考虑到的,所以这个时候需要输入括号里面的没有正确分解的小的数字进行分解(因为小数字分解不对那么大的数字分解也是不对的),结合代码进行逻辑判断哪些出现了问题,对于小数据的来说是比较容易调试的

3. 具体的代码如下:

import java.util.Scanner;
public class Main {
	//我感觉最重要的是要理解其中的整个递归的过程,代入进去具体的例子然后想一下具体的细节
	//比如什么时候去加左括号我们知道
	//递归就是对相同的事情进行同样的处理不断把数据规模缩小
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		//System.out.println(Integer.toBinaryString(n));
		String s = solve(n);
		System.out.println(s);
		sc.close();
	}
	
	private static String solve(int n) {
		//最后一个出口
		if(n == 1) return "2(0)";
		String str = "";
		if(n > 0){
			String s = Integer.toBinaryString(n);
			int len = s.length();
			for(int i = 0; i < len; i++){
				//超过了4我才会去添加左括号
				if(s.charAt(i) == '1' && n >= 4){
					str = str + "2(" + solve(len - i - 1) + ")";
					n -= (1 << (len - i - 1));
					//注意应该是n>=2才正确
					if(n >= 2) str += "+";
				}else if(s.charAt(i) == '1' && n == 3){
					n -= (1 << (len - i - 1));
					str += "2+" + solve(n);
					//下面这句也是很关键的涉及到最后5能否加入2(0)的问题
					n = 0;
				}else if(s.charAt(i) == '1' && n == 2){
					n -= (1 << (len - i - 1));
					str += "2" + solve(n);
				}else if(s.charAt(i) == '1' && n == 1){
					str += "+2(0)"; 
				}
			}
		}
		return str;
	}
}

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值