The problem "Alphabet Board Path" presents a special 5x5 board where each cell contains a lowercase English letter from 'a' to 'y', and the letter 'z' is located alone in the next row at position (5, 0). The board looks like this:
a b c d e f g h i j k l m n o p q r s t u v w x y z
You start at position (0, 0) (which is 'a'). Given a string target
consisting of lowercase English letters, you need to generate a path from the starting position to spell out the target
string by moving up (U
), down (D
), left (L
), or right (R
) on the board. After reaching each letter, you must append a !
to indicate that the letter has been selected. The result should be a single string representing the moves and selections for the entire target
.
Constraints:
target
.target
.
To solve this problem, the first instinct might be to simulate every possible path for each letter in target
, but that would be highly inefficient. Instead, a better approach is to:
target
, calculate the difference in rows and columns from the current position.The main challenge is to avoid stepping outside the board, especially when dealing with 'z'. The solution is to always move vertically before horizontally when moving up to 'z', and horizontally before vertically when moving down from 'z'.
Let's break down the solution step by step:
target
, find its target coordinates.dr
) and columns (dc
) between the current and target positions.
This approach ensures that you always generate a valid and efficient path for any target
.
Let's consider the input target = "leet"
.
The final output is DDR!UURRR!!DDDD!
.
Brute-force approach: If you tried all possible paths, the time complexity would be exponential in the length of target
and the size of the board, which is infeasible.
Optimized approach:
target
. For each letter, you perform a constant number of operations (calculating moves and appending to the result).
The "Alphabet Board Path" problem is elegantly solved by mapping each letter to its board coordinates and calculating the shortest valid path between consecutive letters in the target
string. By handling the special case of 'z' and always moving in a safe order, we avoid invalid moves and ensure correctness. The solution is efficient, intuitive, and leverages simple coordinate arithmetic to generate the required path.
class Solution:
def alphabetBoardPath(self, target: str) -> str:
pos = {c: (divmod(ord(c) - ord('a'), 5)) for c in 'abcdefghijklmnopqrstuvwxyz'}
res = []
x, y = 0, 0
for ch in target:
nx, ny = pos[ch]
# Move up or left first to avoid invalid moves (especially for 'z')
if nx < x:
res.append('U' * (x - nx))
if ny < y:
res.append('L' * (y - ny))
if nx > x:
res.append('D' * (nx - x))
if ny > y:
res.append('R' * (ny - y))
res.append('!')
x, y = nx, ny
return ''.join(res)
class Solution {
public:
string alphabetBoardPath(string target) {
vector<pair<int, int>> pos(26);
for (int i = 0; i < 26; ++i) {
pos[i] = {i / 5, i % 5};
}
int x = 0, y = 0;
string res;
for (char ch : target) {
int nx = pos[ch - 'a'].first, ny = pos[ch - 'a'].second;
// Move up or left first to avoid invalid moves (especially for 'z')
if (nx < x) res.append(x - nx, 'U');
if (ny < y) res.append(y - ny, 'L');
if (nx > x) res.append(nx - x, 'D');
if (ny > y) res.append(ny - y, 'R');
res += '!';
x = nx; y = ny;
}
return res;
}
};
class Solution {
public String alphabetBoardPath(String target) {
int[][] pos = new int[26][2];
for (int i = 0; i < 26; i++) {
pos[i][0] = i / 5;
pos[i][1] = i % 5;
}
int x = 0, y = 0;
StringBuilder res = new StringBuilder();
for (char ch : target.toCharArray()) {
int nx = pos[ch - 'a'][0], ny = pos[ch - 'a'][1];
// Move up or left first to avoid invalid moves (especially for 'z')
if (nx < x) for (int i = 0; i < x - nx; i++) res.append('U');
if (ny < y) for (int i = 0; i < y - ny; i++) res.append('L');
if (nx > x) for (int i = 0; i < nx - x; i++) res.append('D');
if (ny > y) for (int i = 0; i < ny - y; i++) res.append('R');
res.append('!');
x = nx; y = ny;
}
return res.toString();
}
}
var alphabetBoardPath = function(target) {
const pos = {};
for (let i = 0; i < 26; i++) {
pos[String.fromCharCode(97 + i)] = [Math.floor(i / 5), i % 5];
}
let res = '';
let x = 0, y = 0;
for (let ch of target) {
let [nx, ny] = pos[ch];
// Move up or left first to avoid invalid moves (especially for 'z')
if (nx < x) res += 'U'.repeat(x - nx);
if (ny < y) res += 'L'.repeat(y - ny);
if (nx > x) res += 'D'.repeat(nx - x);
if (ny > y) res += 'R'.repeat(ny - y);
res += '!';
x = nx; y = ny;
}
return res;
};