当前位置: 首页 > article >正文

算法必刷系列之位运算

位运算

位运算既能在某些条件下提升运算速度,又能在某些条件下节省运算内存。计算机底层涉及大量位运算,位运算可以替代加加减乘除。位运算的基本运算单元是bit,相比于整数的int占据四个字节,大量节约运算空间,适用于海量数据处理

位1的个数

leetcode191
通过1移位并与给出的数字进行与运算判断对应位置是否位1

public int hammingWeight(int n) {
    int count = 0;
    for(int i=0;i<32;i++){
        int res = n&(1<<i);
        if(res!=0){
            count++;
        }
    }
    return count;
}

比特位计数

leetcode338
将某个数字与该数字减1的数字进行与运算,可以使该数字的最后一个为1的bit位变为0,重复操作,直至该数字为0,操作次数就是bit位1的个数

public int[] countBits(int n) {
    int[] counts = new int[n+1];
    for(int i=0;i<n+1;i++){
        counts[i] = count(i);
    }
    return counts;
}

public int count(int n){
    int count = 0;
    while(n!=0){
        n=n&(n-1);
        count++;
    }
    return count;
}

颠倒32位无符号整数

leetcode190
不断从无符号整数的末尾取比特位,左移31-对应位置,遍历结束之后,完成反转

public int reverseBits(int n) {
    int reverseN = 0;
    for(int i=0;i<32;i++){
        int res = n&(1<<i);
        if(res!=0){
            reverseN += (1<<(31-i));
        }
	}
}  

两整数之和

leetcode371
通过与运算计算进位,通过亦或运算进行不包括进位的加法,然后再将进位相加,重复这个过程,直至进位为0

public int getSum(int a, int b) {
     while(b!=0){
         int sign = (a&b)<<1;
         a=a^b;
         b=sign;
     }
     return a;
}

递归乘法

leetcode08.05
通过将乘数中较小的数字拆分成2的n次方的形式,并通过移位运算实现乘法,之所以选择较小的乘数是因为运算次数少

public int multiply(int A, int B) {
    int res = 0;
    int min = Math.min(A,B);
    int max = Math.max(A,B);
    for(int i=0;i<32;i++){
        int temp = min&(1<<i);
        if(temp!=0){
            res+=(max<<i);
        }
    }
    return res;
}

4KB内存寻找重复元素

给定一个数组,数组中包含N个数字,N最大为32000,数组中存在重复数字,且N的大小不确定,要求用4KB内存实现输出数组中的所有重复数字

32000个数字使用int类型存储,内存是肯定大于4KB的。我们可以考虑使用bit数组来实现,数组的下标代表数字,bit位为0代表没有出现,bit位为1代表已经出现,进行输出

public class Bit {
    public void checkDuplicates(int[] array){
        BitSet bs = new BitSet(32000);
        for (int i = 0; i < array.length; i++) {
            int num = array[i];
            int num0 = num-1;
            if(bs.get(num0)){
                System.out.println(num);
            }else {
                bs.set(num0);
            }
        }
    }
}

class BitSet {
    int[] bitSet;

    public BitSet(int size) {
        this.bitSet = new int[size >> 5];
    }

    boolean get(int pos) {
        int wordNumber = pos >> 5;
        int bitNumber = pos & 0x1F;
        return (bitSet[wordNumber]&(1<<bitNumber))!=0;
    }
    
    void set(int pos){
        int wordNumber = pos >> 5;
        int bitNumber = pos & 0x1F;
        bitSet[wordNumber] |= (1<<bitNumber);
    }
}

http://www.kler.cn/a/135276.html

相关文章:

  • 第三十一天|贪心算法| 56. 合并区间,738.单调递增的数字 , 968.监控二叉树
  • 穿越数据迷宫:C++哈希表的奇幻旅程
  • CTF攻防世界小白刷题自学笔记13
  • Ubuntu 的 ROS 操作系统安装与测试
  • 编写红绿起爆线指标(附带源码下载)
  • pySpark乱码
  • 深度学习系列53:mmdetection上手
  • 目标检测标注工具AutoDistill
  • RK3588平台开发系列讲解(项目篇)嵌入式AI的学习步骤
  • UML统一建模语言
  • rk3588编译lunch出错
  • 广州华锐互动VRAR:利用VR开展刑事案件公安取证培训,沉浸式体验提升实战能力
  • 第十一周任务总结
  • mysql无法访问故障排除步骤
  • 【Zabbix】Zabbix Agent 2在Ubuntu/Debian系统上的安装
  • 事务隔离级别和MVCC
  • 【开题报告】基于uni-app的汽车租赁app的设计与实现
  • NOSQL----redis的安装和基础命令
  • 使用Dockerfile构建hexo博客镜像,并部署
  • [Linux版本Debian系统]安装cuda 和对应的cudnn以cuda 12.0为例
  • Toolformer论文阅读笔记(简略版)
  • java中的深度复制和浅复制的BUG
  • Linux常见命令手册
  • NVS 错误码对应的原因
  • C# Winform围棋棋盘
  • 音视频项目—基于FFmpeg和SDL的音视频播放器解析(十四)