蓝桥杯 算法训练 2的次幂表示

最近博主在刷蓝桥杯官网上的题,发现了一道有意思的算法题:
题目的类容如下:

问题描述
  任何一个正整数都可以用2进制表示,例如:137的2进制表示为10001001。
  将这种2进制表示写成2的次幂的和的形式,令次幂高的排在前面,可得到如下表达式:137=27+23+2^0
  现在约定幂次用括号来表示,即a^b表示为a(b)
  此时,137可表示为:2(7)+2(3)+2(0)
  进一步:7=22+2+20 (2^1用2表示)
  3=2+2^0
  所以最后137可表示为:2(2(2)+2+2(0))+2(2+2(0))+2(0)
  又如:1315=210+28+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)

题目的大意呢就是这样,题很通俗易懂,就是实现起来嘛 额……,
好吧这个当我没说,说一说我的思路把刚开始拿到这道题的时候呢就第一思路就是循环嵌套,加if 判断,但想的是美好的你实践了就会发现这无异于以卵击石,你的思绪会随着这一层一层的嵌套逐步的搅成一缕乱麻(~%?…,# *'☆&℃$︿★?)
后来博主就学聪明了,加上最近喜欢用位运算来解决二进制问题:
我就改变思路用递归的方法来实现了这道题目:

其实嘛递归递归 都是套路(万年不变的模板):
1、首先考虑的就是递归出口(也是最好思考的):
这俩大概的思路我们肯定可以想到 假如我们的递归函数得到一个数字 n = 10
首先 转成二进制格式(关于二进制的转换方法在博主前面的文章里讲解过这里就不仔将转换过程了)
10 =》 (binary)1010
1010 又可以理解为 2^ 3 + 0 + 2^1+0
-----------------------------3------2-----1—0
不知道大家发现规律没有 我们这个逻辑的思考就是从最高位第三位开始 直到最后一位0结束
没错这里的 0 就是递归出口;
那我们的程序就有:
在这里插入图片描述
当我们的 n == 0 的时候就从函数中出来
2、接下来就是理解起来比较难一点的步骤了:
我们都知道c++ 里int类型占 4 个字节也就是 32(4*8)位 那么零 在计算机里以int存放的方式即是 00000000000000000000000000000000 32个零由于是有符号类型的最高位表示的即是符号正负关系
我们想取得n最高位 是第几位只需要使用位运算符
我们将 1 << 31 首先移动31位到int的最高位在于 n 按位与(&)
10000000000000000000000000000000 & 00000000000000000000000000001010 = 0
…… ……
…… ……
直到移动到第三位 1 << 3;
00000000000000000000000000001000 & 00000000000000000000000000001010 = 1
我们便得到了10 的最高位 第三位 那么就可以表示为 2 (3)由于3 > 2 所以又要再次调用函数本身进行嵌套将3 传入函数;

………… 直到n == 0 再依次 从函数栈空间里面(解) 函数 一层一层的跳出来:
在这里插入图片描述
3、最后要注意的是+号问题 如果我们判断一个数 比如 8 =》(binary)1000 现在指向最高位 也就是我们的 j = 3 那么如何判断后面是否添加+号;
这里就可以使用一个巧妙的方法 还是用位运算来完
(binary)1000 我们拿一个 满位 来进行左移 到与他相同位 在进行按位与 就直到它后面是否还又要+的数
65535 (binary)1111111111111111(16个一) 进行左移(16-j)位
那么就是 65535 >> (16-3) = 0000000000001111
0000000000000111 & 1000 =0 为假就表示 后面全为0 就不用再加 + 号
否则就加
在这里插入图片描述

整个程序源代码:

#include <iostream>
using namespace std;
void change(int n){
    if(n == 0){
        cout << 0;return;
    }
    else{
        int i = sizeof(int)*8 - 1;
        while(!(n&(1<<i))){
            i--;
        }
        for(int j = i;j>=0;j--){
            if(n&(1<<j)){
                if(j == 1){
                    cout << "2";
                }
                else{
                    cout << "2" << "(";
                    change(j);
                    cout << ")";
                }
                if(n&(65535>>(16-j))){
                    cout << "+";
                }
            }
        }
    }
}

int main(){
    int n;
    cin >> n;
    change(n);
}
发布了27 篇原创文章 · 获赞 62 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42359956/article/details/87704205