返回介绍

solution / 1200-1299 / 1289.Minimum Falling Path Sum II / README

发布于 2024-06-17 01:03:21 字数 6079 浏览 0 评论 0 收藏 0

1289. 下降路径最小和 II

English Version

题目描述

给你一个 n x n 整数矩阵 grid ,请你返回 非零偏移下降路径 数字和的最小值。

非零偏移下降路径 定义为:从 grid 数组中的每一行选择一个数字,且按顺序选出来的数字中,相邻数字不在原数组的同一列。

 

示例 1:

输入:grid = [[1,2,3],[4,5,6],[7,8,9]]
输出:13
解释:
所有非零偏移下降路径包括:
[1,5,9], [1,5,7], [1,6,7], [1,6,8],
[2,4,8], [2,4,9], [2,6,7], [2,6,8],
[3,4,8], [3,4,9], [3,5,7], [3,5,9]
下降路径中数字和最小的是 [1,5,7] ,所以答案是 13 。

示例 2:

输入:grid = [[7]]
输出:7

 

提示:

  • n == grid.length == grid[i].length
  • 1 <= n <= 200
  • -99 <= grid[i][j] <= 99

解法

方法一:动态规划

我们定义 $f[i][j]$ 表示前 $i$ 行,且最后一个数字在第 $j$ 列的最小数字和。那么状态转移方程为:

$$ f[i][j] = \min_{k \neq j} f[i - 1][k] + grid[i - 1][j] $$

其中 $k$ 表示第 $i - 1$ 行的数字在第 $k$ 列,第 $i$ 行第 $j$ 列的数字为 $grid[i - 1][j]$。

最后答案为 $f[n]$ 中的最小值。

时间复杂度 $O(n^3)$,空间复杂度 $O(n^2)$。其中 $n$ 为矩阵的行数。

实际上,我们也可以维护三个变量 $f$, $g$ 和 $fp$,分别表示前 $i$ 行的最小数字和、第 $i$ 行的第二小数字和以及第 $i$ 行的最小数字在第 $fp$ 列。这样我们就可以将时间复杂度降低到 $O(n^2)$,空间复杂度降低到 $O(1)$。

class Solution:
  def minFallingPathSum(self, grid: List[List[int]]) -> int:
    n = len(grid)
    f = [[0] * n for _ in range(n + 1)]
    for i, row in enumerate(grid, 1):
      for j, v in enumerate(row):
        x = min((f[i - 1][k] for k in range(n) if k != j), default=0)
        f[i][j] = v + x
    return min(f[n])
class Solution {
  public int minFallingPathSum(int[][] grid) {
    int n = grid.length;
    int[][] f = new int[n + 1][n];
    final int inf = 1 << 30;
    for (int i = 1; i <= n; ++i) {
      for (int j = 0; j < n; ++j) {
        int x = inf;
        for (int k = 0; k < n; ++k) {
          if (k != j) {
            x = Math.min(x, f[i - 1][k]);
          }
        }
        f[i][j] = grid[i - 1][j] + (x == inf ? 0 : x);
      }
    }
    int ans = inf;
    for (int x : f[n]) {
      ans = Math.min(ans, x);
    }
    return ans;
  }
}
class Solution {
public:
  int minFallingPathSum(vector<vector<int>>& grid) {
    int n = grid.size();
    int f[n + 1][n];
    memset(f, 0, sizeof(f));
    const int inf = 1 << 30;
    for (int i = 1; i <= n; ++i) {
      for (int j = 0; j < n; ++j) {
        int x = inf;
        for (int k = 0; k < n; ++k) {
          if (k != j) {
            x = min(x, f[i - 1][k]);
          }
        }
        f[i][j] = grid[i - 1][j] + (x == inf ? 0 : x);
      }
    }
    return *min_element(f[n], f[n] + n);
  }
};
func minFallingPathSum(grid [][]int) int {
  n := len(grid)
  f := make([][]int, n+1)
  for i := range f {
    f[i] = make([]int, n)
  }
  const inf = 1 << 30
  for i, row := range grid {
    i++
    for j, v := range row {
      x := inf
      for k := range row {
        if k != j {
          x = min(x, f[i-1][k])
        }
      }
      if x == inf {
        x = 0
      }
      f[i][j] = v + x
    }
  }
  return slices.Min(f[n])
}

方法二

class Solution:
  def minFallingPathSum(self, grid: List[List[int]]) -> int:
    f = g = 0
    fp = -1
    for row in grid:
      ff = gg = inf
      ffp = -1
      for j, v in enumerate(row):
        s = (g if j == fp else f) + v
        if s < ff:
          gg = ff
          ff = s
          ffp = j
        elif s < gg:
          gg = s
      f, g, fp = ff, gg, ffp
    return f
class Solution {
  public int minFallingPathSum(int[][] grid) {
    int f = 0, g = 0;
    int fp = -1;
    final int inf = 1 << 30;
    for (int[] row : grid) {
      int ff = inf, gg = inf;
      int ffp = -1;
      for (int j = 0; j < row.length; ++j) {
        int s = (j != fp ? f : g) + row[j];
        if (s < ff) {
          gg = ff;
          ff = s;
          ffp = j;
        } else if (s < gg) {
          gg = s;
        }
      }
      f = ff;
      g = gg;
      fp = ffp;
    }
    return f;
  }
}
class Solution {
public:
  int minFallingPathSum(vector<vector<int>>& grid) {
    int n = grid.size();
    int f = 0, g = 0, fp = -1;
    const int inf = 1 << 30;
    for (auto& row : grid) {
      int ff = inf, gg = inf;
      int ffp = -1;
      for (int j = 0; j < n; ++j) {
        int s = (fp != j ? f : g) + row[j];
        if (s < ff) {
          gg = ff;
          ff = s;
          ffp = j;
        } else if (s < gg) {
          gg = s;
        }
      }
      f = ff;
      g = gg;
      fp = ffp;
    }
    return f;
  }
};
func minFallingPathSum(grid [][]int) int {
  const inf = 1 << 30
  f, g := 0, 0
  fp := -1
  for _, row := range grid {
    ff, gg := inf, inf
    ffp := -1
    for j, v := range row {
      s := f
      if j == fp {
        s = g
      }
      s += v
      if s < ff {
        ff, gg, ffp = s, ff, j
      } else if s < gg {
        gg = s
      }
    }
    f, g, fp = ff, gg, ffp
  }
  return f
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文