本文主要记录二进制的相关LeetCode题目的实现代码,直接给出本文各个题目的答案,供有需求的读者学习或复制。

一、二进制计数

461. 汉明距离(简单难度)

class Solution {
public:
    int hammingDistance(int x, int y) {
        // 方法一:进制转换
        // int count=0;
        // if(x==y)
        //     return 0;
        // // 同时取位
        // while(x!=0||y!=0){
        //     if(x%2!=y%2)
        //         count++;
        //     x=x/2;
        //     y=y/2;
        // }
        // return count;
        // 方法二:位运算
        int count=0;
        int a=x^y;// 异或运算,相同为0,不同为1
        while(a){
            count+=a&1;// 查看最后一位是否是1
            a>>=1;// 右移1位
        }
        return  count;
    }
};

191. 位1的个数(简单难度)

剑指 Offer 15. 二进制中1的个数(简单难度)

方法一:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        string res;
        if(n==0) res="0";
        while(n>0){
            res=to_string(n%2)+res;
            n=n/2;
        }
        int num=0;
        for(char c:res){
            if(c=='1') num++;
        }
        return num;
    }
};

方法二:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while (n) {
            count += n & 1;
            n>>=1;
        }
        return count;
    }
};

338. 比特位计数(简单难度)

剑指 Offer II 003. 前 n 个数字二进制中 1 的个数(简单难度)

class Solution {
public:
    // 十进制转换为2二进制
    string ten2k(int num,int k=2){
        if(num==0) return "0";
        string ans;
        while(num){
            ans= to_string(num%k)+ans;
            num/=k;
        }
        return ans;
    }
    vector<int> countBits(int n) {
        vector<int> res;
        for(int i=0;i<=n;i++){
            string bits=ten2k(i);//二进制的字符串
            int num=0;//统计字符串中1的个数
            for(int j=0;j<bits.length();j++){
                if(bits[j]=='1') num++;
            }
            res.push_back(num);
        }
        return res;
    }
};

190. 颠倒二进制位(简单难度)

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        uint32_t rev = 0;
        int power=31;
        while(n){
            rev+=(n&1)<<power;//左移32位
            n>>=1;
            power--;
        }
        return rev;
    }
};

二、二进制转换

1290. 二进制链表转整数(简单难度)

class Solution {
public:
    // 二进制转十进制
    int getDecimalValue(ListNode* head) {
        vector<int> arr;
        // 将链表元素加入数组中
        ListNode* p=head;
        while(p){
            arr.push_back(p->val);
            p=p->next;
        }
        // 二进制转换为十进制
        int n=arr.size();
        int k=1;
        int sum=0;
        for(int i=n-1;i>=0;i--){
            sum+=arr[i]*k;
            k*=2;
        }
        return sum;
    }
};

693. 交替位二进制数(简单难度)

class Solution {
public:
    string ten2k(int n,int k=2){
        if(n==0) return "0";
        string res;
        while(n>0){
            res=to_string(n%k)+res;
            n=n/k;
        }
        return res;
    }
    bool hasAlternatingBits(int n) {
        string kbit=ten2k(n);
        char flag='0';
        for(int i=1;i<kbit.length();i++){
            if(kbit[i]==kbit[i-1]) return false;
        }
        return true;
    }
};

1009. 十进制整数的反码(简单难度)

476. 数字的补数(简单难度)

class Solution {
public:
    string ten2k(int n,int k=2){
        if(n==0) return "0";
        string res;
        while(n>0){
            res=to_string(n%k)+res;
            n=n/k;
        }
        return res;
    }
    int k2ten(string n,int k=2){
        int sum=0;
        long a=1;// 注意,必须为整型
        for(int i=n.length()-1;i>=0;i--){
            sum+=(n[i]-'0')*a;
            a*=k;
        }
        return sum;
    }
    int bitwiseComplement(int num) {
        string kbit = ten2k(num);//10进制转换为二进制
        string res="";
        for(char c:kbit){
            if(c=='1'){
                res+='0';
            }
            else {
                res+='1';
            }
        }
        int n=k2ten(res);
        return n;
    }
};

三、非二进制转换

504. 七进制数(简单难度)

class Solution {
public:
    string convertToBase7(int num) {
        if(num==0) return "0";
        string res;
        // 处理正数
        int tempNum=abs(num);//如果num为负数,变为正数
        while(tempNum>0){
            res=to_string(tempNum%7)+res;
            tempNum=tempNum/7;
        }
        if(num<0) res.insert(res.begin(),'-');
        return res;
    }
};

405. 数字转换为十六进制数(简单难度)

class Solution {
public:
    string toHex(int n) {
        if(n==0) return "0";
        unsigned num = n;//转换为无符号
        string res;
        while(num>0){
            int base=num%16;
            char c='0';
            if(base>9) {
                c=base-10+'a';
            }else{
                c=base+'0';
            }
            res+=c;
            num=num/16;
        }
        reverse(res.begin(),res.end());
        return res;
    }
};

171. Excel 表列序号(简单难度)

​ 这道题要求将Excel 表中的26个的由大写字母组成的列名称转换成相对应的列序号,因此本质就是一道26进制转换为10进制的题目,但是这道题与标准的进制转换(0-25)不同,因为Excel表的列序号是1到26,需要特殊处理。

class Solution {
public:
    int titleToNumber(string columnTitle) {
        int sum=0;
        long k=1;//幂,幂要设置为long
        for(int i=columnTitle.length()-1;i>=0;i--){
            sum+=(columnTitle[i]-'A'+1)*k;
            k*=26;
        }
        return sum;
    }
};

168. Excel表列名称(简单难度)

class Solution {
public:
    string convertToTitle(int n) {
        // 10进制转26进制的模板,正常26进制是0-25,该题是1-26,
        string res="";
        while(n>0){
            --n;//每一位都多了1,此处-1使其可以用正常的26进制代码处理
            res+=n%26+'A';//将数字字符转换为大写字母字符,'A'是65,'0'是48
            n=n/26;
        } 
        reverse(res.begin(),res.end());//反转序列
        return res;
    }
};

四、数位分离

1281. 整数的各位积和之差(简单难度)

class Solution {
public:
    int subtractProductAndSum(int n) {
        int sum=0;
        int x=1;
        while(n>0){
            sum+=n%10;
            x*=n%10;
            n=n/10;
        }
        return x-sum;
    }
};

258. 各位相加(简单难度)

class Solution {
public:
    int addDigits(int num) {
        while(num>=10)// 大于等于1位数
        {
            int sum=0;
            while(num>0){
                sum+=num%10;
                num=num/10;
            };
            num=sum;
        }
        return num;
    }
};

1945. 字符串转化后的各位数字之和(简单难度)

class Solution {
public:
    int getLucky(string s, int k) {
        // 转换成数字
        string str="";
        for(int i=0;i<s.length();i++){
            int num=s[i]-'0'-48;
            str+=to_string(num);
        }
        // 重复转换操作k次
        int sum=0;
        while(k)// 
        {
            sum=0;
            for(int i=0;i<str.length();i++){
                sum+=str[i]-'0';
            }
            str=to_string(sum);
            k--;
        }
        return sum;
    }
};

1837. K 进制表示下的各位数字总和(简单难度)

class Solution {
public:
    int sumBase(int n, int k) {
        // 从10进制转换为k进制
        string kbits="";
        if(n==0) kbits="0";
        while(n>0){
            kbits=to_string(n%k)+kbits;
            n=n/k;
        }
        // 各位累和
        int sum=0;
        for(char c:kbits) sum+=c-'0';
        return sum;
    }
};

五、数组中元素出现的次数

1、一个数出现1次,其余数都出现2次

136. 只出现一次的数字(简单难度)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        // 方法一:位运算
        // 数组中一定有奇数个元素,数组中的全部元素进行异或运算,结果即为只出现一次的数字
        // int res=0;
        // for(int num:nums) res^=num;
        // return res;
        // 方法二:位运算
        int res=0;
        for(int i=0;i<32;i++){
            int mask=1<<i;//从右向左取第i位
            int cnt = 0;//第i位出现的次数
            // 遍历整个数组后的第i位出现了几次1
            for (int num:nums) {
                if ((num & mask) != 0) {
                    cnt++;
                }
            }
            // 如果第i位没有出现3次则保留
            if (cnt % 2 != 0) {
                res |= mask;
            }
        }
        return res;
        // // 方法二:哈希法
        // unordered_map<int,int> map;// 数字和出现次数
        // // 遍历数组一遍统计频率
        // for(int num:nums){
        //     map[num]++;
        // }
        // // 遍历哈希表
        // for(auto it=map.begin();it!=map.end();++it){
        //     if(it->second==1)
        //         return it->first;
        // }
        // return -1;
    }
};

2、一个数出现1次,其余数都出现3次

137. 只出现一次的数字 II(中等难度)

剑指 Offer 56 - II. 数组中数字出现的次数 II(中等难度)

剑指 Offer II 004. 只出现一次的数字(中等难度)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        // 方法一:位运算(异或)
        // int ones=0;twos=0;
        // for(int num:nums){
        //     ones=ones^num&(~twos);//x & ~x = 0;// num,0,0
        //     twos=twos^num&(~ones);//x & ~0 = x;// 0,num,0
        // }
        // return ones;
        // 方法二:位运算
        int res=0;
        for(int i=0;i<32;i++){
            int mask=1<<i;//从右向左取第i位
            int cnt = 0;//第i位出现的次数
            // 遍历整个数组后的第i位出现了几次1
            for (int num:nums) {
                if ((num & mask) != 0) {
                    cnt++;
                }
            }
            // 如果第i位没有出现3次则保留
            if (cnt % 3 != 0) {
                res |= mask;
            }
        }
        return res;
        // 方法二:哈希法
        // unordered_map<int,int> map;// 数字和出现次数
        // // 遍历数组一遍统计频率
        // for(int num:nums){
        //     map[num]++;
        // }
        // // 再次遍历遍历字符串
        // for(int num:nums){
        //     if(map[num]==1)
        //         return num;
        // }
        // return -1;
    }
};

3、两个数出现1次,其余数都出现2次

260. 只出现一次的数字 III(中等难度)

剑指 Offer 56 - I. 数组中数字出现的次数(中等难度)

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        vector<int> res(2,0);
        int aob=0;
        for(int num:nums){
            aob^=num;
        }
        // 取出最后一位
        int lastBit = (aob == INT_MIN ? aob : aob & (-aob));// 防止溢出
        for (int num : nums) {
            // 分成2个数
            if ((lastBit & num) != 0) 
                res[0] ^= num;
            else 
                res[1] ^= num;
            
        }
        return res;
    }
};

六、四则运算

1、两数加法

剑指 Offer 64. 求1+2+…+n

class Solution {
public:
    int sumNums(int n) {
        if(n==0) return 0;
        return n+sumNums(n-1);
    }
};

371. 两整数之和(简单难度)

剑指 Offer 65. 不用加减乘除做加法(简单难度)

面试题 17.01. 不用加号的加法(简单难度)

class Solution {
public:
    int getSum(int a, int b) {
        // 当进位部分不为0,说明需要继续加
        while (a != 0) {
            int temp = a ^ b;//非进位部分(没有添加进位部分),按位异或,
            //异或这里可看做是相加但是不显现进位,比如5 ^ 3
                 /*0 1 0 1
                   0 0 1 1
                 ------------
                   0 1 1 0   */
            a = ((unsigned int)a & b) << 1; //进位部分,都是1是发生进位,对有符号左移的溢出保护处理
            //相与为了让进位显现出来,比如5 & 3
                /* 0 1 0 1
                   0 0 1 1
                 ------------
                   0 0 0 1
              上面的最低位1和1相与得1*/
            b = temp;
        }
        return b;
    }
};

67. 二进制求和(简单难度)

剑指 Offer II 002. 二进制加法(简单难度)

class Solution {
public:
    string addBinary(string a, string b) {
        string res;
        // 从右向左同时遍历2个可能不等长的字符串
        int i=a.length()-1;
        int j=b.length()-1;
        bool carry=false;
        int sum=0;
        while(i>=0||j>=0){
            sum=0;
            if(i>=0) sum+=a[i--]-'0';
            if(j>=0) sum+=b[j--]-'0';
            if(carry) sum+=1;
            res =to_string(sum%2)+res;
            carry=sum>=2?true:false;
        }
        // 如果有多余的进位
        if(carry) res =to_string(1)+res;
        return res;
    }
};

2、两数除法

29. 两数相除(中等难度)

剑指 Offer II 001. 整数除法(简单难度)

class Solution {
public:
    /* 被除数÷除数=商...余数,进而推导得出:商×除数+余数=被除数
    思路:找到一个足够大的数x,x足够接近商,使得x*除数<=被除数,即(被除数/x)>=除数(x必须为正数)
    因为不可以使用*和/,就只可使用位移,计算机在做位移时效率特别高,向左移1相当于乘以2,向右位移1相当于除以2
    (被除数/x)>=除数(x必须为正数),可以表示为(被除数>>i)>=除数,x=2^i,因为x足够大,所以i应该从最大值不断减少
    i的取值范围为[0,31],注意:被除数和除数都需要转换为unsigned int
    以100/3为例,x=2^n是1,2,4,8...2^31这种数
    当n=31时,x特别大,100/2^n是一个很小的数,肯定是小于3的,所以循环下来,
    当n=5时,x=32,100/32=3, 刚好是大于等于3的,说明真正的商res>=x,我们可以先res+=x;
    将100-32*3=4,此时被除数变为了4,接下来继续处理4:
    当n=0时,x=1,4/1=4,刚好大于等于3,说明res+=1,被除数4-1*3=1,此时n已到最小值,结束商res=33
    这其中得处理一些特殊的数,比如divisor是不能为0的,INT_MIN和INT_MAX*/
    int divide(int dividend, int divisor) {
        if(dividend==0) return 0;// 被除数为0,直接返回0
        if (dividend==INT_MIN &&divisor==-1) return INT_MAX;// 被除数是最小值,除数是-1,返回最大值
        bool negative=(dividend^divisor)<0;//用异或来计算是否符号相异
        // 将有符号整数转为无符号整数
        unsigned int t = abs(dividend);//被除数
        unsigned int d = abs(divisor);// 除数
        unsigned int res = 0;// 商
        // i从大到小,商从小到大
        for (int i = 31; i >= 0; i--) {
            // 计算t除于2^i的商
            if((t>>i)>=d) {//找出足够大的数2^n*divisor
                res+=((unsigned int)1)<<i;//商>=1*2^n
                t-= d<<i;//将被除数-2^n*divisor
            }
        }
        //特殊数不能将unsigned int转为int
        if(res == INT_MIN) return INT_MIN;
        else return negative?-(int)res:(int)res;//符号相异取反
    }
};

####