三道经典题目彻底搞懂位运算

三道题搞懂位运算

1、位运算优先级

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Jm6FcjB-1663840992615)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\1663839690903.png)]

2、题目

(1)LeetCode1386. 安排电影院座位

class Solution {
    // 采用补集的思想 先计算最多有多少座位(无占座行数 * 2) 再减去所有 有占座的座位*2 再 加上能坐的座位
    public int maxNumberOfFamilies(int n, int[][] reservedSeats) {
        //用哈希表记录被占的座位行列
         Map<Integer, Integer> hash = new HashMap<>();
         for(int[] seat: reservedSeats){
             //x 代表行 y代表列
             int x = seat[0], y = seat[1];
             if(y != 1 && y != 10)
             // 将2~9映射到0~7  用7位的二进制数表示这个位置有没有被占用,如果是1 则被占用
             // 若没有就是0 若有就是原值 | 1 << y -2
                hash.put(x, hash.getOrDefault(x, 0) | 1 << y -2);
         }

         int left = 0b11110000;
         int right = 0b00001111;
         int mid = 0b00111100;

         int res = n * 2 - hash.size() * 2;
         //entrySet()返回映射所包含的映射关系的Set集合(一个关系就是一个键-值对),就是把(key-value)作为一个整体一对一对地存放到Set集合当中。
         for(Map.Entry<Integer, Integer> entry: hash.entrySet()){
             int v = entry.getValue();
             if((v & left) == 0 || (v & right) == 0 || (v & mid) == 0)
                res ++;
         }
         return res;
    }
} 

(2)LeetCode1371. 每个元音包含偶数次的最长子字符串

思路:

aeiou一共五个字母,用二进制来表示每个字母出现的奇偶情况。用1来表示奇数个,0表示偶数个。所以一共有2^5 = 32 种情况 。可以开一个数组或哈希表记录每一种状态。
然后遍历字符串s,枚举每个字符串中的字母,利用元音字母使得每个字母对应一种状态。如果有重复的状态,用当前的下标减去第一次出现这个状态的下标取MAX即可,否则将这个状态添加到哈希表或数组中。需要注意的是,**hash[0]的值应该为-1。**因为hash[0] 表示所有的元音字母数都是偶数,上一次出现这个状态应该是第一个字母的前一个字母,所以下标为-1。

//状态压缩 + 位运算
class Solution {
    /*
    	每次记录第一次出现每种状态的下标
    */
    public int findTheLongestSubstring(String s) {
        //存储第一次出现这个状态的最小的位置(下标)
        int[] hash = new int[32]; 
        Arrays.fill(hash, -2);
        hash[0] = -1;
        String cs = "aeiou";
        int res = 0, state = 0;
        for(int i = 0; i < s.length(); i ++ ){
            int k = cs.indexOf(s.charAt(i));
            if(k != -1) state ^= 1 << k;
            if(hash[state] != -2) res = Math.max(res, i - hash[state]);
            else hash[state] = i;
        }
        return res;
    }
}

(3)LeetCode2401. 最长优雅子数组

思路:

用异或运算符和变量 state记录所有数字在位数上的 1 的出现情况,一旦出现冲突(也就是新近数字和原来的 state在同一位上出现 1)就不停地右移窗口左边界,直到删掉前方所有和新数字 nums[i] 在位数上有冲突的数字为止

小技巧:

x & y == 0 时 x | y ^ y = x

// 滑动窗口+位运算
class Solution {
    public int longestNiceSubarray(int[] nums) {
        int res = 0;
        int n = nums.length;
        for(int l = 0, r = 0, state = 0; r < n; r ++ ){
            while ((state & nums[r] )> 0)
                state ^= nums[l ++];
            state |= nums[r];
            res = Math.max(res, r - l + 1);
        }
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值