算法【位图】

特别提醒:Python同学实现位运算的题目需要特别注意,需要自己去手动处理溢出和符号扩展等问题。比如:

python 复制代码
(n << shift_amount) & 0xFFFFFFFF

一、位图原理

其实就是用bit组成的数组来存放值,用bit状态1、0代表存在、不存在,取值和存值操作都用位运算。限制是必须为连续范围且不能过大。好处是极大的节省空间,因为1个数字只占用1个bit的空间。

二、位图的实现

一个位图有以下几个函数:

cpp 复制代码
// 初始化位图 只支持0~n-1所有数字的增删改查
Bitset(int n);
// 把num加入到位图
void add(int num);
// 把num从位图中删除
void remove(int num);
// 如果位图里没有num 就加入  如果位图里有num 就删除
void reverse(int num);
// 查询num是否在位图中
bool contains(int num);

代码如下。

cpp 复制代码
class Bitset
{
public:
    int *arr;
    Bitset(int n);
    ~Bitset();
    void add(int num);
    void remove(int num);
    void reverse(int num);
    bool contains(int num);
};

Bitset::Bitset(int n)
{
    // 数组大小为n/32向上取整 可写成(n+31)/32
    arr = new int[(n+31)/32];
}

Bitset::~Bitset()
{
    delete [] arr;
}

void Bitset::add(int num){
    arr[num/32] |= (1 << (num % 32));
}

void Bitset::remove(int num){
    arr[num/32] &= ~(1 << (num % 32));
}

bool Bitset::contains(int num){
    return ~((arr[num/32] & (1 << (num % 32))) == 0);
}

void Bitset::reverse(int num){
    if(contains(num)){
        remove(num);
    }else{
        add(num);
    }
}

由于是用位代表一个数是否存在,所以一个int可代表32个数,则需要的int个数为n/32向上取整。对此可用(a + b -1)/b为a/b的向上取整来计算。对于一个数num,它被哪一个int代表由num/32得到下标,而具体的位则是由num%32得到。add方法中得到具体位数直接或进去,remove方法中得到具体的位数直接与进去。

下面有一个相关测试可以检验一下,按照题目要求修改部分即可。

测试链接:https://leetcode-cn.com/problems/design-bitset/

代码如下。

cpp 复制代码
class Bitset {
public:
    // 根据数据量提前申请
    int arr[3126] = {0};
    // 是否翻转 false为没翻转 true为翻转
    bool f;
    // 记录1的个数
    int cnt;
    // 能代表多少个数
    int nums;
    Bitset(int size) {
        f = false;
        cnt = 0;
        nums = size;
    }

    void fix(int idx) {
        if(!f){
            if(((arr[idx/32] >> (idx % 32)) & 1) == 0){
                arr[idx/32] |= (1 << (idx % 32));
                cnt++;
            }
        }else{
            if(((arr[idx/32] >> (idx % 32)) & 1) == 1){
                arr[idx/32] &= ~(1 << (idx % 32));
                cnt++;
            }
        }
    }
    
    void unfix(int idx) {
        if(!f){
            if(((arr[idx/32] >> (idx % 32)) & 1) == 1){
                arr[idx/32] &= ~(1 << (idx % 32));
                cnt--;
            }
        }else{
            if(((arr[idx/32] >> (idx % 32)) & 1) == 0){
                arr[idx/32] |= (1 << (idx % 32));
                cnt--;
            }
        }
    }
    
    void flip() {
        f = !f;
        cnt = nums - cnt;
    }
    
    bool all() {
        return cnt == nums;
    }
    
    bool one() {
        return cnt != 0;
    }
    
    int count() {
        return cnt;
    }
    
    string toString() {
        string s = "";
        for(int i = 0;i < (nums + 31)/32;++i){
            int cons = nums - i * 32 < 32 ? nums - i * 32 : 32;
            for(int j = 0;j < cons;++j){
                if((!f && ((arr[i] >> j) & 1) == 1) || (f && ((arr[i] >> j) & 1) == 0)){
                    s += '1';
                }else{
                    s += '0';
                }
            }
        }
        return s;
    }
};

其中,翻转使用一个变量代表,不需要每次遍历位图实现翻转。fix和unfix方法均分为翻转和未翻转两种情况。

相关推荐
九圣残炎8 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
童先生12 分钟前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
lulu_gh_yu13 分钟前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
丫头,冲鸭!!!33 分钟前
B树(B-Tree)和B+树(B+ Tree)
笔记·算法
Re.不晚37 分钟前
Java入门15——抽象类
java·开发语言·学习·算法·intellij-idea
老秦包你会39 分钟前
Qt第三课 ----------容器类控件
开发语言·qt
凤枭香42 分钟前
Python OpenCV 傅里叶变换
开发语言·图像处理·python·opencv
ULTRA??1 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
远望清一色1 小时前
基于MATLAB的实现垃圾分类Matlab源码
开发语言·matlab
confiself1 小时前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言