773. Sliding Puzzle
On an 2 x 3 board, there are five tiles labeled from 1 to 5, and an empty square represented by 0. A move consists of choosing 0 and a 4-directionally adjacent number and swapping it.
The state of the board is solved if and only if the board is [[1,2,3],[4,5,0]].
Given the puzzle board board, return the least number of moves required so that the state of the board is solved. If it is impossible for the state of the board to be solved, return -1.
Example 1:
Input: board = [[1,2,3],[4,0,5]]
Output: 1
Explanation: Swap the 0 and the 5 in one move.
Example 2:
Input: board = [[1,2,3],[5,4,0]]
Output: -1
Explanation: No number of moves will make the board solved.
Example 3:
Input: board = [[4,1,2],[5,0,3]]
Output: 5
Explanation: 5 is the smallest number of moves that solves the board.
An example path:
After move 0: [[4,1,2],[5,0,3]]
After move 1: [[4,1,2],[0,5,3]]
After move 2: [[0,1,2],[4,5,3]]
After move 3: [[1,0,2],[4,5,3]]
After move 4: [[1,2,0],[4,5,3]]
After move 5: [[1,2,3],[4,5,0]]
Constraints:
- board.length == 2
- board[i].length == 3
- 0 <= board[i][j] <= 5
- Each value board[i][j] is unique.
From: LeetCode
Link: 773. Sliding Puzzle
Solution:
Ideas:
1. State Representation: Each state contains the board configuration and the number of moves taken to reach it.
2. BFS Queue: Used to explore states level by level, ensuring we find the minimum number of moves.
3. Visited Tracking: Uses a hash table to avoid revisiting the same board configuration.
4. Move Generation: For each state, finds the empty space (0) and tries swapping it with all adjacent numbers (up, down, left, right).
Code:
#define ROWS 2
#define COLS 3
#define MAX_STATES 1000
// Structure to represent a board state
typedef struct {
int board[ROWS][COLS];
int moves;
} State;
// Queue for BFS
typedef struct {
State states[MAX_STATES];
int front, rear;
} Queue;
void initQueue(Queue* q) {
q->front = 0;
q->rear = 0;
}
bool isEmpty(Queue* q) {
return q->front == q->rear;
}
void enqueue(Queue* q, State state) {
q->states[q->rear] = state;
q->rear = (q->rear + 1) % MAX_STATES;
}
State dequeue(Queue* q) {
State state = q->states[q->front];
q->front = (q->front + 1) % MAX_STATES;
return state;
}
// Convert board to string for hashing/comparison
void boardToString(int board[ROWS][COLS], char* str) {
int idx = 0;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
str[idx++] = '0' + board[i][j];
}
}
str[idx] = '\0';
}
// Check if current board matches target
bool isTarget(int board[ROWS][COLS]) {
int target[ROWS][COLS] = {{1,2,3},{4,5,0}};
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (board[i][j] != target[i][j]) {
return false;
}
}
}
return true;
}
// Find position of 0 (empty space)
void findZero(int board[ROWS][COLS], int* row, int* col) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (board[i][j] == 0) {
*row = i;
*col = j;
return;
}
}
}
}
// Copy board
void copyBoard(int src[ROWS][COLS], int dest[ROWS][COLS]) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
dest[i][j] = src[i][j];
}
}
}
// Simple hash table using array (for small state space)
bool visited[1000000];
int hashBoard(int board[ROWS][COLS]) {
int hash = 0;
int multiplier = 1;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
hash += board[i][j] * multiplier;
multiplier *= 10;
}
}
return hash % 1000000;
}
int slidingPuzzle(int** board, int boardSize, int* boardColSize) {
// Initialize visited array
memset(visited, false, sizeof(visited));
// Convert input to local board format
int startBoard[ROWS][COLS];
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
startBoard[i][j] = board[i][j];
}
}
// Check if already solved
if (isTarget(startBoard)) {
return 0;
}
// BFS setup
Queue q;
initQueue(&q);
State startState;
copyBoard(startBoard, startState.board);
startState.moves = 0;
enqueue(&q, startState);
int startHash = hashBoard(startBoard);
visited[startHash] = true;
// Direction vectors for adjacent moves (up, down, left, right)
int dr[] = {-1, 1, 0, 0};
int dc[] = {0, 0, -1, 1};
while (!isEmpty(&q)) {
State current = dequeue(&q);
// Find position of 0
int zeroRow, zeroCol;
findZero(current.board, &zeroRow, &zeroCol);
// Try all four directions
for (int dir = 0; dir < 4; dir++) {
int newRow = zeroRow + dr[dir];
int newCol = zeroCol + dc[dir];
// Check bounds
if (newRow >= 0 && newRow < ROWS && newCol >= 0 && newCol < COLS) {
// Create new state by swapping
State newState;
copyBoard(current.board, newState.board);
newState.moves = current.moves + 1;
// Swap 0 with adjacent number
newState.board[zeroRow][zeroCol] = newState.board[newRow][newCol];
newState.board[newRow][newCol] = 0;
// Check if this is the target
if (isTarget(newState.board)) {
return newState.moves;
}
// Check if we've seen this state before
int newHash = hashBoard(newState.board);
if (!visited[newHash]) {
visited[newHash] = true;
enqueue(&q, newState);
}
}
}
}
// No solution found
return -1;
}