码迷,mamicode.com
首页 > 其他好文 > 详细

[LeetCode#52]N-Queens II

时间:2015-08-21 12:45:01      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:

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;
    }
}

 

[LeetCode#52]N-Queens II

标签:

原文地址:http://www.cnblogs.com/airwindow/p/4747141.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!