给定行和列的和求可行矩阵

标签: 贪心 数组 矩阵

难度: Medium

给你两个非负整数数组 rowSum 和 colSum ,其中 rowSum[i] 是二维矩阵中第 i 行元素的和, colSum[j] 是第 j 列元素的和。换言之你不知道矩阵里的每个元素,但是你知道每一行和每一列的和。

请找到大小为 rowSum.length x colSum.length 的任意 非负整数 矩阵,且该矩阵满足 rowSum 和 colSum 的要求。

请你返回任意一个满足题目要求的二维矩阵,题目保证存在 至少一个 可行矩阵。

示例 1:

输入:rowSum = [3,8], colSum = [4,7]
输出:[[3,0],
      [1,7]]
解释:
第 0 行:3 + 0 = 3 == rowSum[0]
第 1 行:1 + 7 = 8 == rowSum[1]
第 0 列:3 + 1 = 4 == colSum[0]
第 1 列:0 + 7 = 7 == colSum[1]
行和列的和都满足题目要求,且所有矩阵元素都是非负的。
另一个可行的矩阵为:[[1,2],
                  [3,5]]

示例 2:

输入:rowSum = [5,7,10], colSum = [8,6,8]
输出:[[0,5,0],
      [6,1,0],
      [2,0,8]]

示例 3:

输入:rowSum = [14,9], colSum = [6,9,8]
输出:[[0,9,5],
      [6,0,3]]

示例 4:

输入:rowSum = [1,0], colSum = [1]
输出:[[1],
      [0]]

示例 5:

输入:rowSum = [0], colSum = [0]
输出:[[0]]

提示:

  • 1 <= rowSum.length, colSum.length <= 500
  • 0 <= rowSum[i], colSum[i] <= 108
  • sum(rowSum) == sum(colSum)

Submission

运行时间: 43 ms

内存: 20.3 MB

class Solution:
    def restoreMatrix(self, rowSum: List[int], colSum: List[int]) -> List[List[int]]:
        n, m = len(rowSum), len(colSum)
        matrix = [[0] * m for _ in range(n)]
        i = j = 0
        while i < n and j < m:
            v = min(rowSum[i], colSum[j])
            matrix[i][j] = v
            rowSum[i] -= v
            colSum[j] -= v
            if rowSum[i] == 0:
                i += 1
            if colSum[j] == 0:
                j += 1
        return matrix

Explain

题解的核心思路是贪心算法。对于每个矩阵元素 matrix[i][j],我们选择 rowSum[i] 和 colSum[j] 中较小的一个值作为其值,然后相应地减少 rowSum[i] 和 colSum[j]。这样确保了不会超过任一行或列的总和。对于每个元素的选取,都是尽可能地满足当前行和列的需求,直到填满整个矩阵。

时间复杂度: O(n*m)

空间复杂度: O(n*m)

# 贪心算法构造满足行和列和的矩阵
class Solution:
    def restoreMatrix(self, rowSum: List[int], colSum: List[int]) -> List[List[int]]:
        n, m = len(rowSum), len(colSum) # 获取行和列的数量
        matrix = [[0] * m for _ in range(n)] # 初始化全零矩阵
        i = j = 0 # 初始化行和列的索引
        while i < n and j < m: # 当行和列索引均在范围内时
            v = min(rowSum[i], colSum[j]) # 取行和列和中较小的一个作为当前元素的值
            matrix[i][j] = v # 设置矩阵元素
            rowSum[i] -= v # 更新行和
            colSum[j] -= v # 更新列和
            if rowSum[i] == 0: # 如果当前行和为0,移动到下一行
                i += 1
            if colSum[j] == 0: # 如果当前列和为0,移动到下一列
                j += 1
        return matrix # 返回构造的矩阵

Explore

选择`min(rowSum[i], colSum[j])`作为矩阵元素的值是为了确保不超过当前行和列的最大可能值,同时尽可能地满足行和列的总和要求。这种选择保证了算法的正确性,因为它避免了任何一个行或列的和被超出。从效率上讲,这种方法允许算法在遍历每个元素时立即决定其值,避免了需要回溯或重新调整已填充的值,从而提高了算法的执行效率。

当`rowSum[i]`变为0后,增加i索引移动到下一行是基于当前行已经完全满足其需求的假设。这种做法理论上不会影响列的匹配,因为每一步操作都是基于行和列当前的需求来分配值。只要输入的行和列和是一致的,即总的行和等于总的列和,这种方法最终能够精确匹配所有行和列的需求。

是的,这种做法能够保证所有行的和最终匹配`rowSum`数组中的值。这是因为每次填充矩阵时都是根据当前行和列的需求来决定值的分配,只有当某一列的需求已经被完全满足,即`colSum[j]`为0时,才会移动到下一列。保证了不会有列和被提前耗尽而影响行和的匹配。

贪心策略在这种情况下仍然适用。贪心策略的核心在于每一步都尽可能满足当前行和列的最小需求,这样可以更平衡地分配矩阵中的值,避免任何一个行或列的需求未被满足。即使在极端情况下,例如某些行或列的值非常大或非常小,这种方法仍然能够确保每一步操作都是有效且合理的,从而最终满足所有行和列的总和要求。