8048. Maximum Odd Binary Number

给你一个 二进制 字符串 s ,其中至少包含一个 '1' 。

你必须按某种方式 重新排列 字符串中的位,使得到的二进制数字是可以由该组合生成的 最大二进制奇数 。

以字符串形式,表示并返回可以由给定组合生成的最大二进制奇数。

注意 返回的结果字符串 可以 含前导零。

测试样例:

输入:s = "010"

输出:"001"

解释:
因为字符串 s 中仅有一个 '1' ,其必须出现在最后一位上。所以答案是 "001" 。

解答:计算一下string中,1的个数。然后用贪婪。

class Solution {
    public String maximumOddBinaryNumber(String s) {
        int one = 0;
        for (int i = 0; i < s.length(); ++i) {
            if (s.charAt(i) == '1') {
                ++one;
            }
        }
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < s.length(); ++i) {
            if (i != s.length() - 1) {
                if (one > 1) {
                    res.append(1);
                    --one;
                } else {
                    res.append(0);
                }
            } else {
                res.append(1);
            }
        }
        return res.toString();
    }
}

100049. Beautiful Towers I

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。

你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。

如果以下条件满足,我们称这些塔是 美丽 的:

  1. 1 <= heights[i] <= maxHeights[i]
    2, heights 是一个 山状 数组。

如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山状 数组:

  • 对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
  • 对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k]

请你返回满足 美丽塔 要求的方案中,高度和的最大值 。

测试样例:

输入:maxHeights = [5,3,4,1,1]

输出:13

解释:
和最大的美丽塔方案为 heights = [5,3,3,1,1] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 0 处。

13 是所有美丽塔方案中的最大高度和。

解答:这道题目和这周第三题其实是一样的,只是范围不一样。这里就直接用第三题的思路来做了。因为需要变成山状数组,那么我们可以选定一个数作为山峰。如果能快速计算出作为山峰时,当前数组的结果,那么就可以得到答案了。接下来的重点就是怎么快速计算结果。

我们可以利用前缀和的方法来计算。维护一个单调栈,保持单调栈一直是递增状态。然后计算前缀和。

class Solution {
    public long maximumSumOfHeights(List<Integer> maxHeights) {
        int[] arr = new int[maxHeights.size()];
        int len = 0;
        for (int n : maxHeights) {
            arr[len++] = n;
        }

        long[] left = new long[len];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < len; ++i) {
            while (!stack.isEmpty() && arr[i] < arr[stack.peek()]) {
                stack.pop();
            }
            if (stack.isEmpty()) {
                left[i] = arr[i] * (i + 1L);
            } else {
                long h = arr[i];
                left[i] = left[stack.peek()] + h * (i - stack.peek());
            }
            stack.push(i);
        }

        long res = 0;
        stack = new Stack<>();
        long[] right = new long[len];
        for (int i = len - 1; i >= 0; --i) {
            while (!stack.isEmpty() && arr[i] < arr[stack.peek()]) {
                stack.pop();
            }
            if (stack.isEmpty()) {
                right[i] = (arr[i] * ((long) len - i));
                res = Math.max(res, left[i] + arr[i] * (len - i - 1L));
            } else {
                long h = arr[i];
                right[i] = right[stack.peek()] + arr[i] * ((long) stack.peek() - i);
                res = Math.max(res, left[i] + right[stack.peek()] + arr[i] * ((long) stack.peek() - i - 1));
            }
            stack.push(i);
        }
        return res;
    }
}

100048. Beautiful Towers II

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。

你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。

如果以下条件满足,我们称这些塔是 美丽 的:

  1. 1 <= heights[i] <= maxHeights[i]
    2, heights 是一个 山状 数组。

如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山状 数组:

  • 对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
  • 对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k]

请你返回满足 美丽塔 要求的方案中,高度和的最大值 。

测试样例:

输入:maxHeights = [5,3,4,1,1]

输出:13

解释:
和最大的美丽塔方案为 heights = [5,3,3,1,1] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 0 处。

13 是所有美丽塔方案中的最大高度和。

解答:这道题目和这周第三题其实是一样的,只是范围不一样。这里就直接用第三题的思路来做了。因为需要变成山状数组,那么我们可以选定一个数作为山峰。如果能快速计算出作为山峰时,当前数组的结果,那么就可以得到答案了。接下来的重点就是怎么快速计算结果。

我们可以利用前缀和的方法来计算。维护一个单调栈,保持单调栈一直是递增状态。然后计算前缀和。

class Solution {
    public long maximumSumOfHeights(List<Integer> maxHeights) {
        int[] arr = new int[maxHeights.size()];
        int len = 0;
        for (int n : maxHeights) {
            arr[len++] = n;
        }

        long[] left = new long[len];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < len; ++i) {
            while (!stack.isEmpty() && arr[i] < arr[stack.peek()]) {
                stack.pop();
            }
            if (stack.isEmpty()) {
                left[i] = arr[i] * (i + 1L);
            } else {
                long h = arr[i];
                left[i] = left[stack.peek()] + h * (i - stack.peek());
            }
            stack.push(i);
        }

        long res = 0;
        stack = new Stack<>();
        long[] right = new long[len];
        for (int i = len - 1; i >= 0; --i) {
            while (!stack.isEmpty() && arr[i] < arr[stack.peek()]) {
                stack.pop();
            }
            if (stack.isEmpty()) {
                right[i] = (arr[i] * ((long) len - i));
                res = Math.max(res, left[i] + arr[i] * (len - i - 1L));
            } else {
                long h = arr[i];
                right[i] = right[stack.peek()] + arr[i] * ((long) stack.peek() - i);
                res = Math.max(res, left[i] + right[stack.peek()] + arr[i] * ((long) stack.peek() - i - 1));
            }
            stack.push(i);
        }
        return res;
    }
}

100047. Count Valid Paths in a Tree

给你一棵 n 个节点的无向树,节点编号为 1 到 n 。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ui, vi] 表示节点 ui 和 vi 在树中有一条边。

请你返回树中的 合法路径数目 。

如果在节点 a 到节点 b 之间 恰好有一个 节点的编号是质数,那么我们称路径 (a, b) 是 合法的 。

注意:

  • 路径 (a, b) 指的是一条从节点 a 开始到节点 b 结束的一个节点序列,序列中的节点 互不相同 ,且相邻节点之间在树上有一条边。
  • 路径 (a, b) 和路径 (b, a) 视为 同一条 路径,且只计入答案 一次 。

测试样例

输入:n = 5, edges = [[1,2],[1,3],[2,4],[2,5]]

输出:4

恰好有一个质数编号的节点路径有:

  • (1, 2) 因为路径 1 到 2 只包含一个质数 2 。
  • (1, 3) 因为路径 1 到 3 只包含一个质数 3 。
  • (1, 4) 因为路径 1 到 4 只包含一个质数 2 。
  • (2, 4) 因为路径 2 到 4 只包含一个质数 2 。

只有 4 条合法路径。

解答:最近几周的第四题都是一个套路:在树上遍历记录历史结果,第二次遍历再更新一次。

这次也是类似的,我们先假设1是root,从1开始遍历,计算当前节点到最近的质数的所有路径数。第二次遍历,假设当前节点是质数,那么我们计算当前质数节点所有遍历可能。

class Solution {
    private int[] isPrime;
    private long[] mem;
    private List<Integer>[] edges;
    private long res;

    public long countPaths(int n, int[][] _edges) {
        this.edges = new List[n + 1];
        isPrime = new int[n + 1];
        for (int i = 0; i <= n; ++i) {
            edges[i] = new ArrayList<>();
            isPrime[i] = -1;
        }
        for (int[] e : _edges) {
            edges[e[0]].add(e[1]);
            edges[e[1]].add(e[0]);
        }

        mem = new long[n + 1];
        initialTree(1, -1);

        res = 0;
        dfsResult(1, -1, 0);
        return res;
    }

    private long initialTree(int cur, int last) {
        long decent = 0;
        for (int n : edges[cur]) {
            if (n != last) {
                decent += initialTree(n, cur);
            }
        }
        mem[cur] = isPrime(cur) ? 0 : decent + 1;
        return mem[cur];
    }

    private void dfsResult(int cur, int last, long lastVal) {
        long sum = lastVal;
        for (int n : edges[cur]) {
            if (n != last) {
                sum += mem[n];
            }
        }
        if (isPrime(cur)) {
            long sumDup = sum;
            for (int n : edges[cur]) {
                long tmp;
                if (n == last) {
                    tmp = lastVal;
                } else {
                    tmp = mem[n];
                }
                sumDup -= tmp;
                res += tmp * sumDup;
                res += tmp;
            }

            for (int n : edges[cur]) {
                if (n != last) {
                    dfsResult(n, cur, 0);
                }
            }
        } else {
            for (int n : edges[cur]) {
                if (n != last) {
                    dfsResult(n, cur, sum - mem[n] + 1);
                }
            }
        }
    }

    private boolean isPrime(int n) {
         if (isPrime[n] == -1) {
            if (n == 1) {
                isPrime[n] = 1;
            } else {
                isPrime[n] = 0;
                for (int t = 2; t * t <= n; ++t) {
                    if (n % t == 0) {
                        isPrime[n] = 1;
                        break;
                    }
                }
            }
        }
        return isPrime[n] == 0;
    }
}

Leave a Reply

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