Rotate Image

You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise). Follow up: Could you do this in-place?

难度:medium

Solution: Level by Level Movement

从最外层开始,把每个元素直接swap到对应的位置。


public class Solution {
    public void rotate(int[][] matrix) {
        int up = 0, down = matrix.length - 1, left = 0, right = matrix.length - 1;
        int n = matrix.length - 1;
        while(up < down) {
            for(int i = left; i < right; ++i) {
                int temp = matrix[down][i];
                matrix[down][i] = matrix[n - i][right];
                matrix[n - i][right] = matrix[up][n - i];
                matrix[up][n - i] = matrix[i][left];
                matrix[i][left] = temp;
            }
            ++up;
            --down;
            ++left;
            --right;
        }
    }
}

Solution: Flipping

clockwise rotate first reverse up to down, then swap the symmetry 1 2 3 => 7 8 9 => 7 4 1 4 5 6 => 4 5 6 => 8 5 2 7 8 9 => 1 2 3 => 9 6 3

public class Solution {
    public void rotate(int[][] matrix) {
        int up = 0, down = matrix.length - 1;
        while(up < down) {
            for(int j = 0; j < matrix.length; ++j) {
                int temp = matrix[up][j];
                matrix[up][j] = matrix[down][j];
                matrix[down][j] = temp;
            }
            ++up;
            --down;
        }
        for (int i = 0; i < matrix.length; ++i) {
            for (int j = i + 1; j < matrix[i].length; ++j) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
    }
}

anticlockwise rotate first reverse left to right, then swap the symmetry 1 2 3 => 3 2 1 => 3 6 9 4 5 6 => 6 5 4 => 2 5 8 7 8 9 => 9 8 7 => 1 4 7

public class Solution {
    public void rotate(int[][] matrix) {
        int left = 0, right = matrix.length - 1;
        while(left < right) {
            for(int i = 0; i < matrix.length; ++i) {
                int temp = matrix[i][left];
                matrix[i][left] = matrix[i][right];
                matrix[i][right] = temp;
            }
            ++left;
            --right;
        }
        for (int i = 0; i < matrix.length; ++i) {
            for (int j = i + 1; j < matrix[i].length; ++j) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
    }
}

Spiral Matrix

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

难度:medium

public class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> res = new ArrayList<Integer>();
        if(matrix.length == 0) {
            return res;
        }
        int up = 0, down = matrix.length - 1, left = 0, right = matrix[0].length - 1;

        while(up <= down && left <= right) {
            // up
            for(int j = left; j <= right; ++j) { // while condition has checked the boundary
                res.add(matrix[up][j]);
            }
            ++up;

            // right
            for(int i = up; i <= down; ++i) { // while condition has checked the boundary
                res.add(matrix[i][right]);
            }
            --right;

            // down
            if(up > down) { // check the boundary
                break;
            }
            for(int j = right; j >= left; --j) {
                res.add(matrix[down][j]);
            }
            --down;

            // left
            if(left > right) { // check the boundary
                break;
            }
            for(int i = down; i >= up; --i) {
                res.add(matrix[i][left]);
            }
            ++left;
        }
        return res;
    }
}

Spiral Matrix II

Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.

难度:medium

public class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];

        int up = 0, down = n - 1, left = 0, right = n - 1;
        int num = 1;

        while(up <= down) {
            // up
            for(int i = left; i <= right; ++i) {
                res[up][i] = num++;
            }
            ++up;

            // right
            for(int j = up; j <= down; ++j) {
                res[j][right] = num++;
            }
            --right;

            if(down < up) {
                break;
            }
            for(int i = right; i >= left; --i) {
                res[down][i] = num++;
            }
            --down;

            if(left > right) {
                break;
            }
            for(int j = down; j >= up; --j) {
                res[j][left] = num++;
            }
            ++left;
        }
        return res;
    }
}

Set Matrix Zeroes

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.

难度:medium

public class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;

        boolean firstColumnZero = false;
        boolean firstRowZero = false;
        for(int i = 0; i < m; ++i) {
            if(matrix[i][0] == 0) {
                firstColumnZero = true;
                break;
            }
        }

        for(int j = 0; j < n; ++j) {
            if(matrix[0][j] == 0) {
                firstRowZero = true;
                break;
            }
        }

        for(int i = 1; i < m; ++i) {
            for(int j = 1; j < n; ++j) {
                if(matrix[i][j] == 0) {
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }

        for(int i = 1; i < m; ++i) {
            if(matrix[i][0] == 0) {
                for(int j = 1; j < n; ++j) {
                    matrix[i][j] = 0;
                }
            }
        }

        for(int j = 1; j < n; ++j) {
            if(matrix[0][j] == 0) {
                for(int i = 1; i < m; ++i) {
                    matrix[i][j] = 0;
                }
            }
        }

        if(firstColumnZero) {
            for(int i = 0; i < m; ++i) {
                matrix[i][0] = 0;
            }
        }

        if(firstRowZero) {
            for(int j = 0; j < n; ++j) {
                matrix[0][j] = 0;
            }
        }

    }
}

Search a 2D Matrix

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

难度:medium

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        if(matrix.length == 0) {
            return false;
        }

        int m = matrix.length, n = matrix[0].length;
        int begin = 0, end = m * n - 1, mid, i, j;
        while(begin <= end) {
            mid = begin + ((end - begin) >> 1);
            i = mid / n;
            j = mid % n;

            if(matrix[i][j] == target) {
                return true;
            } else if(matrix[i][j] > target) {
                end = mid - 1;
            } else {
                begin = mid + 1;
            }
        }
        return false;
    }
}

Kth Smallest Element in a Sorted Matrix

Medium

Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix. Note that it is the kth smallest element in the sorted order, not the kth distinct element. Note: You may assume k is always valid, 1 ≤ k ≤ n2.

Solution: Heap

Note: this problem is very similar to the problem - merge k sorted linked list.

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        PriorityQueue<int[]> heap = new PriorityQueue<>((n1, n2) -> n1[0] - n2[0]);
        int bound = Math.min(k, matrix.length);
        for(int i = 0; i < bound; ++i) {
            heap.offer(new int[]{matrix[i][0], i, 0});
        }

        for(int i = 0; i < k - 1; ++i) {
            int[] cur = heap.poll();
            if(cur[2] + 1 < matrix.length) {
                heap.offer(new int[]{matrix[cur[1]][cur[2] + 1], cur[1], cur[2] + 1});
            }
        }
        return heap.poll()[0];
    }
}

Reference

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int start = matrix[0][0], end = matrix[matrix.length - 1][matrix.length - 1];
        while(start < end) {
            int mid = start + ((end - start) >> 1);
            int count = 0;
            for(int i = 0; i < matrix.length; ++i) {
                for(int j = 0; j < matrix.length; ++j) {
                    if(matrix[i][j] > mid) {
                        break;
                    }
                    ++count;
                }
            }

            if(count < k) {
                start = mid + 1;
            } else {
                end = mid;
            }
        }
        return start;
    }
}

Valid Sudoku

Determine if a Sudoku is valid. A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.

难度:medium

Solution: Hashtable

public class Solution {
    public boolean isValidSudoku(char[][] board) {
        Map<Character, Integer> digits = new HashMap<>();
        int m = board.length;
        int n = board[0].length;

        // row
        for(int i = 0; i < m; ++i) {
            digits.clear();
            for(int j = 0; j < n; ++j) {
                if(board[i][j] == '.') {
                    continue;
                }
                if(digits.containsKey(board[i][j])) {
                    return false;
                } else {
                    digits.put(board[i][j], 1);
                }
            }
        }

        // each cell
        for(int cell = 0; cell < 9; ++cell) {
            digits.clear();
            for(int index = 0; index < 9; ++index) {
                int i = index / 3;
                int j = index % 3;
                i += (cell / 3) * 3;
                j += (cell % 3) * 3;
                if(board[i][j] == '.') {
                    continue;
                }
                if(digits.containsKey(board[i][j])) {
                    return false;
                } else {
                    digits.put(board[i][j], 1);
                }
            }
        }
        // column
        for(int j = 0; j < n; ++j) {
            digits.clear();
            for(int i = 0; i < m; ++i) {
                if(board[i][j] == '.') {
                    continue;
                }
                if(digits.containsKey(board[i][j])) {
                    return false;
                } else {
                    digits.put(board[i][j], 1);
                }
            }
        }
        return true;
    }
}

Sudoku Solver

Write a program to solve a Sudoku puzzle by filling the empty cells. Empty cells are indicated by the character '.'. You may assume that there will be only one unique solution.

难度:hard

Solution: Backtracking

public class Solution {
    private char[] digits = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
    public void solveSudoku(char[][] board) {
        solveSudokuHelper(board, 0);
    }
    private boolean solveSudokuHelper(char[][] board, int start) {
        if(start == 81) {
            return true;
        }
        int i = start / 9, j = start % 9;
        if(board[i][j] != '.') {
            return solveSudokuHelper(board, start + 1);
        }
        for(char digit : digits) {
            if(isValid(board, i, j, digit)) {
                board[i][j] = digit;
                if(solveSudokuHelper(board, start + 1)) {
                    return true;
                }
            }
            board[i][j] = '.';
        }
        return false;
    }
    private boolean isValid(char[][] board, int i, int j, char digit) {
        for(int k = 0; k < 9; ++k) {
            if(board[k][j] == digit || board[i][k] == digit || board[k / 3 + (i / 3) * 3][k % 3 + (j / 3) * 3] == digit) {
                return false;
            }
        }
        return true;
    }
}

N-Queens

Given an integer n, return all distinct solutions to the n-queens puzzle. Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space respectively.

难度:hard

Solution: Backtracking

public class Solution {
    private void solveNQueensHelper(int n, int start, List<List<String>> res, List<String> tempRes, boolean[] column, boolean[] angle, boolean[] backAngle) {
        if(start == n) {
            res.add(new ArrayList<String>(tempRes));
            return;
        }

        for(int i = 0; i < n; ++i) {
            if(column[i] || backAngle[i + start] || angle[n - 1 + start - i]) {
                continue;
            }

            column[i] = angle[n - 1 + start - i] = backAngle[i + start] = true;

            StringBuilder place = new StringBuilder();
            for(int j = 0; j < n; ++j) {
                if(j == i) {
                    place.append('Q');
                } else {
                    place.append('.');
                }
            }
            tempRes.add(place.toString());
            solveNQueensHelper(n, start + 1, res, tempRes, column, angle, backAngle);
            tempRes.remove(tempRes.size() - 1);

            column[i] = angle[n - 1 + start - i] = backAngle[i + start] = false;
        }
    }
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new ArrayList<>();
        boolean[] column = new boolean[n];
        boolean[] angle = new boolean[2 * n - 1];
        boolean[] backAngle = new boolean[2 * n - 1];
        solveNQueensHelper(n, 0, res, new ArrayList<String>(), column, angle, backAngle);
        return res;
    }
}

N-Queens II

Follow up for N-Queens problem. Now, instead outputting board configurations, return the total number of distinct solutions.

难度:hard

Solution: Backtracking

public class Solution {
    private int solutions = 0;
    public int totalNQueens(int n) {
        boolean[] column = new boolean[n];
        boolean[] diagonal = new boolean[2*n - 1];
        boolean[] antiDiagonal = new boolean[2*n - 1];
        totalNQueensHelper(n, 0, column, diagonal, antiDiagonal);
        return solutions;
    }
    private void totalNQueensHelper(int n, int start, boolean[] column, boolean[] diagonal, boolean[] antiDiagonal) {
        if(start == n) {
            solutions += 1;
            return;
        }
        for(int j = 0; j < n; ++j) {
            if(!column[j] && !diagonal[n - 1 + j - start] && !antiDiagonal[j + start]) {
                column[j] = diagonal[n - 1 + j - start] = antiDiagonal[j + start] = true;
                totalNQueensHelper(n, start + 1, column, diagonal, antiDiagonal);
                column[j] = diagonal[n - 1 + j - start] = antiDiagonal[j + start] = false;
            }
        }
    }
}

Surrounded Regions

Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A region is captured by flipping all 'O's into 'X's in that surrounded region.

难度:medium 这个问题实际上是一个Connected Components问题。

Solution: DFS

public class Solution {
    private void dfs(char[][] board, int i, int j) {
        if(i >= 0 && i < board.length && j >= 0 && j < board[0].length && board[i][j] == 'O') {
            board[i][j] = 'I';
            if(i > 1) {
                dfs(board, i - 1, j);
            }
            if(i < board.length - 2) {
                dfs(board, i + 1, j);
            }
            if(j > 1) {
                dfs(board, i, j - 1);
            }
            if(j < board[0].length - 2) {
                dfs(board, i, j + 1);
            }
        }
    }
    public void solve(char[][] board) {
        if(board.length == 0 || board[0].length == 0) {
            return;
        }
        int m = board.length, n = board[0].length;
        for(int i = 0; i < m; ++i) {
            if(board[i][0] == 'O') {
                board[i][0] = 'I';
                dfs(board, i, 1);
            }
            if(board[i][n - 1] == 'O') {
                board[i][n - 1] = 'I';
                dfs(board,i, n - 2);
            }
        }
        for(int j = 0; j < n; ++j) {
            if(board[0][j] == 'O') {
                board[0][j] = 'I';
                dfs(board, 1, j);
            }
            if(board[m - 1][j] == 'O') {
                board[m - 1][j] = 'I';
                dfs(board, m - 2, j);
            }
        }

        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
        }
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(board[i][j] == 'I') {
                    board[i][j] = 'O';
                }
            }
        }
    }
}

Solution: BFS

public class Solution {
    public void solve(char[][] board) {
        if(board.length == 0) {
            return;
        }
        int m = board.length, n = board[0].length;
        Queue<Integer> elements = new LinkedList<>();
        for(int i = 0; i < m; ++i) {
            if(board[i][0] == 'O') {
                elements.add(i * n + 0);
            }
            if(board[i][n - 1] == 'O') {
                elements.add(i * n + n - 1);
            }
        }
        for(int j = 1; j < n - 1; ++j) {
            if(board[0][j] == 'O') {
                elements.add(0 * n + j);
            }
            if(board[m - 1][j] == 'O') {
                elements.add((m - 1) * n + j);
            }
        }
        while(!elements.isEmpty()) {
            int index = elements.remove();
            int i = index / n, j = index % n;
            board[i][j] = 'I';
            if(i - 1 >= 0 && board[i - 1][j] == 'O') {
                elements.add((i - 1) * n + j);
            }
            if(i + 1 != m && board[i + 1][j] == 'O') {
                elements.add((i + 1) * n + j);
            }
            if(j - 1 >= 0 && board[i][j - 1] == 'O') {
                elements.add(i * n + j - 1);
            }
            if(j + 1 != n && board[i][j + 1] == 'O') {
                elements.add(i * n + j + 1);
            }
        }
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(board[i][j] == 'O') {
                    board[i][j] = 'X';
                }
            }
        }
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(board[i][j] == 'I') {
                    board[i][j] = 'O';
                }
            }
        }
    }
}

Perfect Rectangle

Hard

Given N axis-aligned rectangles where N > 0, determine if they all together form an exact cover of a rectangular region.

Each rectangle is represented as a bottom-left point and a top-right point. For example, a unit square is represented as [1,1,2,2]. (coordinate of bottom-left point is (1, 1) and top-right point is (2, 2)).

Solution: Hash Table

class Solution {
    public boolean isRectangleCover(int[][] rectangles) {
        Set<String> set = new HashSet<>();
        int down = Integer.MAX_VALUE, left = Integer.MAX_VALUE, top = Integer.MIN_VALUE, right = Integer.MIN_VALUE;
        int area = 0;
        for(int[] rec : rectangles) {
            down = Math.min(rec[0], down);
            left = Math.min(rec[1], left);
            top = Math.max(rec[2], top);
            right = Math.max(rec[3], right);
            area += (rec[2] - rec[0]) * (rec[3] - rec[1]);
            String s1 = rec[0] + " " + rec[1];
            String s2 = rec[0] + " " + rec[3];
            String s3 = rec[2] + " " + rec[3];
            String s4 = rec[2] + " " + rec[1];

            if (!set.add(s1)) set.remove(s1);
            if (!set.add(s2)) set.remove(s2);
            if (!set.add(s3)) set.remove(s3);
            if (!set.add(s4)) set.remove(s4);
        }

        if (!set.contains(down + " " + left) || 
            !set.contains(down + " " + right) || 
            !set.contains(top + " " + left) || 
            !set.contains(top + " " + right) || 
            set.size() != 4) {
            return false;
        }

        return area == (top - down) * (right - left);
    }
}

results matching ""

    No results matching ""