上岸算法 I LeetCode Weekly Contest 233解题报告

No.1最大升序子数组和

解题思路

注意该题目的子数组是连续的。因此枚举起始位置即可。

代码展示

class Solution {
    public int maxAscendingSum(int[] nums) {
        int res = nums[0];
        for (int start = 0; start < nums.length; start++) {
            int sum = nums[start];
            for (int i = start + 1; i < nums.length; i++) {
                if (nums[i] > nums[i - 1]) {
                    sum += nums[i];
                } else {
                    break;
                }
            }
            res = Math.max(res, sum);
        }
        return res;
    }
}

No.2 积压订单中的订单总数

解题思路

使用 PriorityQueue 或者 TreeMap 维护两类挤压订单即可。

代码展示

class Solution {
    public int getNumberOfBacklogOrders(int[][] orders) {
        TreeMap<Integer, Integer> toSell = new TreeMap<Integer, Integer>();
        TreeMap<Integer, Integer> toBuy = new TreeMap<Integer, Integer>();
        for (var order : orders) {
            if (order[2] == 0) {
                // buy
                while (order[1] > 0) {
                    var entry = toSell.firstEntry();
                    if (entry == null || entry.getKey() > order[0]) {
                        break;
                    }
                    int cnt = Math.min(entry.getValue(), order[1]);
                    order[1] -= cnt;
                    if (cnt == entry.getValue()) {
                        toSell.remove(entry.getKey());
                    } else {
                        toSell.put(entry.getKey(), entry.getValue() - cnt);
                    }
                    // break;
                }
                if (order[1] > 0) {
                    toBuy.put(order[0], order[1] + toBuy.getOrDefault(order[0], 0));
                }
            } else {
                // sell
                while (order[1] > 0) {
                    var entry = toBuy.lastEntry();
                    if (entry == null || entry.getKey() < order[0]) {
                        break;
                    }
                    int cnt = Math.min(entry.getValue(), order[1]);
                    order[1] -= cnt;
                    if (cnt == entry.getValue()) {
                        toBuy.remove(entry.getKey());
                    } else {
                        toBuy.put(entry.getKey(), entry.getValue() - cnt);
                    }
                    // break;
                }
                if (order[1] > 0) {
                    toSell.put(order[0], order[1] + toSell.getOrDefault(order[0], 0));
                }
            }
        }
        int res = 0;
        for (var entry : toSell.entrySet()) {
            res = (res + entry.getValue()) % 1000000007;
        }
        for (var entry : toBuy.entrySet()) {
            res = (res + entry.getValue()) % 1000000007;
        }
        return res;
    }
}

No.3 有界数组中指定下标处的最大值

解题思路

二分答案。当指定下标处的值确定后,贪心地令其他元素尽可能小即可,所以就是等差数列求和。

代码展示

class Solution {
    public int maxValue(int n, int index, int maxSum) {
        long l = 0, r = maxSum;
        while (l + 1 < r) {
            long mid = (l + r) / 2;
            if (check(mid, index, maxSum, n)) {
                l = mid;
            } else {
                r = mid;
            }
        }
        return (int) (check(r, index, maxSum, n) ? r : l);
    }

    long sum(long start, long count) {
        if (count <= 0) {
            return 0;
        }
        if (start < count) {
            return (start + 1) * start / 2 + (count - start);
        }
        return (start + start - count + 1) * count / 2;
    }

    boolean check(long value, long index, long maxSum, long n) {
        long left = index;
        long right = n - index - 1;
        return sum(value - 1, left) + sum(value - 1, right) + value <= maxSum;
    }
}

No.4 统计异或值在范围内的数对有多少

解题思路

求 [low, high] 区间内的等同于求 [low, inf) 再减去 (high, inf)。

因此问题转换成求异或值大于给定数值的数对数量。使用字典树即可。

代码展示

class Solution {
    public int countPairs(int[] nums, int low, int high) {
        return (int) (solve(nums, low - 1) - solve(nums, high));
    }

    static class TrieTree {
        TrieTree[] next = new TrieTree[2];
        int count = 1;
    }

    long solve(int[] nums, int m) {
        TrieTree trieTree = buildTrieTree(nums);
        long result = 0;
        for (int i = 0; i < nums.length; i++) {
            result += queryTrieTree(trieTree, nums[i], m, 31);
        }
        return result / 2;
    }

    long queryTrieTree(TrieTree trieTree, int a, int m, int index) {
        if (trieTree == null)
            return 0;
        TrieTree current = trieTree;
        for (int i = index; i >= 0; i--) {
            int aDigit = (a >> i) & 1;
            int mDigit = (m >> i) & 1;
            if (aDigit == 1 && mDigit == 1) {
                if (current.next[0] == null)
                    return 0;
                current = current.next[0];
            } else if (aDigit == 0 && mDigit == 1) {
                if (current.next[1] == null)
                    return 0;
                current = current.next[1];
            } else if (aDigit == 1 && mDigit == 0) {
                long p = queryTrieTree(current.next[1], a, m, i - 1);
                long q = current.next[0] == null ? 0 : current.next[0].count;
                return p + q;
            } else if (aDigit == 0 && mDigit == 0) {
                long p = queryTrieTree(current.next[0], a, m, i - 1);
                long q = current.next[1] == null ? 0 : current.next[1].count;
                return p + q;
            }
        }
        return 0;
    }

    TrieTree buildTrieTree(int[] a) {
        TrieTree trieTree = new TrieTree();
        for (int i = 0; i < a.length; i++) {
            TrieTree current = trieTree;
            for (int j = 31; j >= 0; j--) {
                int digit = (a[i] >> j) & 1;
                if (current.next[digit] == null) {
                    current.next[digit] = new TrieTree();
                } else {
                    current.next[digit].count++;
                }
                current = current.next[digit];
            }
        }
        return trieTree;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值