每日算法总结——异或运算的性质和扩展、二分法求平方根

一、位运算

所有运算到计算中底层中都会变成位运算,位运算可以提高程序的效率,而且我们在研究JDK或者某个框架的源码时,会发现很多地方都用到了位运算!

异或运算
  • 描述:对应位相同为0,不同为1,在实际运算的时候可以理解为**无进位相加**

  • 性质

    1. 0^N=NN^N=0
    2. 异或运算满足交换律和结合律:a^b=b^a(a^b)^c=a^(b^c)
    3. 由性质2推出:一批数统一异或在一起得到一个值,和异或的先后顺序无关
  • 应用

    1. 使用异或运算**交换两个数的值**

      int a = 甲, b = 乙
      a = a ^ b	--->	a = 甲^乙
      b = a ^ b	--->	b = 甲^乙^乙 = 甲^0 = 甲
      a = a ^ b	--->	a = 甲^乙^甲 = 甲^甲^乙 = 0^乙 = 乙
      

      优点:不用申请额外的空间,即可完成交换;位运算效率更高

      【注意】:两个变量所指向的内存必须不相同

      面试题】一个int类型的一维数组arr
      ①其中有一种数出现了奇数次,其他数都出现了偶数次,找出该数

      int eor = 0
      eor^arr[0]^arr[1]^...^arr[N-1]最终的结果即为该数
      

      ②其中有两种数出现了奇数次,其他数都出现了偶数次,找出这两个数

      假设这两个数分别为a、b
      	int eor = 0
      	eor = eor^arr[0]^arr[1]^...^arr[N-1] = a^b
      	由于a≠b,所以eor = a^b ≠ 0
      	eor等于1的位置,a和b在该位置一定不相同,假设该位置为第8位(只用考虑一个为1的位置)
      再进行一次异或遍历:
      	int eor' = 0
      	只将第8位为1的数arr[i]与eor'异或,最终就会得到a/b
      

      Java实现:

      public class EvenTimesOddTimes {
          /**
           * 【面试题目】一个int类型的一维数组arr
           * ①其中有一种数出现了奇数次,其他数都出现了偶数次,找出该数
           * ②其中有两种数出现了奇数次,其他数都出现了偶数次,找出这两个数
           */
          public static void printOddTimesNum1(int[] arr) {
              // ①其中有一种数出现了奇数次,其他数都出现了偶数次,找出该数
              int eor = 0;
              for (int cur : arr) {
                  eor ^= cur;
              }
              System.out.println(eor);
          }
      
          public static void printOddTimesNum2(int[] arr) {
              // ②其中有两种数出现了奇数次,其他数都出现了偶数次,找出这两个数
              int eor = 0;
              for (int cur : arr) {
                  eor ^= cur;
              }
              // eor = a^b
              // eor != 0
              // eor必有一个位置上是1
              // eor与运算eor的补码,可以提取出最右侧的1
              int rightOne = eor & (~eor + 1);
              int onlyOne = 0;
              for (int cur : arr) {
                  if ((cur & rightOne) == 0) {
                      onlyOne ^= cur;
                  }
              }
              System.out.println("a=" + onlyOne + ",b=" + (onlyOne ^ eor));
          }
      }
      
求出某个数最右侧的1

假设要求eor最右侧的1:eor与运算eor的补码eor & (~eor + 1)

求两个数的中间值

(left + right) / 2 等价于 left + ((right - left) >> 1)

  1. 这样写的目的一个是为了防止 (left + right)出现溢出,一个是用右移操作替代除法提升性能。

  2. left + ((right -left) >> 1) 对于目标区域长度为奇数而言,是处于正中间的,对于长度为偶数而言,是中间偏左的。因此左右边界相遇时,只会是以下两种情况:

    • left/mid , right (left, mid 指向同一个数,right指向它的下一个数)

    • left/mid/right (left, mid, right 指向同一个数)

即因为mid对于长度为偶数的区间总是偏左的,所以当区间长度小于等于2时,mid 总是和 left在同一侧。

二、LeetCode题目

给你一个非负整数 x ,计算并返回 x 的算术平方根 。
由于返回类型是整数,结果只保留整数部分 ,小数部分将被舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

提示:

  • 0 <= x <= 231 - 1

69. x 的平方根 - 力扣(LeetCode)

这道题我开始是按照二分查找的思路做的,但官方题解给出了其他的思路

袖珍计算器算法

是一种用指数函数 e x p exp exp 和对数函数 l n ⁡ ln⁡ ln 代替**平方根函数**的方法

x \sqrt{x} x 写成幂的形式 x 1 / 2 x^{1/2} x1/2 ,再使用自然对数 e e e 进行换底,即可得到

x = x 1 / 2 = ( e l n   x ) 1 / 2 = e 1 2 l n   x \sqrt{x}=x^{1/2}=(e^{ln\ x})^{1/2}=e^{\frac{1}{2}ln\ x} x =x1/2=(eln x)1/2=e21ln x

由此来估计 x \sqrt{x} x 的值

class Solution {
    public int mySqrt(int x) {
        if (x == 0) {
            return 0;
        }
        int ans = (int) Math.exp(0.5 * Math.log(x));
        return (long) (ans + 1) * (ans + 1) <= x ? ans + 1 : ans;
    }
}

打比赛可以用,面试就算了,我觉得面试官真出了这道题,应该就是想考察二分查找

class Solution {
    public int mySqrt(int x) {
        if (x <= 1) return x;
        int left = 1, right = x-1;
        while (left <= right){
            int mid = left + ((right - left) >> 1);
            if (mid > x/mid){
                right = mid - 1;
            } else if(mid < x/mid) {
                if ((mid+1) > x/(mid+1))
                    return mid;
                left = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值