zoukankan      html  css  js  c++  java
  • [LeetCode#52]N-Queens II

    Problem:

    Follow up for N-Queens problem.

    Now, instead outputting board configurations, return the total number of distinct solutions.

    link:

    https://leetcode.com/problems/n-queens-ii/

    Analysis:

    Prolem definition:
    https://en.wikipedia.org/wiki/Eight_queens_puzzle
    --------------------------------------------------------------------------------------
    solution 1: (Wrong solution, no two queens could be placed on the same diagonal line.)
        public int totalNQueens(int n) {
            if (n <= 0)
                return 0;
            ArrayList<Integer> ret = new ArrayList<Integer> ();
            ret.add(0);
            boolean[] used_column = new boolean[n];
            for (int j = 0; j < n; j++) {
                helper(used_column, n, 0, j, ret);
            }
            return ret.get(0);
        }
    
        private void helper(boolean[] used_column, int n, int i, int j, ArrayList<Integer> ret) {
            if (i == n - 1 && used_column[j] == false) {
                ret.set(0, ret.get(0) + 1);
                return;
            }
            if (used_column[j]) {
                return;
            } else{
                used_column[j] = true;
                for (int next_column = 0; next_column < n; next_column ++) {
                    helper(used_column, n, i + 1, next_column, ret);
                }
                used_column[j] = false;
            }
        }
        
        
    At first glance, it seems we have to use a two dimensional array to record each queen's position, since we need to check there are two queens on the same diagonal. However, there is a very important skill in solving this problem: each row would only taken up a single queen. 
    Here, we introduce a more elegant and powerful solution for this problem.
    Basic idea:
    We check each new placement against the post placement, it is valid we continue to place on the next row. (the same idea as above solution). However could significantly alleviate the coding work, by use inherently backtracking. 
    At above solution, 
    helper(boolean[] used_column, int n, int i, int j, ArrayList<Integer> ret)
    ------------------------------------------------------------------------
    we specify the column number j for the row i. The incovenience for this method is that we need obviously recover the used_column's state before we specify the column number j+1.
    This design introduce the following code snippt.
    ------------------------------------------------------------
    used_column[j] = true;
    for (int next_column = 0; next_column < n; next_column ++) {
        helper(used_column, n, i + 1, next_column, ret);
    }
    used_column[j] = false; (for back tracking purpose)
    
    Also introduce following ugly code snippt when invoking helper.
    for (int j = 0; j < n; j++) {
        helper(used_column, n, 0, j, ret);
    }
    
    The above way is too ugly for this probelm. We could take advantage of "for-loop" over the same element, so as to avoid obviously backtracking.
    helper(int row, int n, int[] column_for_row, ArrayList<Integer> ret)
    At each helper, we test against each column placement for a row. 
    for (int i = 0; i < n; i++) {
        column_for_row[row] = i;
        if (isValid(row, column_for_row))
            helper(row + 1, n, column_for_row, ret);
    }
    Even the current placement is not valid, the for loop could easily take us for the next column placement by overwriting the column_for_row[row] into i+1.
    
    Skills:
    1. use the exceed case as base case. 
    Since at each helper, we firstly check if the current placement is valid, and then go to the next row. If we reach the row n, it means the rows before n-1 are all valid.
    if (row == n) {
        ret.set(0, ret.get(0) + 1);
        return;
    }
    
    2. use the column_for_row to check agianst vioation cases.
    ------------------------------------------------------------
    2.1 two queens were placed in the same column.
    if (column_for_row[i] == column_for_row[row])
    
    2.2 two queens on the same diagonal line. 
    if ((row - i) == Math.abs(column_for_row[row] - column_for_row[i]))
    Note: must use abs, not sure which placement is at the lower column.
    
    
    Time complexity:
    Even though this question only ask for the total count. We still have to search along all possible routines.
    At each row, we could place a queen on any column. (at least we have tested for each placement)
    Thus the time complexity is sadly O(n^2)

    Solution:

    public class Solution {
        public int totalNQueens(int n) {
            if (n <= 0)
                return 0;
            ArrayList<Integer> ret = new ArrayList<Integer> ();
            ret.add(0);
            int[] column_for_row = new int[n];
            helper(0, n, column_for_row, ret);
            return ret.get(0);
        }
        
        private void helper(int row, int n, int[] column_for_row, ArrayList<Integer> ret) {
            if (row == n) {
                ret.set(0, ret.get(0) + 1);
                return;
            }
            //a totally different way of thinking!!!!
            for (int i = 0; i < n; i++) {
                column_for_row[row] = i;
                if (isValid(row, column_for_row))
                    helper(row + 1, n, column_for_row, ret);
            }
        }
        
        private boolean isValid(int row, int[] column_for_row) {
            for (int i = 0; i < row; i++) {
                if (column_for_row[i] == column_for_row[row] || (row - i) == Math.abs(column_for_row[row] - column_for_row[i]))
                    return false;
            }   
            return true;
        }
    }
  • 相关阅读:
    0909《操作系统教程》理解和认识
    1230《操作系统教程》实验四 主存空间的分配和回收模拟
    1203《操作系统教程》实验三 进程调度模拟程序 ——实验点评
    1203《操作系统教程》实验三 进程调度模拟程序
    1111《操作系统教程》实验二 作业调度模拟程序
    实验四 主存空间的分配和回收模拟
    实验三同学互评
    实验三 进程调度模拟程序
    实验二、作业调度模拟实验
    实验一报告
  • 原文地址:https://www.cnblogs.com/airwindow/p/4747141.html
Copyright © 2011-2022 走看看