二进制 leetcode

5@TOC

背景

  • 异或^满足结合律和交换律
  • a=0 ^ a
  • 0=a ^ a
  • a=a^ b ^b
  • 交换a和b:
    a=a ^ b
    b=a ^ b
    a=a ^ b
    整理得:
    b=a ^ b ^ b=a
    a=a ^ b ^ b ^ a ^ b=a ^ a ^ b=b

只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

class Solution {
    
    
public:
    int singleNumber(vector<int>& nums) {
    
    
        int result=0;
        for(auto e:nums){
    
    
            result^=e;
        }
        return result;
    }
};

只出现一次的数字 II

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
思路: 某一位上1出现的次数除以三的余数一定是1或者0;

class Solution {
    
    
public:
    int singleNumber(vector<int>& nums) {
    
    
        int result=0;
        for(int i=0; i<32;i++){
    
    
            int sum=0;
            for(auto e:nums){
    
    
                int n=e>>i;
                int tmp=n & 1;
                sum+=tmp;
            }
            cout<<"i"<<i<<"sum"<<sum<<endl;
            result |=(sum%3)<<i;
        }
        return result;
    }
};
class Solution {
    
    
public:
    vector<int> singleNumber(vector<int>& nums) {
    
    
      int tmp_result=0;
      int tmp_result1=0;
      int tmp_result2=0;
      int i;
      vector<int> result;
      for(int e: nums){
    
    
          tmp_result^=e;
      }  
      for(i=0;i<32;i++){
    
    
          int n=tmp_result>>i;
          int tmp=n&1;
          if(tmp==1){
    
    
              break;
          }
      }
      for(int e: nums){
    
    
          int n=e>>i;
          int tmp=n&1;
          if(tmp==1){
    
    
              tmp_result1^=e;
          }else{
    
    
              tmp_result2^=e;
          }
      }
      result.push_back(tmp_result1);
      result.push_back(tmp_result2);
      return result;
    }
};

比特位计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
思路: 利用二叉树的层次遍历,左儿子比特数不变,右儿子比特数加一。

class Solution {
    
    
public:
    vector<int> countBits(int num) {
    
    

        queue<pair<int,int>> que;
        que.push(make_pair(1,1));
        vector<int> result;
        result.push_back(0);
        if (num==0){
    
    
            return result;
        }
        while(!que.empty()){
    
    
            auto tmp=que.front();
            que.pop();
            auto n=tmp.first;
            auto bit=tmp.second;
            if(n==num){
    
    
                result.push_back(bit);
                break;
            }else{
    
    
                result.push_back(bit);
                que.push(make_pair(n<<1,bit));
                que.push(make_pair((n<<1)+1,bit+1));
            }
        }
        return result;
    }
};

数字范围按位与

给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
思路: 转换为求最长公共前缀,因为某一位上不同的话后一位肯定不同

class Solution {
    
    
public:
    int rangeBitwiseAnd(int m, int n) {
    
    
        int tmp1;
        int tmp2;
        int i;
        for(i=0; i<32; i++){
    
    
            tmp1=m>>i;
            tmp2=n>>i;
            if(tmp1==tmp2){
    
    
                break;
            }
        }
        return tmp1<<i;
    }
};

剑指 Offer 56 - I. 数组中数字出现的次数

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

示例 2:

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

限制:

2 <= nums.length <= 10000

思路: 假设那两个数为a,b,异或和为x。所有数字异或和等于x,找到x中为1的那一位index,说明在index位上a,b不同。把所有数字按照index位分为两组,就转换成两个在一组数字中求一个特殊数字的问题。


class Solution {
    
    
public:
    vector<int> singleNumbers(vector<int>& nums) {
    
    
        int len=nums.size();
        int sum=0;
        int a=0;
        int b=0;
        int tmp;
        int index;
        vector<int> result;
        for(int i=0;i<len;i++){
    
    
            sum^=nums[i];
        }
        for(index=0;index<32;index++){
    
    
            if((sum>>index)&1==1){
    
    
                break;
            }
        }
        for(int i=0;i<len;i++){
    
    
            if((nums[i]>>index)&1==1){
    
    
                a^=nums[i];
            }else{
    
    
                b^=nums[i];
            }
        }
        result.push_back(a);
        result.push_back(b);
        return result;
    }
};

29. 两数相除

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

示例 1:

输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333…) = truncate(3) = 3

示例 2:

输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333…) = -2

提示:

被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231,  231 − 1]。本题中,如果除法结果溢出,则返回 231 − 1。

思路: 使用原码除法,要把每个负数转为正数,使用int表示数时,而-int_min会溢出,所以改用long。
使用补码除法虽然不用把负数转成正数,但是求余数时可能涉及int_min的减法,所以还是要用long。

class Solution {
    
    
public:
    int divide(int dividend, int divisor) {
    
    
        bool flag1=dividend>0;
        long dividendLong=dividend;
        if(!flag1){
    
    
            dividendLong=-dividendLong;
        }
        bool flag2=divisor>0;
        long divisorLong=divisor;
        if(!flag2){
    
    
            divisorLong=-divisorLong;
        }
        if(dividendLong==0 || divisorLong>dividendLong){
    
    
            return 0;
        }
        bool flag=!((flag1)^(flag2));
        int zNum1=0,zNum2=0;
        unsigned int t=1<<31;
        while(true){
    
    
            if((dividendLong & t)==t){
    
    
                break;
            }else{
    
    
                t=t>>1;
                zNum1+=1;
            }
        }
        t=1<<31;
        while(true){
    
    
            if((divisorLong & t)==t){
    
    
                break;
            }else{
    
    
                t=t>>1;
                zNum2+=1;
            }
        }
        long result=0;
        long level=zNum2-zNum1;
        long r=dividendLong;
        long y=divisorLong<<level;
        long tmp;
        for(;level>=0;level--){
    
    
            tmp=r-y;
            if(tmp>=0){
    
    
                result|=long(1)<<level;
                y=y>>1;
                r=tmp;
            }else{
    
    
                y=y>>1;
            }
        }
        if(!flag){
    
    
            result= -result;

        }
        if(result<INT_MIN){
    
    
                result=INT_MIN;
            }
        if(result>INT_MAX){
    
    
            result=INT_MAX;
        }
        cout<<1-INT_MIN;
        return result;

    }
};

猜你喜欢

转载自blog.csdn.net/weixin_39849839/article/details/107335202