算法【位图】

特别提醒: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方法均分为翻转和未翻转两种情况。

相关推荐
NAGNIP5 小时前
大模型框架性能优化策略:延迟、吞吐量与成本权衡
算法
美团技术团队6 小时前
LongCat-Flash:如何使用 SGLang 部署美团 Agentic 模型
人工智能·算法
Fanxt_Ja11 小时前
【LeetCode】算法详解#15 ---环形链表II
数据结构·算法·leetcode·链表
侃侃_天下11 小时前
最终的信号类
开发语言·c++·算法
茉莉玫瑰花茶11 小时前
算法 --- 字符串
算法
博笙困了11 小时前
AcWing学习——差分
c++·算法
NAGNIP11 小时前
认识 Unsloth 框架:大模型高效微调的利器
算法
NAGNIP11 小时前
大模型微调框架之LLaMA Factory
算法
echoarts11 小时前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Python技术极客11 小时前
一款超好用的 Python 交互式可视化工具,强烈推荐~
算法