wuxin0011`blog wuxin0011`blog
首页
  • 基础内容

    • HTML
    • CSS
    • JavaScript
  • 进阶

    • JavaScript教程
    • ES6 教程
    • Vue
    • React
    • Typescript
    • Git
  • 推荐阅读
  • java随笔
  • JVM (opens new window)
  • 分类
  • 标签
  • 归档
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • git使用
  • docker部署项目
  • 错误收集
  • github-start
  • background-color
  • live-server
  • tampermonkey-script (opens new window)
  • leetcode-tool (opens new window)
  • 网站
  • 前端
  • 后端
  • Github Topic (opens new window)
GitHub (opens new window)

wuxin0011

懂得越多,懂得越少
首页
  • 基础内容

    • HTML
    • CSS
    • JavaScript
  • 进阶

    • JavaScript教程
    • ES6 教程
    • Vue
    • React
    • Typescript
    • Git
  • 推荐阅读
  • java随笔
  • JVM (opens new window)
  • 分类
  • 标签
  • 归档
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
  • git使用
  • docker部署项目
  • 错误收集
  • github-start
  • background-color
  • live-server
  • tampermonkey-script (opens new window)
  • leetcode-tool (opens new window)
  • 网站
  • 前端
  • 后端
  • Github Topic (opens new window)
GitHub (opens new window)
  • 学习

  • 面试

  • 心情杂货

  • 实用技巧

    • 2分钟规则
    • 位运算相关总结
      • 集合基本概念
      • 集合与位运算
      • 其他操作
        • 检查单独出现
        • 获取1出现的个数
        • 获取最低位
        • 获取最高位
        • 更多技巧
      • 相关例题
        • 第一个出现两次字母 easy
        • 至少出现一次的数字 hard
  • 友情链接
  • 更多
  • 实用技巧
wuxin0011
2024-02-02
目录

位运算相关总结

#

# 集合基本概念

术语 集合 位运算 举例1 举例2
交集 A∩B a&b {0,2,3} ∩ {0,1,2} = {0,2} 1101 & 0111 = 0101
并集 A∪B a ∣ b {0,2,3} ∪ {0,1,2} = {0,1,2,3} 1101 | 0111 = 1111
对称差 A Δ B a⊕b {0,2,3} Δ {0,1,2} = {1,3} 1101 ⊕ 0111 = 1111
差 A∖B a&∼b {0,2,3} \ {1,2} = {0,3} 1101 & 0111 = 1001
差(子集) A∖B (B ⊆ A) a⊕b {0,2,3} \ {0,2} = {3} 1101 ⊕ 0101 = 1000
包含于 A⊆B a&b=a a ∣ b=b {0,2} ⊆ {0,2,3} 0101 & 1101 = 0101 , 0101 | 1101 = 1101

其中 & 表示按位与,∣ 表示按位或,⊕ 表示按位异或,∼ 表示按位取反。

# 集合与位运算

S 为集合 i 为元素

术语 集合 位运算 举例1 举例2
空集 ∅ 0
单元素集合 {i} 1<<i {2} 1<<2
全集 {0,1,2,...,n-1} (1<<n)-1 {0,1,2,3} (1<<4)-1
补集 ∁U**S=U∖S ~s
属于 i∈S (s>>i)&1 == 1 2∈ {0,1,2,3} 1111>>2&1 = 1
不属于 i∈/ s (s>>i)&1 == 0 4∈/ {0,1,2,3} 1111>>4&1 = 0
添加元素 S∪{i} s ∣ (1 << i) {0,3}∪{2} 1001 ∣ (1 << 2)
删除元素 S∖{i} s&∼(1 << i) {0,2,3}∖{2} 1101&∼(1 << 2)
删除元素 S∖{i} (i∈S) s⊕(1 << i) {0,2,3}∖{2} 1101⊕(1 << 2)
获取最低位 i & ~i
删除最小元素 s&(s−1) 1110 & (1110 - 0001) = 1100

其中 & 表示按位与,∣ 表示按位或,⊕ 表示按位异或,∼ 表示按位取反。

# 其他操作

# 检查单独出现

a ^ a = 0
a ^ 0 = a
1
2

因此有相关定义

假设集合S中其他元素都出现了偶数次,只有元素a出现了一次,请找出a

public static void check() {
    int[] arr = {1,1,2,2,3,4,3,6,6};
    int ans = arr[0];
    for(int i =1;i<arr.length;i++) {
        ans ^= arr[i];
        // 出现偶数次根据上面定义会被自己消除
        // 最后只剩小 0 和 a
        // 因此 能找到 a
    }
    System.out.println("ONE = " + ans);
}
1
2
3
4
5
6
7
8
9
10
11

# 获取1出现的个数

// 普通实现方式
public static int bitCount(int i) {
    int cnt = 0;
    while (i != 0) {
        i &= i - 1;
        cnt++;
    }
    return cnt;
}


// JDK Integer类 实现方式 当然看不懂了,不过效率肯定比while方式快!
public static int bitCount(int i) {
    // HD, Figure 5-2
    i = i - ((i >>> 1) & 0x55555555);
    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
    i = (i + (i >>> 4)) & 0x0f0f0f0f;
    i = i + (i >>> 8);
    i = i + (i >>> 16);
    return i & 0x3f;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 获取最低位

// 可以参见 JDK Integer类 源码
public static int lowestOneBit(int i) {
    return i & -i;
}
1
2
3
4

# 获取最高位

// 可以参见 JDK Integer类 源码
public static int highbit(int i) {
    i |= (i >>  1);
    i |= (i >>  2);
    i |= (i >>  4);
    i |= (i >>  8);
    i |= (i >> 16);
    i -= (i >>> 1)
    return i ;
}
1
2
3
4
5
6
7
8
9
10

# 更多技巧

low-tips

# 相关例题

  • 只出现一次的数字 (opens new window)

  • 只出现一次的数字 II (opens new window)

  • 只出现一次的数字 III (opens new window)

  • 第一个出现两次的字母 (opens new window)

  • 至少有 1 位重复的数字 (opens new window)

# 第一个出现两次字母 easy

思路分析

  • 字符串的字符本质是数字 可以使用 s>>i&1 == 1 判断是否出现 对于不存在i的添加 s |= 1<<i
public char repeatedCharacter(String s) {
    int mask = 1 << (s.charAt(0) - '0');
    for(int i = 1;i<s.length();i++){
        int idx =  s.charAt(i) - '0';
        if( (mask >> idx & 1) == 0){
            mask |= 1 << idx;
            continue;
        } 
        return s.charAt(i);
    }
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12

# 至少出现一次的数字 hard

思路分析

  • 至少出现一次的数字 = 总数 - 枚举一次都没有出现的重复数字
  • 动态规划当前位数
  • 注意非数字的特殊情况
class Solution {
    char[] nums;
    int[][] dp;
    public int numDupDigitsAtMostN(int n) {
        this.nums = String.valueOf(n).toCharArray();
        this.dp = new int[nums.length][1<<10];
        for(int i = 0;i<nums.length;i++) Arrays.fill(dp[i],-1);
        return n - dfs(0,0,true,false);
    }

    public int dfs(int idx,int mask,boolean isLimit,boolean isNumber){
        if( idx == nums.length ) {
            return isNumber ? 1 : 0;
        }
        if( !isLimit && isNumber && dp[idx][mask] != -1 ) return dp[idx][mask];
        int ans = 0;
        if( !isNumber){
            ans = dfs(idx + 1,mask,false,false);
        }
        int up = isLimit ? nums[idx] - '0' : 9;
        for(int di = isNumber ? 0 : 1;di<=up;di++){
            if( ( (mask>>di) & 1) == 0){
                ans += dfs(idx+1,mask | (1 << di),isLimit && up == di,true);
            }
        }
        if( !isLimit && isNumber) dp[idx][mask] = ans;
        return ans;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

参考链接

  • 从集合论到位运算,常见位运算技巧分类总结! (opens new window)
编辑 (opens new window)
#位运算
上次更新: 2024-05-21, 09:50:09
2分钟规则
友情链接

← 2分钟规则 友情链接→

最近更新
01
LeetCode刷题工具之本地对拍
04-04
02
sublime对应语言模板使用技巧
02-28
03
经典字符串匹配算法
02-05
更多文章>
Theme by Vdoing | Copyright © 2020-2024 wuxin0011 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式