【LeetCode精选算法】位运算专题

目录

[1. 判断字符是否唯一(面试题 01.01)](#1. 判断字符是否唯一(面试题 01.01))

解题思路

[Java 代码](#Java 代码)

[2. 丢失的数字(268)](#2. 丢失的数字(268))

解题思路

[Java 代码](#Java 代码)

[3. 两整数之和(371)](#3. 两整数之和(371))

解题思路

[Java 代码](#Java 代码)

[4. 只出现一次的数字 II(137)](#4. 只出现一次的数字 II(137))

解题思路

[Java 代码](#Java 代码)

[5. 消失的两个数字(面试题 17.19)](#5. 消失的两个数字(面试题 17.19))

解题思路

[Java 代码](#Java 代码)


1. 判断字符是否唯一(面试题 01.01)

解题思路
  • 利用鸽巢原理优化:若字符串长度大于 26(小写字母总数),直接返回 false。
  • 位图思想:用一个 int 类型变量(32 位)充当哈希表,每个比特位对应一个小写字母。比特位为 0 表示字符未出现,为 1 表示已出现。
  • 遍历字符串时,通过字符与 'a' 的差值确定对应比特位,先判断该比特位是否为 1(已出现),若否则将该比特位置为 1。
Java 代码
java 复制代码
class Solution {
    public boolean isUnique(String astr) {
        // 利用鸽巢原理来做的优化
        if (astr.length() > 26) return false;
        
        int bitMap = 0;
        for (int i = 0; i < astr.length(); i++) {
            int x = astr.charAt(i) - 'a';
            // 先判断字符是否在位图中
            if (((bitMap >> x) & 1) == 1) return false;
            // 把当前字符加入到位图中
            bitMap |= 1 << x;
        }
        return true;
    }
}

2. 丢失的数字(268)

解题思路
  • 设数组大小为 n,完整范围是 [0, n],数组是该范围缺失一个数后的序列。
  • 利用异或运算的 "消消乐" 特性:相同数字异或结果为 0,0 与任意数字异或结果为该数字。
  • 将数组中所有元素与 [0, n] 中所有数字逐一异或,最终结果即为缺失的数字。
Java 代码
java 复制代码
class Solution {
    public int missingNumber(int[] nums) {
        int ret = 0;
        for (int x : nums) ret ^= x;
        for (int i = 0; i <= nums.length; i++) ret ^= i;
        return ret;
    }
}

3. 两整数之和(371)

解题思路
  • 异或(^)运算本质是 "无进位加法",可得到两数相加不考虑进位的结果。
  • 按位与(&)运算可得到两数相加产生进位的位置,左移 1 位后即为进位值。
  • 循环执行 "无进位加法" 和 "计算进位" 操作,直到进位值为 0,此时的无进位加法结果即为最终和。
Java 代码
java 复制代码
class Solution {
    public int getSum(int a, int b) {
        while (b != 0) {
            int x = a ^ b; // 先算出无进位相加的结果
            int carry = (a & b) << 1; // 计算进位
            a = x;
            b = carry;
        }
        return a;
    }
}

4. 只出现一次的数字 II(137)

解题思路
  • 数组中除目标元素外,其余元素均出现三次,目标元素仅出现一次。
  • 统计所有数字每个比特位上 1 的总和,总和对 3 取余,结果为 1 则说明目标元素该比特位为 1,否则为 0。
  • 遍历 32 位整数的每一位,按上述规则还原目标元素的每一位,最终得到目标元素。
Java 代码
java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        int ret = 0;
        for (int i = 0; i < 32; i++) { // 依次修改 ret 中的每一个比特位
            int sum = 0;
            for (int x : nums) { // 统计 nums 中所有的数的第i位的和
                if (((x >> i) & 1) == 1) {
                    sum++;
                }
            }
            sum %= 3;
            if (sum == 1) {
                ret |= 1 << i;
            }
        }
        return ret;
    }
}

5. 消失的两个数字(面试题 17.19)

解题思路
  • 结合 "丢失的数字" 和 "只出现一次的数字 III" 的思路:先将数组元素与 [1, n+2](n 为数组长度)的所有数字异或,得到两个消失数字的异或结果(其余数字均出现两次,异或后抵消)。
  • 找到异或结果中任意一个为 1 的比特位(该位表示两个消失数字在该位上的值不同)。
  • 根据该比特位将所有数字(数组元素 +[1, n+2])分为两组,每组内仅包含一个消失数字,分别对两组异或,得到两个消失数字。
Java 代码
java 复制代码
class Solution {
    public int[] missingTwo(int[] nums) {
        // 1. 先把所有的数异或在一起
        int tmp = 0;
        for (int x : nums) tmp ^= x;
        for (int i = 1; i <= nums.length + 2; i++) tmp ^= i;
        
        // 2. 找出a,b两个数比特位不同的那一位
        int diff = 0;
        while (true) {
            if (((tmp >> diff) & 1) == 1) break;
            else diff++;
        }
        
        // 3. 将所有的数按照diff位不同,分两类异或
        int[] ret = new int[2];
        for (int x : nums) {
            if (((x >> diff) & 1) == 1) ret[1] ^= x;
            else ret[0] ^= x;
        }
        for (int i = 1; i <= nums.length + 2; i++) {
            if (((i >> diff) & 1) == 1) ret[1] ^= i;
            else ret[0] ^= i;
        }
        return ret;
    }
}
相关推荐
强化试剂1 小时前
Ergosterol-PEG-Biotin,麦角甾醇PEG生物素在生物偶联中的关键应用
jvm·intellij-idea·mybatis·nio
源代码•宸1 小时前
Leetcode—102. 二叉树的层序遍历【中等】
经验分享·后端·算法·leetcode·职场和发展·golang·slice
工程师老罗1 小时前
Pytorch自定义数据集的用法
开发语言·pytorch·python
OnYoung1 小时前
设计模式在C++中的实现
开发语言·c++·算法
曹牧1 小时前
Java:代理转发配置Nginx
java·开发语言·nginx
好学且牛逼的马1 小时前
【Hot100|20-LeetCode 240. 搜索二维矩阵 II 】
linux·算法·leetcode
foundbug9991 小时前
利用MATLAB计算梁单元刚度矩阵并组装成总体刚度矩阵
开发语言·matlab·矩阵
洋不写bug2 小时前
JavaEE基础,计算机是如何工作的
java·java-ee·状态模式
码农水水2 小时前
小红书Java面试被问:mTLS(双向TLS)的证书验证和握手过程
java·开发语言·数据库·redis·python·面试·开源