LeetCode刷题记185-Binary Indexed Tree(树状数组)

327. 区间和的个数

class Solution {
    int[] a;

    public void init(int n) {
        a = new int[n + 1];
    }

    public void insert(int i, int x) {
        while (i < a.length) {
            a[i] += x;
            i += lowbit(i);
        }
    }

    public int sum(int i) {
        int res = 0;
        while (i > 0) {
            res += a[i];
            i -= lowbit(i);
        }
        return res;
    }

    public int lowbit(int x) {
        return x & (-x);
    }

    public int countRangeSum(int[] nums, int lower, int upper) {
        if (nums.length == 0) return 0;
        int ans = 0;
        // 求前缀数组和
        // 题目有[-2147483647,0,-2147483647,2147483647]  -564  3864
        long[] preSum = new long[nums.length];  
        Set<Long> set = new HashSet<Long>();  // 用于辅助离散化preSum
        preSum[0] = (long)nums[0];
        set.add(preSum[0]);
        for (int i = 1; i < nums.length; i ++) {
            preSum[i] = preSum[i - 1] + nums[i];
            set.add(preSum[i]);
        }

        // 离散化
        TreeMap<Long, Integer> treeMap = new TreeMap();
        List<Long> list = new ArrayList(set);
        Collections.sort(list);
        int id = 0;
        for (long num : list) {
            treeMap.put(num, ++id);
        }
        // 初始化树状数组
        init(set.size());

        // 区间sum[j, i] = preSum[i] - preSum[j - 1];
        // lower <= sum[j, i] <= upper就是lower <= preSum[i] - preSum[j - 1]; <= upper
        // preSum[i] - upper <= preSum[j - 1] <= preSum[i] - lower
        for (int i = 0; i < nums.length; i ++) {
            // 当前[0,i]区间满足条件,但是树状数组里面还没有插入当前的前缀和
            if (preSum[i] >= lower && preSum[i] <= upper) ans ++;  

            long l = preSum[i] - upper;  // l是满足条件的preSum[j - 1]最小值
            long r = preSum[i] - lower;  // r是满足条件的preSum[j - 1]最大值
            Long _l = treeMap.ceilingKey(l);  // 返回大于或等于给定键值的最小键。没有则返回null。
            Long _r = treeMap.floorKey(r);  // 返回小于于或等于给定键值的最小键。没有则返回null。
            
            if (_l != null && _r != null) {
                int leftId = treeMap.get(_l);
                int rightId = treeMap.get(_r);
                ans += sum(rightId) - sum(leftId - 1); 
            }
            id = treeMap.get(preSum[i]);
            insert(id, 1);  // 注意插入树状数组要在这次计算完成之后再进行,保证不会出现区间长度为零的情况
        }
        return ans;
    }
}

307. 区域和检索 - 数组可修改

class NumArray {
    int[] _nums;
    int[] a;

    public NumArray(int[] nums) {
        _nums = new int[nums.length];
        a = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i ++) {
            update(i, nums[i]);
            _nums[i] = nums[i];
        }
    }
    
    public void update(int index, int val) {
        int _val = val;
        int _index = index;
        val -= _nums[index];
        index ++;
        while (index < a.length) {
            a[index] += val;
            index += lowbit(index);
        }
        _nums[_index] = _val;
    }

    int sum(int index) {
        index ++;
        int ans = 0;
        while (index > 0) {
            ans += a[index];
            index -= lowbit(index);
        }
        return ans;
    }

    public int sumRange(int left, int right) {
        return sum(right) - sum(left - 1);
    }

    int lowbit(int x) {
        return x & (- x);
    }
}

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray obj = new NumArray(nums);
 * obj.update(index,val);
 * int param_2 = obj.sumRange(left,right);
 */

493. 翻转对

class Solution {
    int[] a;
    int n;

    public void init(int n) {
        this.n = n;
        a = new int[n];
    }

    public int lowbit(int x) {
        return x & (-x);
    }

    public void insert(int ind, int x) {
        while(ind < n) {
            a[ind] += x;
            ind += lowbit(ind);
        }
    }

    public int sum(int ind) {
        int sum = 0;
        while(ind > 0) {
            sum += a[ind];
            ind -= lowbit(ind);
        }
        return sum;
    }

    public int reversePairs(int[] nums) {
        Set<Integer> set = new TreeSet<Integer>();
        for (int num : nums) set.add(num);
        TreeMap<Integer, Integer> numToId = new TreeMap<Integer, Integer>();
        int id = 0;
        for (int num : set) numToId.put(num, ++ id);

        init(id + 1);

        int ans = 0;
        for (int i = 0; i < nums.length; i ++) {
            long dnum = (long)nums[i] * 2 + 1;
            if (dnum > 2147483647) {
                insert(numToId.get(nums[i]), 1);
                continue;
            } else if (dnum < - 2147483648) {
                dnum = - 2147483648;
            }
            Integer key = numToId.ceilingKey((int)dnum);
            if (key != null) {
                int Id = numToId.get(key);
                ans += i - sum(Id - 1);
            }
            insert(numToId.get(nums[i]), 1);
        }
        return ans;
    }
}

1649. 通过指令创建有序数组

class Solution {
    final static int MOD = 1_000_000_007;
    int[] a;
    int n;

    public void init(int n) {
        this.n = n;
        a = new int[n];
    }

    public int lowbit(int x) {
        return x & (-x);
    }

    public void insert(int i, int x) {
        while (i < n) {
            a[i] += x;
            i += lowbit(i);
        }
    }

    public int getSum(int i) {
        int sum = 0;
        while (i > 0) {
            sum += a[i];
            i -= lowbit(i);
        }
        return sum;
    }

    public int createSortedArray(int[] instructions) {
        int maxNum = 0;
        for (int num : instructions) {
            maxNum = Math.max(maxNum, num);
        }
        init(maxNum + 1);

        int ans = 0;
        for (int i = 0; i < instructions.length; i ++) {
            ans += Math.min(getSum(instructions[i] - 1), i - getSum(instructions[i]));
            ans %= MOD;
            insert(instructions[i], 1);
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值