LeetCode 327. Count of Range Sum(区间和计数)

来源:互联网 发布:淘宝阿丑体育 编辑:程序博客网 时间:2024/06/13 09:38

原题网址:https://leetcode.com/problems/count-of-range-sum/

Given an integer array nums, return the number of range sums that lie in [lower, upper] inclusive.
Range sum S(i, j) is defined as the sum of the elements in nums between indices i and j (i ≤ j), inclusive.

Note:
A naive algorithm of O(n2) is trivial. You MUST do better than that.

Example:
Given nums = [-2, 5, -1]lower = -2upper = 2,
Return 3.
The three ranges are : [0, 0][2, 2][0, 2] and their respective sums are: -2, -1, 2.

方法一:使用TreeMap来保存每个前缀和的计数。

public class Solution {    public int countRangeSum(int[] nums, int lower, int upper) {        if (nums == null || nums.length==0) return 0;        long[] sums = new long[nums.length];        sums[0] = nums[0];        for(int i=1; i<nums.length; i++) sums[i] = sums[i-1] + nums[i];        int total = 0;        TreeMap<Long, Integer> treemap = new TreeMap<>();        for(int i=0; i<nums.length; i++) {            if (lower <= sums[i] && sums[i] <= upper) total ++;            for(Integer count: treemap.subMap(sums[i]-upper, true, sums[i]-lower, true).values()) {                total += count;            }            Integer count = treemap.get(sums[i]);            if (count == null) count = 1; else count ++;            treemap.put(sums[i], count);        }        return total;    }}

方法二:使用二叉搜索树(相当于方法一的自己实现)

public class Solution {    Node root;    private int sub(Node node, long lower, long upper) {        // System.out.printf("sub=%s, lower=%d, upper=%d\n", node==null?"null":Long.toString(node.val), lower, upper);        if (node == null) return 0;        if (node.val < lower) return sub(node.right, lower, upper);        if (upper < node.val) return sub(node.left, lower, upper);        return node.count + sub(node.left, lower, node.val-1) + sub(node.right, node.val+1, upper);    }    private void insert(Node node, long val) {        if (node.val < val) {            if (node.right == null) node.right = new Node(val);            insert(node.right, val);        } else if (val < node.val) {            if (node.left == null) node.left = new Node(val);            insert(node.left, val);        } else {            node.count ++;        }    }    public int countRangeSum(int[] nums, int lower, int upper) {        if (nums == null || nums.length == 0) return 0;        long[] sums = new long[nums.length];        sums[0] = nums[0];        for(int i=1; i<nums.length; i++) sums[i] = sums[i-1] + nums[i];        root = new Node(nums[0]);        int count = 0;        for(int i=0; i<nums.length; i++) {            // System.out.printf("i=%d, sums[i]=%d\n", i, sums[i]);            if (lower <= sums[i] && sums[i] <= upper) {                count ++;                // System.out.printf("1. count=%d\n", count);            }            count += sub(root, sums[i]-upper, sums[i]-lower);            // System.out.printf("2. count=%d\n", count);            insert(root, sums[i]);        }        return count;    }}class Node {    long val;    int count;    Node left, right;    Node(long val) {        this.val = val;    }}

方法三:改进的二叉搜索树(保存左子树节点数量)

public class Solution {    private Node build(long[] nums, int from, int to) {        if (from>to) return null;        int m = (from+to)/2;        Node node = new Node(nums[m]);        if (from<m) node.left = build(nums, from, m-1);        if (m<to) node.right = build(nums, m+1, to);        return node;    }    private void update(Node node, long val) {        if (node == null) return;        if (val < node.val) {            node.count ++;            update(node.left, val);        } else if (val > node.val) {            update(node.right, val);        } else {            node.count ++;        }    }    private int smaller(Node node, long val) {        if (node == null) return 0;        if (node.val <= val) {            return node.count + smaller(node.right, val);        } else {            return smaller(node.left, val);        }    }    public int countRangeSum(int[] nums, int lower, int upper) {        if (nums == null || nums.length == 0) return 0;        long[] sums = new long[nums.length];        sums[0] = nums[0];        for(int i=1; i<nums.length; i++) sums[i] = sums[i-1] + nums[i];        Set<Long> set = new HashSet<>();        for(int i=0; i<nums.length; i++) set.add(sums[i]);        long[] unique = new long[set.size()];        int u=0;        for(long s: set) unique[u++] = s;        Arrays.sort(unique);        Node root = build(unique, 0, unique.length-1);        int count = 0;        for(int i=0; i<sums.length; i++) {            if (lower <= sums[i] && sums[i] <= upper) count ++;            count += smaller(root, sums[i]-lower) - smaller(root, sums[i]-upper-1);            update(root, sums[i]);        }        return count;    }}class Node {    long val;    int count;    Node left, right;    Node(long val) {        this.val = val;    }}

方法四:使用分段树,通过预先排序实现数的平衡。

public class Solution {    private Node root;    private Node build(long[] ranges, int min, int max) {        if (min>max) return null;        Node Node = new Node(ranges[min], ranges[max]);        if (min==max) return Node;        int m = (min+max)/2;        Node.left = build(ranges, min, m);        Node.right = build(ranges, m+1, max);        return Node;    }    private void update(Node node, long val) {        if (node == null) return;        if (val < node.min || node.max < val) return;        node.count ++;        update(node.left, val);        update(node.right, val);    }    private int query(Node node, long from, long to) {        if (node==null) return 0;        if (node.max < from || to < node.min) return 0;        if (from <= node.min && node.max <= to) return node.count;        return query(node.left, from, to) + query(node.right, from, to);    }    public int countRangeSum(int[] nums, int lower, int upper) {        if (nums == null || nums.length == 0) return 0;        long[] sums = new long[nums.length];        sums[0] = nums[0];        Set<Long> set = new HashSet<>();        set.add(sums[0]);        for(int i=1; i<nums.length; i++) {            sums[i] = sums[i-1] + nums[i];            set.add(sums[i]);        }        long[] ranges = new long[set.size()];        int r=0;        for(long s: set) ranges[r++] = s;        Arrays.sort(ranges);        root = build(ranges, 0, ranges.length-1);        int count = 0;        for(int i=0; i<sums.length; i++) {            if (lower <= sums[i] && sums[i] <= upper) count ++;            count += query(root, sums[i]-upper, sums[i]-lower);            update(root, sums[i]);        }        return count;    }}class Node {    long min, max;    int count;    Node left, right;    Node(long min, long max) {        this.min = min;        this.max = max;    }}

方法五:使用合并排序发实现分治策略。

public class Solution {    private int sort(long[] sums, int from, int to, int lower, int upper) {        if (from > to) return 0;        if (from == to) return (lower <= sums[from] && sums[from] <= upper) ? 1 : 0;        int count = 0;        int m = (from + to) / 2;        count = sort(sums, from, m, lower, upper) + sort(sums, m+1, to, lower, upper);        for(int i=from, j=m+1, k=m+1; i<=m; i++) {            while (j<=to && sums[j] - sums[i] < lower) j++;            while (k<=to && sums[k] - sums[i] <= upper) k++;            count += k - j;        }        long[] merged = new long[to-from+1];        int l=from, r=m+1;        for(int i=0, j=from, k=m+1; i<merged.length; i++) {            if (j>m) merged[i] = sums[k++];            else if (k>to) merged[i] = sums[j++];            else if (sums[j] <= sums[k]) merged[i] = sums[j++];            else merged[i] = sums[k++];        }        System.arraycopy(merged, 0, sums, from, merged.length);        return count;    }    public int countRangeSum(int[] nums, int lower, int upper) {        if (nums == null || nums.length == 0) return 0;        long[] sums = new long[nums.length];        sums[0] = nums[0];        for(int i=1; i<nums.length; i++) sums[i] = sums[i-1] + nums[i];        return sort(sums, 0, sums.length-1, lower, upper);    }}

方法六:树状数组。

未实现,留待下次。

二叉树不一定要用指针实现,可以用数组实现。

0 0
原创粉丝点击