目录
[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;
}
}