03-位图

1. BitMap

  • 一个数在BitMap是否存在
/**
 * 位图
 * 集合太占用空间,存一个数占用4字节
 */
public class _01_BitMap {

    // 这个类的实现是正确的
    public static class BitMap {
        // long 8字节,64位
        private final long[] bits;

        /**
         * BitMap
         */
        public BitMap(int max) {
            // (max + 64) >> 6  ->  (max + 64) / 64
            bits = new long[(max + 64) >> 6];
        }

        public void add(int num) {
            // **出错啦!!!1是4字节,32位。1L是8字节,64位**
            // num >> 6 -> num / 64 -> 哪个整数
            // num % 64 -> num & 63
            bits[num >> 6] |= (1L << (num & 63));
        }

        public void delete(int num) {
            bits[num >> 6] &= ~(1L << (num & 63));
        }

        public boolean contains(int num) {
            return (bits[num >> 6] & (1L << (num & 63))) != 0;
        }
    }

    public static void main(String[] args) {
        System.out.println("测试开始!");
        int max = 10_000;
        BitMap bitMap = new BitMap(max);
        // hash表
        HashSet<Integer> set = new HashSet<>();
        int testTime = 10_000_000;
        for (int i = 0; i < testTime; i++) {
            int num = (int) (Math.random() * (max + 1));
            double decide = Math.random();
            if (decide < 0.333) {           // 1/3概率加一个数
                bitMap.add(num);
                set.add(num);
            } else if (decide < 0.666) {    // 1/3概率删一个数
                bitMap.delete(num);
                set.remove(num);
            } else {                        // 1/3概率查一个数
                if (bitMap.contains(num) != set.contains(num)) {
                    System.out.println("Oops!");
                    break;
                }
            }
        }
        // 全查一遍,比对
        for (int num = 0; num <= max; num++) {
            if (bitMap.contains(num) != set.contains(num)) {
                System.out.println("Oops!");
            }
        }
        System.out.println("测试结束!");
    }

}









 






 






 



 



 






 







 


 


 















2. 加-减-乘-除

  • (2 + 6) => (0 1 1 0) + (0 0 1 0)
    • a ^ b => 无进位相加
    • (a & b) << 1 => 进位信息
/**
 * 位运算(int) + - * /
 * https://leetcode.com/problems/divide-two-integers
 */
public class _02_BitAddMinusMultiDiv {

    /**
     * (a + b)原理
     * 位运算不能出现 + 号,因此把b递归为0
     * <p>
     * 0 1 1 0
     * 0 0 1 0
     * ----------------
     * 0 1 0 0
     * 0 1 0 0
     * ----------------
     * 0 0 0 0
     * 1 0 0 0
     * ----------------
     * 1 0 0 0
     * 0 0 0 0
     */
    public static int add(int a, int b) {
        int sum = a;
        // 什么进位信息为0,a即为结果
        while (b != 0) {
            sum = a ^ b;        // 无进位相加
            b = (a & b) << 1;   // 进位
            a = sum;
        }
        return sum;
    }

    /**
     * (-a)原理
     */
    public static int negNum(int n) {
        return add(~n, 1);
    }

    /**
     * (a - b)原理
     */
    public static int minus(int a, int b) {
        return add(a, negNum(b));
    }

    /**
     * (a * b)原理。支持负数,原理相对复杂(略)
     * 竖式运算
     * 支持负数
     * <p>
     * 0 0 0 1 1 0
     * 0 0 0 1 1 1
     * ----------------
     * 0 0 0 1 1 0
     * 0 0 1 1 0
     * 0 1 1 0
     * ----------------
     * 0 1 1 1 1 0
     */
    public static int multi(int a, int b) {
        int res = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                res = add(res, a);
            }
            a <<= 1;
            b >>>= 1;
        }
        return res;
    }

    /**
     * negative
     * 判断是否是负数
     */
    public static boolean isNeg(int n) {
        return n < 0;
    }

    /**
     * div
     * <p>
     * 0 1 1 1 1 0
     * 0 0 0 1 1 1
     * <p>
     * ----------------
     * 0 1 1 1 0 0
     * 0 0 0 0 1 0
     */
    public static int div(int a, int b) {
        // 负数 -> 正数 => 取绝对值
        int x = isNeg(a) ? negNum(a) : a;
        int y = isNeg(b) ? negNum(b) : b;
        int res = 0;
        // x, y一定是非负的。31位是符号位,从30位即可
        for (int i = 30; i >= 0; i = minus(i, 1)) {
            // x右移,避免右移超范围
            if ((x >> i) >= y) {
                res |= (1 << i);
                x = minus(x, y << i);
            }
        }
        return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
    }

    /**
     * 除法(考虑系统最小值)
     */
    public static int divide(int a, int b) {
        if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
            return 1;
        } else if (b == Integer.MIN_VALUE) {
            return 0;
        }
        // a为系统最小
        else if (a == Integer.MIN_VALUE) {
            // a/-1
            if (b == negNum(1)) {
                // LeetCode强行规定,最小值的相反数为最大值
                return Integer.MAX_VALUE;
            } else {
                // 1. c = (a+1) / b
                // 2. c + (a - c*b) / b
                int c = div(add(a, 1), b);
                return add(c, div(minus(a, multi(c, b)), b));
            }
        }
        // 都不是系统最小
        else {
            return div(a, b);
        }
    }

}