这是LeetCode 上的第 173 场周赛(链接)。

1341. 方阵中战斗力最弱的 K 行(The K Weakest Rows in a Matrix)

给定一个只包含 0 和 1 的二维数组,输出包含 1 数量最少的前 k 行。写这题的时候总有一种 Python 用了这么多语法糖会不会太投机取巧的担忧。。

class Solution:
    def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]:
        s = [[i, sum(mat[i])] for i in range(len(mat))]
        s.sort(key=lambda x: x[1])
        return [x[0] for x in s[:k]]

1342. 数组大小减半(Reduce Array Size to The Half)

给定一个数组,一次可以删除所有的某个数字,求将数组长度缩减到至少一半的最小删除次数。

思路是现将所有数字按照出现的次数从大到小排序,然后遍历累加这个频次数组,一旦累加的和(即长度)超过原数组一半就输出累加次数。

class Solution:
    def minSetSize(self, arr: List[int]) -> int:
        dic = dict()
        for i in arr:
            if i not in dic:
                dic[i] = 1
            else:
                dic[i] += 1
        v = list(dic.values())
        v.sort(reverse=True)
        count = 0
        ans = 0
        for i in v:
            count += i
            ans += 1
            if count*2 >= len(arr):
                return ans

1339. 分裂二叉树的最大乘积(Maximum Product of Splitted Binary Tree)

给定一棵二叉树,去掉一条边变成两树二叉树。找到这两棵子树和的乘积的最大值。由于这个值很大,所以输出还要模 1e9+7。

这其实是一道基础的题,关键在于对二叉树这个数据结构的理解。参考了 这位dalao 的思路。

  1. 对整棵树后序遍历,得到以各个节点为根的子树总和。
  2. 去掉一条边,两棵子树的乘积 = 子树总和 * (总和 - 子树总和),遍历取最大值。
  3. 最后进行取模操作。
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    
    def maxProduct(self, root: TreeNode) -> int:
        sums = []

        def postOrder(root: TreeNode):
            if not root:
                return 0
            res = root.val + postOrder(root.left) + postOrder(root.right)
            sums.append(res)
            return res

        s = postOrder(root)
        ans = -1
        for i in sums:
            ans = max(ans, i * (s - i))
        return int(ans % (1e9 + 7))

1344. 跳跃游戏 V(Jump Game V)

动态规划。使用 dp[i] 表示下标 i 最多能跳的次数,max(dp) 就是我们想要的结果。

关键在于,如何计算 dp[i]。

  • 我们可以通过下标 i 的左右可跳范围去计算 dp[i],状态转移方程是:

    \[dp[i] = max(dp[j] + 1)\]

    上式中,j 为在 i 的可跳范围内的下标,即 i-d..i+d(或 0..i+d、i-d..len(arr)-1、0..len(arr)-1,视是否到边界的情况而定)。

  • 初始条件:所有 dp[i] 一开始初始化为 1,即一开始我们认为每个地方都只能跳自己一次。

  • 最后,按照高度从低到高的顺序遍历下标,在可跳范围内,按照状态转移方程更新 dp[i] 的值即可。

class Solution:
    def maxJumps(self, arr: List[int], d: int) -> int:
        l = len(arr)
        A = [[i, arr[i]] for i in range(l)]
        A.sort(key=lambda x:x[1])
        dp = [1 for _ in range(l)]
        for index, height in A:
            cur = 1
            # 向左找
            for i in range(index-1, max(index-d, 0)-1, -1):
                if arr[i] >= height:
                    break
                cur = max(cur, dp[i]+1)
            # 向右找
            for i in range(index+1, min(index+d, l-1)+1):
                if arr[i] >= height:
                    break
                cur = max(cur, dp[i]+1)          
            dp[index] = max(dp[index], cur)
        return max(dp)

动态规划真是巧妙呀!

This is LeetCode Weekly Contest 174.

1341. The K Weakest Rows in a Matrix

Given a binary matrix, return the indices of the k rows with the fewest 1s. Python makes this almost embarrassingly concise.

class Solution:
    def kWeakestRows(self, mat: List[List[int]], k: int) -> List[int]:
        s = [[i, sum(mat[i])] for i in range(len(mat))]
        s.sort(key=lambda x: x[1])
        return [x[0] for x in s[:k]]

1342. Reduce Array Size to The Half

Given an array, in each step you can remove all occurrences of one number. Find the minimum number of steps to reduce the array to at most half its original size.

The strategy: sort numbers by frequency (highest first), then greedily remove the most frequent ones until the removed count reaches half the array length.

class Solution:
    def minSetSize(self, arr: List[int]) -> int:
        dic = dict()
        for i in arr:
            if i not in dic:
                dic[i] = 1
            else:
                dic[i] += 1
        v = list(dic.values())
        v.sort(reverse=True)
        count = 0
        ans = 0
        for i in v:
            count += i
            ans += 1
            if count * 2 >= len(arr):
                return ans

1339. Maximum Product of Splitted Binary Tree

Remove one edge from a binary tree to create two subtrees. Maximize the product of their node-value sums. Return the result modulo 1e9+7.

The approach (credit to this solution):

  1. Post-order traverse the tree; record the sum of every subtree.
  2. For each possible cut, the product = subtree_sum × (total_sum − subtree_sum). Take the maximum.
  3. Apply the modulo at the end.
class Solution:
    def maxProduct(self, root: TreeNode) -> int:
        sums = []

        def postOrder(root: TreeNode):
            if not root:
                return 0
            res = root.val + postOrder(root.left) + postOrder(root.right)
            sums.append(res)
            return res

        s = postOrder(root)
        ans = max(i * (s - i) for i in sums)
        return int(ans % (1e9 + 7))

1344. Jump Game V

Dynamic programming. Define dp[i] as the maximum number of indices reachable starting from index i. The answer is max(dp).

Transition: from index i (height arr[i]), you can jump to index j within distance d if arr[j] < arr[i]. So:

\[dp[i] = \max_{j \in \text{reachable from } i}(dp[j] + 1)\]

Key insight: process indices in order of increasing height. This guarantees that when computing dp[i], all reachable dp[j] values are already finalized (since they're shorter).

Base case: all dp[i] = 1 (every position can at least “jump” to itself).

class Solution:
    def maxJumps(self, arr: List[int], d: int) -> int:
        l = len(arr)
        A = [[i, arr[i]] for i in range(l)]
        A.sort(key=lambda x: x[1])
        dp = [1] * l
        for index, height in A:
            cur = 1
            # Search left
            for i in range(index - 1, max(index - d, 0) - 1, -1):
                if arr[i] >= height:
                    break
                cur = max(cur, dp[i] + 1)
            # Search right
            for i in range(index + 1, min(index + d, l - 1) + 1):
                if arr[i] >= height:
                    break
                cur = max(cur, dp[i] + 1)
            dp[index] = max(dp[index], cur)
        return max(dp)

DP never ceases to be elegant.