【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;
    }
}
相关推荐
葫芦和十三4 小时前
图解 MongoDB 23|两地三中心:跨可用区部署怎么扛机房故障
后端·mongodb·agent
地平线开发者5 小时前
J6B vio scenario sample
算法
勇哥java实战分享6 小时前
PaddleOCR 太慢?我换成 RapidOCR 后,速度直接起飞
后端
苏三说技术11 小时前
LangChain4j 和 LangGraph4j,哪个更好?
后端
ServBay12 小时前
7 个AI开发中真正用得上的 MCP Server,配合Claude Code食用效果更佳
后端·claude·mcp
妙码生花12 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(十五):优化细节、网络请求封装
前端·后端·ai编程
用户67570498850213 小时前
Go 语言里判断字符串为空,90% 的人都写错了!
后端·go
Flittly13 小时前
【AgentScope Java新手村系列】(16)从RAG到多路检索
java·spring boot·spring