private boolean helper(final char[][] board, final int i, final int j) {

        // current row ends; go to next row
        if (j >= 9) {
            return helper(board, i + 1, 0);
        }

        // all the rows are checked, return
        if (i == 9) {
            return true;
        }

        // come to the cell that needs to fill in a number
        if (board[i][j] == '.') {
            // check all numbers to see which number is fit in
            for (int k = 1; k <= 9; k++) {
                board[i][j] = (char) (k + '0');
                if (isValid(board, i, j)) {
                    // check next
                    if (helper(board, i, j + 1)) {
                        return true;
                    }
                }
                // DFS (have to reset the cell after the dfs)
                board[i][j] = '.';
            }
        }
        else {
            // if the column is already filled,
            return helper(board, i, j + 1);
        }
        return false;
    }