Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Build confidence with an intuition-first walkthrough focused on array fundamentals.
Tic-tac-toe is played by two players A and B on a 3 x 3 grid. The rules of Tic-Tac-Toe are:
' '.A always places 'X' characters, while the second player B always places 'O' characters.'X' and 'O' characters are always placed into empty squares, never on filled ones.Given a 2D integer array moves where moves[i] = [rowi, coli] indicates that the ith move will be played on grid[rowi][coli]. return the winner of the game if it exists (A or B). In case the game ends in a draw return "Draw". If there are still movements to play return "Pending".
You can assume that moves is valid (i.e., it follows the rules of Tic-Tac-Toe), the grid is initially empty, and A will play first.
Example 1:
Input: moves = [[0,0],[2,0],[1,1],[2,1],[2,2]] Output: "A" Explanation: A wins, they always play first.
Example 2:
Input: moves = [[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]] Output: "B" Explanation: B wins.
Example 3:
Input: moves = [[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]] Output: "Draw" Explanation: The game ends in a draw since there are no moves to make.
Constraints:
1 <= moves.length <= 9moves[i].length == 20 <= rowi, coli <= 2moves.moves follow the rules of tic tac toe.Problem summary: Tic-tac-toe is played by two players A and B on a 3 x 3 grid. The rules of Tic-Tac-Toe are: Players take turns placing characters into empty squares ' '. The first player A always places 'X' characters, while the second player B always places 'O' characters. 'X' and 'O' characters are always placed into empty squares, never on filled ones. The game ends when there are three of the same (non-empty) character filling any row, column, or diagonal. The game also ends if all squares are non-empty. No more moves can be played if the game is over. Given a 2D integer array moves where moves[i] = [rowi, coli] indicates that the ith move will be played on grid[rowi][coli]. return the winner of the game if it exists (A or B). In case the game ends in a draw return "Draw". If there are still movements to play return "Pending". You can assume that moves is valid (i.e., it follows the rules of
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
[[0,0],[2,0],[1,1],[2,1],[2,2]]
[[0,0],[1,1],[0,1],[0,2],[1,0],[2,0]]
[[0,0],[1,1],[2,0],[1,0],[1,2],[2,1],[0,1],[0,2],[2,2]]
categorize-box-according-to-criteria)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1275: Find Winner on a Tic Tac Toe Game
class Solution {
public String tictactoe(int[][] moves) {
int n = moves.length;
int[] cnt = new int[8];
for (int k = n - 1; k >= 0; k -= 2) {
int i = moves[k][0], j = moves[k][1];
cnt[i]++;
cnt[j + 3]++;
if (i == j) {
cnt[6]++;
}
if (i + j == 2) {
cnt[7]++;
}
if (cnt[i] == 3 || cnt[j + 3] == 3 || cnt[6] == 3 || cnt[7] == 3) {
return k % 2 == 0 ? "A" : "B";
}
}
return n == 9 ? "Draw" : "Pending";
}
}
// Accepted solution for LeetCode #1275: Find Winner on a Tic Tac Toe Game
func tictactoe(moves [][]int) string {
n := len(moves)
cnt := [8]int{}
for k := n - 1; k >= 0; k -= 2 {
i, j := moves[k][0], moves[k][1]
cnt[i]++
cnt[j+3]++
if i == j {
cnt[6]++
}
if i+j == 2 {
cnt[7]++
}
if cnt[i] == 3 || cnt[j+3] == 3 || cnt[6] == 3 || cnt[7] == 3 {
if k%2 == 0 {
return "A"
}
return "B"
}
}
if n == 9 {
return "Draw"
}
return "Pending"
}
# Accepted solution for LeetCode #1275: Find Winner on a Tic Tac Toe Game
class Solution:
def tictactoe(self, moves: List[List[int]]) -> str:
n = len(moves)
cnt = [0] * 8
for k in range(n - 1, -1, -2):
i, j = moves[k]
cnt[i] += 1
cnt[j + 3] += 1
if i == j:
cnt[6] += 1
if i + j == 2:
cnt[7] += 1
if any(v == 3 for v in cnt):
return "B" if k & 1 else "A"
return "Draw" if n == 9 else "Pending"
// Accepted solution for LeetCode #1275: Find Winner on a Tic Tac Toe Game
struct Solution;
impl Solution {
fn tictactoe(moves: Vec<Vec<i32>>) -> String {
let mut board = [[' '; 3]; 3];
let mut player = 'X';
let n = moves.len();
for m in moves {
let r = m[0] as usize;
let c = m[1] as usize;
board[r][c] = player;
player = if player == 'X' { 'O' } else { 'X' };
}
let ss = [
[(0, 0), (0, 1), (0, 2)],
[(1, 0), (1, 1), (1, 2)],
[(2, 0), (2, 1), (2, 2)],
[(0, 0), (1, 0), (2, 0)],
[(0, 1), (1, 1), (2, 1)],
[(0, 2), (1, 2), (2, 2)],
[(0, 0), (1, 1), (2, 2)],
[(0, 2), (1, 1), (2, 0)],
];
for s in &ss {
let mut a = 0;
let mut b = 0;
for p in s {
let i = p.0;
let j = p.1;
match board[i][j] {
'X' => a += 1,
'O' => b += 1,
_ => {}
}
}
if a == 3 {
return "A".to_string();
}
if b == 3 {
return "B".to_string();
}
}
if n == 9 {
return "Draw".to_string();
}
"Pending".to_string()
}
}
#[test]
fn test() {
let moves = vec_vec_i32![[0, 0], [2, 0], [1, 1], [2, 1], [2, 2]];
let res = "A".to_string();
assert_eq!(Solution::tictactoe(moves), res);
let moves = vec_vec_i32![[0, 0], [1, 1], [0, 1], [0, 2], [1, 0], [2, 0]];
let res = "B".to_string();
assert_eq!(Solution::tictactoe(moves), res);
let moves = vec_vec_i32![
[0, 0],
[1, 1],
[2, 0],
[1, 0],
[1, 2],
[2, 1],
[0, 1],
[0, 2],
[2, 2]
];
let res = "Draw".to_string();
assert_eq!(Solution::tictactoe(moves), res);
let moves = vec_vec_i32![[0, 0], [1, 1]];
let res = "Pending".to_string();
assert_eq!(Solution::tictactoe(moves), res);
}
// Accepted solution for LeetCode #1275: Find Winner on a Tic Tac Toe Game
function tictactoe(moves: number[][]): string {
const n = moves.length;
const cnt = new Array(8).fill(0);
for (let k = n - 1; k >= 0; k -= 2) {
const [i, j] = moves[k];
cnt[i]++;
cnt[j + 3]++;
if (i == j) {
cnt[6]++;
}
if (i + j == 2) {
cnt[7]++;
}
if (cnt[i] == 3 || cnt[j + 3] == 3 || cnt[6] == 3 || cnt[7] == 3) {
return k % 2 == 0 ? 'A' : 'B';
}
}
return n == 9 ? 'Draw' : 'Pending';
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.