【算法】解题总结:剑指Offer 11 二进制中1的个数(4 种方法)、剑指Offer 12 数值的整数次方

JZ11 二进制中1的个数

(中等)

题目

描述
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。

示例
输入:
10
返回值:
2

解题过程

1 纯正数版——方法一

此题我首先是按纯正数的情况来进行考虑的,但因为负数涉及补码,因此这种方式很对负数是行不通的,但是我还是想练习一下针对这种问题的编码能力,而且如果只是纯正数(当然,0 的情况特殊可考虑,可不考虑),也可以单独出一道题,也有研究的价值。

对一个十进制正数转为二进制的形式,简单来说就是拆成了多个 2^n 的组合(当然,需是先从高位算起的个数最少的组合),在二进制的相应位中用 有效数1 进行标记,因此,我们可以找出数 n 的最高二进制,同时让 n 减去这个数得到新的 n,再对新的 n 进行重复操作,过程中记录下 n 执行减法的次数即可得知 n 的二进制形式中有几个 1 。

【实现】

public class Solution {
    public int NumberOf1(int n) {
        int num = 0; // 二进制形式中 1 的个数

        while (n > 0) {
            int i = 2;
            while (i < n) {
                i *= 2;
            }
            if (i != 2 && i != n) { //当 while 循环体执行过,并且 i 多乘了一次 2 时
                i /= 2;
            }
            n -= i;
            num++;
        }
        return num;
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        System.out.println("solution.NumberOf1(10) = " + solution.NumberOf1(10));
        System.out.println("solution.NumberOf1(8) = " + solution.NumberOf1(8));
        System.out.println("solution.NumberOf1(3) = " + solution.NumberOf1(3));
        System.out.println("solution.NumberOf1(1) = " + solution.NumberOf1(1));
    }
}

在这里插入图片描述

2 纯正数版——方法二

或是用另一种更简洁的方式实现,参数 n 对 2 求余,如果没有余数,则可能是正好的 2 的整数倍,也可能不是,因此只要 n 不等于 0 ,再对 n 进行除以 2 ,在这其中如果出现余数为 1 的情况,则说明当前的 n 值,用 2 进制表示时,1 的数量肯定是多余 1 个的,因此要计数上这种情况的一次,并且,之后 n 因为是整除 2 ,因此最后肯定还会出现 1 次求余为 1 的情况,这也正是当前 n 值(当然不是说初始的 n 值)对应的当前最高位的二进制 1,因此,用这种方法,最终也可以求出正数情况时的二进制中 1 的个数。

【实现】

public class Solution {
    public int NumberOf1(int n) {
       int ans = 0;
        while (n != 0) {
            int tmp = n % 2;
            if (tmp == 1) ++ans;
            n /= 2;
        }
        return ans;
    }
}
3 此题正式版——二进制位移法

直接将整数看成二进制,然后采用与运算、移位的方法。

首先,我们先写一下正数情况下的实现:

【实现】

public class Solution {
    public int NumberOf1(int n) {
		int ans = 0;
        while (n != 0) {
            if ((n & 1) == 1)  ans++;
            n >>= 1;
        }
        return ans;
    }
}

由于正数情况,右移 1 位,左位是补 0 ,因此,可以终止 while 循环,最终得出正确答案,但是如果我们想处理负数的情况,即左位补 1 ,在上述代码中就解决不了,而且 while 就终止不了,况且一直左移只会让 1 的个数越来越多。

因此,我们换种方式,我们用 1 作为移动方,使用初始的 1 不断左移,并与参数 n 进行与运算,这样最终这个初始的 1 是可以将 1 移出左边界,从而变成 0 ,并且也已经将参数 n 中的 1 全部找出,因此,是可行的,代码如下:

【实现】

public class Solution {
    public int NumberOf1(int n) {
		int ans = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) != 0)  ans++;
            flag <<= 1;
        }
        return ans;
    }
}

这个算法可以解决此题,但是需要运行32次(int 型为 4 个字节,因此在内存中占 32 位,并且是将 1 从右向左移出)。
在这里插入图片描述

4 此题正式版——技巧法

十分巧妙且高效,题解也解释的十分清楚,我不再过多赘述,只能说发明这个算法的人太强了,并且是十分善于观察和探索的人才能想出来,当然我们也不能排除是偶然的灵感迸发。
在这里插入图片描述

JZ12 数值的整数次方

(中等)

题目

描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0。不得使用库函数,同时不需要考虑大数问题,也不用考虑小数点后面0的位数。

示例1
输入:
2.00000,3
返回值:
8.00000

示例2
输入:
2.10000,3
返回值:
9.26100

示例3
输入:
2.00000,-2
返回值:
0.25000
说明:
2的-2次方等于1/4=0.25

思路

此题根据指数的情况来划分即可。

当指数为 0 时,若底数也为 0 ,因 0 的 0 次幂无意义,因此此情况应提示错误信息;

当指数为正数时,将指数个底数相乘返回结果即可;

当指数为负数时,应将底数转为其倒数,并且,若在循环计算时借助指数与当前下标大小作为循环终止条件,则指数应提前转为其相反数。

实现

public class JZ12数值的整数次方 {
    public double Power(double base, int exponent) {
        if (exponent == 0) {
            if (base == 0) {
                try {
                    throw new Exception("0的0次方无意义");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return 1;
        } else if (exponent > 0) { //指数为正数
            if (base == 0) {
                return 0;
            }
        } else if (exponent < 0) { //指数为负数
            if (base == 0) {
                try {
                    throw new Exception("当指数为负数,底数为0时无意义");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            base = 1 / base;
            exponent = -exponent;
        }
        double result = 1;
        for (int i = 0; i < exponent; i++) {
            result *= base;
        }
        return result;
    }


    public static void main(String[] args) {
        JZ12数值的整数次方 s = new JZ12数值的整数次方();
        System.out.println("s.Power(2.00000, 3) = " + s.Power(2.00000, 3));
        System.out.println("s.Power(2.00000, 0) = " + s.Power(2.00000, 0));
        System.out.println("s.Power(2.00000, -2) = " + s.Power(2.00000, -2));
    }
}

在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超周到的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值