100180. Find Polygon With the Largest Perimeter

给你一个长度为 n 的 正 整数数组 nums 。

多边形 指的是一个至少有 3 条边的封闭二维图形。多边形的 最长边 一定 小于 所有其他边长度之和。

如果你有 k (k >= 3)个 正 数 a1,a2,a3, ...,ak 满足 a1 <= a2 <= a3 <= ... <= ak 且 a1 + a2 + a3 + ... + ak-1 > ak ,那么 一定 存在一个 k 条边的多边形,每条边的长度分别为 a1 ,a2 ,a3 , ...,ak 。

一个多边形的 周长 指的是它所有边之和。

请你返回从 nums 中可以构造的 多边形 的 最大周长 。如果不能构造出任何多边形,请你返回 -1 。

测试样例:

输入:nums = [5,5,5]

输出:15

解释:nums 中唯一可以构造的多边形为三角形,每条边的长度分别为 5 ,5 和 5 ,周长为 5 + 5 + 5 = 15 。

解答:排序之后,记录到当前数字之前的和。如果sum(a1, a2, .., ak-1) < ak,又因为排序了,所以必然有ak > ak-1,则当前必然是一个多边形。

class Solution {
    public long largestPerimeter(int[] nums) {
        Arrays.sort(nums);
        long res = -1, sum = 0;
        for (int i = 0; i < nums.length; ++i) {
            if (sum > nums[i]) {
                res = Math.max(res, sum + nums[i]);
            }
            sum += nums[i];
        }
        return res;
    }
}

100167. Count the Number of Incremovable Subarrays II

给你一个下标从 0 开始的 正 整数数组 nums 。

如果 nums 的一个子数组满足:移除这个子数组后剩余元素 严格递增 ,那么我们称这个子数组为 移除递增 子数组。比方说,[5, 3, 4, 6, 7] 中的 [3, 4] 是一个移除递增子数组,因为移除该子数组后,[5, 3, 4, 6, 7] 变为 [5, 6, 7] ,是严格递增的。

请你返回 nums 中 移除递增 子数组的总数目。

注意 ,剩余元素为空的数组也视为是递增的。

子数组 指的是一个数组中一段连续的元素序列。

测试样例:

输入:nums = [1,2,3,4]

输出:10

解释:10 个移除递增子数组分别为:[1], [2], [3], [4], [1,2], [2,3], [3,4], [1,2,3], [2,3,4] 和 [1,2,3,4]。移除任意一个子数组后,剩余元素都是递增的。注意,空数组不是移除递增子数组。

解答:如果当前已经是一个严格递增序列,则用等差数列求和公式计算一下结果。否则我们需要将从0开始的升序序列寻找到,并存在一个红黑树中,然后从后向前遍历数组。从后向前遍历的时候需要保证后序数组也是严格递增序列。那么这个时候,我们可以利用红黑树,寻找到一个前置序列,这个序列拼接上后置序列也是一个严格升序序列。利用这个性质,我们可以求出当前位置,满足条件的移除递增 子数组。

class Solution {
    public long incremovableSubarrayCount(int[] nums) {
        TreeMap<Integer, Integer> increase = new TreeMap<>();
        for (int i = 0; i < nums.length; ++i) {
            if (i == 0 || nums[i] > nums[i - 1]) {
                increase.put(nums[i], i);
            } else {
                break;
            }
        }
        int max = increase.lastEntry().getValue();
        if (max == nums.length - 1) {
            return (1L + nums.length) * nums.length / 2;
        }
        long res = increase.lastEntry().getValue() + 2;
        for (int i = nums.length - 1; i >= 0; --i) {
            if (i == nums.length - 1 || nums[i] < nums[i + 1]) {
                Map.Entry<Integer, Integer> lower = increase.lowerEntry(nums[i]);
                if (lower == null) {
                    res += 1;
                } else {
                    res += lower.getValue() + (i <= max ? 1 : 2);
                }
            } else {
                break;
            }
        }
        return res;
    }
}

100141. Find Number of Coins to Place in Tree Nodes

给你一棵 n 个节点的 无向 树,节点编号为 0 到 n - 1 ,树的根节点在节点 0 处。同时给你一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 之间有一条边。

给你一个长度为 n 下标从 0 开始的整数数组 cost ,其中 cost[i] 是第 i 个节点的 开销 。

你需要在树中每个节点都放置金币,在节点 i 处的金币数目计算方法如下:

  • 如果节点 i 对应的子树中的节点数目小于 3 ,那么放 1 个金币。
  • 否则,计算节点 i 对应的子树内 3 个不同节点的开销乘积的 最大值 ,并在节点 i 处放置对应数目的金币。如果最大乘积是 负数 ,那么放置 0 个金币。

请你返回一个长度为 n 的数组 coin ,coin[i]是节点 i 处的金币数目。

测试样例:

输入:edges = [[0,1],[0,2],[0,3],[0,4],[0,5]], cost = [1,2,3,4,5,6]

输出:[120,1,1,1,1,1]

解释:在节点 0 处放置 6 5 4 = 120 个金币。所有其他节点都是叶子节点,子树中只有 1 个节点,所以其他每个节点都放 1 个金币。

解答:这题没啥难度,注意2个负数相乘也是正数(因为这个WA了一次,泪目)。每个节点都记录一下当前最大的3个正数和负数,然后计算一下当前节点的最大乘积。

class Solution {
    private class PersonnelQueue {
        LinkedList<Integer> pos;
        LinkedList<Integer> neg;

        public PersonnelQueue() {
            pos = new LinkedList<>();
            neg = new LinkedList<>();
        }

        public boolean isValid() {
            return pos.size() + neg.size() >= 3;
        }

        public void add(int n) {
            if (n >= 0) {
                pos.add(n);
                Collections.sort(pos);
                if (pos.size() > 3) {
                    pos.removeFirst();
                }
            } else {
                neg.add(n);
                Collections.sort(neg);
                if (neg.size() > 3) {
                    neg.removeLast();
                }
            }
        }

        public long findBest() {
            long res = 0;
            if (neg.size() >= 2 && pos.size() >= 1) {
                long tmp = neg.get(0);
                tmp *= neg.get(1);
                tmp *= pos.get(pos.size() - 1);
                res = Math.max(res, tmp);
            }
            if (pos.size() >= 3) {
                long tmp = 1;
                for (int n : pos) {
                    tmp *= n;
                }
                res = Math.max(res, tmp);
            }
            return res;
        }
    }

    public long[] placedCoins(int[][] _edges, int[] cost) {
        int len = _edges.length + 1;
        List<Integer>[] edges = new List[len + 1];
        for (int i = 0; i < len; ++i) {
            edges[i] = new ArrayList<>();
        }
        for (int[] e : _edges) {
            edges[e[0]].add(e[1]);
            edges[e[1]].add(e[0]);
        }

        long[] res = new long[len];
        dfs(0, -1, edges, cost, res);
        return res;
    }

    private PersonnelQueue dfs(int node, int pre, List<Integer>[] edges, int[] cost, long[] res) {
        PersonnelQueue queue = new PersonnelQueue();
        for (int n : edges[node]) {
            if (n != pre) {
                PersonnelQueue tmp = dfs(n, node, edges, cost, res);
                for (int t : tmp.neg) {
                    queue.add(t);
                }
                for (int t : tmp.pos) {
                    queue.add(t);
                }
            }
        }
        queue.add(cost[node]);
        if (queue.isValid()) {
            res[node] = queue.findBest();
        } else {
            res[node] = 1;
        }
        return queue;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *