From 33ef7f7743b11bc51ee9204b9ca1d009ac8250af Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 5 Jul 2026 04:41:00 +0000 Subject: [PATCH] feat: add solution for 1301. Number of Paths with Max Score --- .../analysis.md | 102 ++++++++++++++++++ .../problem.md | 56 ++++++++++ .../solution_daily_20260705.go | 74 +++++++++++++ .../solution_daily_20260705_test.go | 59 ++++++++++ 4 files changed, 291 insertions(+) create mode 100644 problems/1301-number-of-paths-with-max-score/analysis.md create mode 100644 problems/1301-number-of-paths-with-max-score/problem.md create mode 100644 problems/1301-number-of-paths-with-max-score/solution_daily_20260705.go create mode 100644 problems/1301-number-of-paths-with-max-score/solution_daily_20260705_test.go diff --git a/problems/1301-number-of-paths-with-max-score/analysis.md b/problems/1301-number-of-paths-with-max-score/analysis.md new file mode 100644 index 0000000..969a28d --- /dev/null +++ b/problems/1301-number-of-paths-with-max-score/analysis.md @@ -0,0 +1,102 @@ +# 1301. Number of Paths with Max Score + +[LeetCode Link](https://leetcode.com/problems/number-of-paths-with-max-score/) + +Difficulty: Hard +Topics: Array, Dynamic Programming, Matrix +Acceptance Rate: 49.6% + +## Hints + +### Hint 1 + +You start at the bottom-right `'S'` and must reach the top-left `'E'`, moving only +up, left, or up-left. Notice that every legal move strictly decreases your position +toward `(0, 0)`. Whenever a problem asks for the *best value over all paths in a grid* +where movement is restricted to a fixed set of directions, think **dynamic programming +over the grid** rather than brute-force search — the number of paths is exponential, +but the number of cells is not. + +### Hint 2 + +This problem has two coupled quantities: the **maximum score** reachable at a cell, and +the **number of distinct paths** that achieve that maximum. A single DP value is not +enough — carry a *pair* `(bestSum, count)` for each cell. When you combine several +incoming directions, the maximum sum is decided first, and only the neighbors that tie +for that maximum contribute to the path count. Remember to take the count modulo +`10^9 + 7`. + +### Hint 3 + +Fill the table in an order where a cell's predecessors are already computed. Because a +move goes *toward* `(0,0)`, a cell `(i, j)` is reached *from* one of `(i+1, j)`, +`(i, j+1)`, or `(i+1, j+1)` (the cells you were standing on before the move). So iterate +`i` from `n-1` down to `0` and `j` from `n-1` down to `0`. For each non-obstacle cell, +look at those three predecessors, pick the maximum reachable sum, sum the path counts of +every predecessor tying for that maximum, then add the cell's own digit value (`'E'` and +`'S'` contribute `0`). Mark obstacles and truly unreachable cells so they can never feed +a path. + +## Approach + +We run a bottom-up DP on the `n x n` board. + +Define two tables: + +- `dp[i][j]` = the maximum sum of digits collectable on a path from `S` (the + bottom-right cell) to cell `(i, j)`. We use `-1` as a sentinel meaning "unreachable". +- `cnt[i][j]` = the number of distinct paths from `S` to `(i, j)` achieving `dp[i][j]`, + taken modulo `10^9 + 7`. + +**Base case.** The journey begins on `S` at `(n-1, n-1)`, so `dp[n-1][n-1] = 0` and +`cnt[n-1][n-1] = 1`. + +**Transition.** A move from the previous cell to the current cell goes up, left, or +up-left, which means the current cell `(i, j)` is entered *from* one of its three +"lower/right" neighbors: `(i+1, j)`, `(i, j+1)`, `(i+1, j+1)`. To have those neighbors +already solved, we sweep `i` from `n-1` down to `0` and, inside, `j` from `n-1` down to +`0`. + +For each cell (other than the start): + +1. If it is an obstacle `'X'`, leave it unreachable. +2. Otherwise scan the three predecessors. Track `best`, the largest `dp` value among the + reachable ones, and `ways`, the sum (mod `1e9+7`) of the `cnt` values of every + predecessor whose `dp` equals `best`. +3. If no predecessor is reachable, this cell is unreachable too. +4. Otherwise set `dp[i][j] = best + value`, where `value` is the digit's numeric value, + or `0` when the cell is `'E'` (or `'S'`). Set `cnt[i][j] = ways`. + +**Answer.** The destination is `E` at `(0, 0)`. If `dp[0][0]` is still the sentinel, no +path exists, so return `[0, 0]`. Otherwise return `[dp[0][0], cnt[0][0]]`. + +**Worked example.** For `board = ["E23","2X2","12S"]`, the sweep computes a best sum of +`7` reaching `(0,0)` along the single path `S(2,2) → (2,1)=2 → (2,0)=1 → (1,0)=2 → +(0,0)=E`... wait, the actual max path collects `2 + 2 + 3 = 7` via +`S → (0,2)=3 → (0,1)=2 → E` combined with the right column, and exactly one path attains +`7`, giving `[7, 1]`. In `["E12","1X1","21S"]` two different routes both collect `4`, so +the answer is `[4, 2]`, and the count-merging step is what distinguishes them. + +## Complexity Analysis + +Time Complexity: O(n^2) — each of the `n^2` cells does a constant amount of work +(inspecting three predecessors). +Space Complexity: O(n^2) for the `dp` and `cnt` tables. This can be reduced to O(n) by +keeping only two rows, but O(n^2) is clear and well within the constraints +(`n <= 100`). + +## Edge Cases + +- **No path exists (example 3, `["E11","XXX","11S"]`).** A wall of obstacles can cut off + `E` entirely. The sentinel `-1` propagates: since no predecessor is reachable, `E` + stays unreachable and we return `[0, 0]` rather than a spurious sum. +- **Obstacle handling.** An `'X'` cell must never contribute a path; treating it as + unreachable (never assigning it a `dp`) prevents it from feeding downstream cells. +- **`'E'` and `'S'` contribute zero.** They are not digits; adding a numeric value for + them would inflate the sum. Only characters `'1'..'9'` add their value. +- **Counting with ties.** When two or three predecessors tie for the best sum, their path + counts must be *added*, not overwritten — this is the whole point of the second output. +- **Modulo on the count only.** The maximum sum is small (at most `9 * (2n-2)`), so only + the path count needs the `10^9 + 7` modulo; applying it to the sum would be wrong. +- **Minimum board size.** With `n = 2`, `E` and `S` are always distinct cells and the + three-predecessor scan still works because out-of-range neighbors are simply skipped. diff --git a/problems/1301-number-of-paths-with-max-score/problem.md b/problems/1301-number-of-paths-with-max-score/problem.md new file mode 100644 index 0000000..536a5f6 --- /dev/null +++ b/problems/1301-number-of-paths-with-max-score/problem.md @@ -0,0 +1,56 @@ +--- +number: "1301" +frontend_id: "1301" +title: "Number of Paths with Max Score" +slug: "number-of-paths-with-max-score" +difficulty: "Hard" +topics: + - "Array" + - "Dynamic Programming" + - "Matrix" +acceptance_rate: 4957.1 +is_premium: false +created_at: "2026-07-05T04:38:03.527460+00:00" +fetched_at: "2026-07-05T04:38:03.527460+00:00" +link: "https://leetcode.com/problems/number-of-paths-with-max-score/" +date: "2026-07-05" +--- + +# 1301. Number of Paths with Max Score + +You are given a square `board` of characters. You can move on the board starting at the bottom right square marked with the character `'S'`. + +You need to reach the top left square marked with the character `'E'`. The rest of the squares are labeled either with a numeric character `1, 2, ..., 9` or with an obstacle `'X'`. In one move you can go up, left or up-left (diagonally) only if there is no obstacle there. + +Return a list of two integers: the first integer is the maximum sum of numeric characters you can collect, and the second is the number of such paths that you can take to get that maximum sum, **taken modulo`10^9 + 7`**. + +In case there is no path, return `[0, 0]`. + + + +**Example 1:** + + + **Input:** board = ["E23","2X2","12S"] + **Output:** [7,1] + + +**Example 2:** + + + **Input:** board = ["E12","1X1","21S"] + **Output:** [4,2] + + +**Example 3:** + + + **Input:** board = ["E11","XXX","11S"] + **Output:** [0,0] + + + + +**Constraints:** + + * `2 <= board.length == board[i].length <= 100` diff --git a/problems/1301-number-of-paths-with-max-score/solution_daily_20260705.go b/problems/1301-number-of-paths-with-max-score/solution_daily_20260705.go new file mode 100644 index 0000000..8d18bff --- /dev/null +++ b/problems/1301-number-of-paths-with-max-score/solution_daily_20260705.go @@ -0,0 +1,74 @@ +package main + +// Problem 1301. Number of Paths with Max Score +// +// Bottom-up dynamic programming over the board. Starting from 'S' at the +// bottom-right, every legal move (up, left, up-left) goes toward 'E' at the +// top-left, so a cell (i, j) is reached from one of (i+1, j), (i, j+1) or +// (i+1, j+1). We sweep i and j from high to low so predecessors are solved +// first. For each cell we carry two values: the maximum collectable sum +// (dp) and the number of paths achieving it (cnt), with cnt taken modulo +// 1e9+7. Unreachable cells are marked with dp = -1. +func pathsWithMaxScore(board []string) []int { + const mod = 1_000_000_007 + n := len(board) + + dp := make([][]int, n) + cnt := make([][]int, n) + for i := range dp { + dp[i] = make([]int, n) + cnt[i] = make([]int, n) + for j := range dp[i] { + dp[i][j] = -1 // sentinel: unreachable + } + } + + // Base case: the path starts on 'S' at the bottom-right corner. + dp[n-1][n-1] = 0 + cnt[n-1][n-1] = 1 + + // Predecessors of (i, j): the cell we stood on before moving here. + dirs := [3][2]int{{1, 0}, {0, 1}, {1, 1}} + + for i := n - 1; i >= 0; i-- { + for j := n - 1; j >= 0; j-- { + if i == n-1 && j == n-1 { + continue // start cell already initialized + } + if board[i][j] == 'X' { + continue // obstacle: stays unreachable + } + + best := -1 + ways := 0 + for _, d := range dirs { + pi, pj := i+d[0], j+d[1] + if pi >= n || pj >= n || dp[pi][pj] < 0 { + continue + } + if dp[pi][pj] > best { + best = dp[pi][pj] + ways = cnt[pi][pj] + } else if dp[pi][pj] == best { + ways = (ways + cnt[pi][pj]) % mod + } + } + + if best < 0 { + continue // no reachable predecessor + } + + value := 0 + if board[i][j] != 'E' { // 'E' and 'S' contribute nothing + value = int(board[i][j] - '0') + } + dp[i][j] = best + value + cnt[i][j] = ways + } + } + + if dp[0][0] < 0 { + return []int{0, 0} + } + return []int{dp[0][0], cnt[0][0]} +} diff --git a/problems/1301-number-of-paths-with-max-score/solution_daily_20260705_test.go b/problems/1301-number-of-paths-with-max-score/solution_daily_20260705_test.go new file mode 100644 index 0000000..6b731a6 --- /dev/null +++ b/problems/1301-number-of-paths-with-max-score/solution_daily_20260705_test.go @@ -0,0 +1,59 @@ +package main + +import ( + "reflect" + "testing" +) + +func TestSolution(t *testing.T) { + tests := []struct { + name string + board []string + expected []int + }{ + { + name: "example 1: single max path", + board: []string{"E23", "2X2", "12S"}, + expected: []int{7, 1}, + }, + { + name: "example 2: two paths tie for max", + board: []string{"E12", "1X1", "21S"}, + expected: []int{4, 2}, + }, + { + name: "example 3: no path due to obstacle wall", + board: []string{"E11", "XXX", "11S"}, + expected: []int{0, 0}, + }, + { + name: "edge case: smallest 2x2 board with digits", + board: []string{"E1", "1S"}, + expected: []int{1, 2}, + }, + { + name: "edge case: 2x2 with diagonal obstacle forces one path", + board: []string{"E1", "XS"}, + expected: []int{1, 1}, + }, + { + name: "edge case: diagonal S-to-E move still reachable past corner obstacles", + board: []string{"EX", "XS"}, + expected: []int{0, 1}, + }, + { + name: "edge case: all nines, max avoids diagonals to collect more cells", + board: []string{"E99", "999", "99S"}, + expected: []int{27, 6}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := pathsWithMaxScore(tt.board) + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("pathsWithMaxScore(%v) = %v, want %v", tt.board, got, tt.expected) + } + }) + } +}