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

    The problem:

    The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other.

    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.

    For example,
    There exist two distinct solutions to the 4-queens puzzle:

    [
     [".Q..",  // Solution 1
      "...Q",
      "Q...",
      "..Q."],
    
     ["..Q.",  // Solution 2
      "Q...",
      "...Q",
      ".Q.."]
    ]
    
    My analysis:
    The N-Queuens problem is a typical recursion problem with backtracking property. 
    The key idea:
    At current row, we place the Queue at a column(often use a for loop). Then we validate this placement, if the placement is legal, we step into the next row. 
    1. We need to record following information during the recursion process:(pass through arguments)
    1.1 the total N. this is used for base case checking.
    1.2 the current row. 
    1.3 previous rows's placement(which column).
    1.4 the final result set. 
    private void helper(int n, int cur_row, int[] placed_row, ArrayList<String[]> ret);
    
    2. Check the base case. 
    Skill: like the base case checking we used in other rursive problem. we check the base case at the virtual layer next the last layer. The ration is that: iff we could reach the virtual layer, it indicates the current placed_row is legal in all previous layers.(which means a valid N-Queues placement!)
    if (cur_row == n) { //note we start cur_row from 0, the last row is n-1. 
    ...
    }
    
    3. The skills in backtracking. 
    two invalid cases:
        3.1 two Queues were placed in the same column. 
            placed_row[cur_row] == placed_row[i] 
        3.2 two Queues were placed in a diagonal line. 
            Math.abs(placed_row[cur_row]-placed_row[i]) == cur_row-i
    
    Note: we only check the current row's placement with that of its previous rows.
    private boolean checkNotCollision(int[] placed_row, int cur_row) {
        for (int i = 0; i < cur_row; i++) {
            if (placed_row[cur_row] == placed_row[i] || Math.abs(placed_row[cur_row]-placed_row[i]) == cur_row-i)
                return false;
        } 
        return true;
    }
    
    4. The skills in recording the state of current placement.
    One errors thinking pattern: since we need to pass the same updated state into different banches, we should copy the state at each recursion step in oder to not mess the state in other branches. 
    The pattern is abolutely wrong. The reason is that we continue the recursive process row by row, and we record the current row's index. At one recursion, the different branches would begin with the same state. (no matter whether other branches finish first or not, since other branches would only affect the rows after the current row(including current row)). The changed current row state could be easily recovered by:
    for (int i = 0; i < n; i++) {
        placed_row[cur_row] = i; //for current branch i, we see the same state(previous rows' state)
        if (checkNotCollision(placed_row, cur_row)) {
            helper(n, cur_row+1, placed_row, ret);
        }
    }
    
    for (int i = 0; i < cur_row; i++) {
        if (placed_row[cur_row] == placed_row[i] || Math.abs(placed_row[cur_row]-placed_row[i]) == cur_row-i)
        return false;
    }
    
    Thus for each recursion level, we could only use one state array, because :
    for (int i = 0; i < n; i++) {
        placed_row[cur_row] = i;
        ...
    }
    for cross recursion level, we could also only use one state array, because:
    for (int i = 0; i < cur_row; i++) {
        ...
    }
    
    Amazing: only one state array is enough!!!

    My solution:

    public class Solution {
        public List<String[]> solveNQueens(int n) {
            ArrayList<String[]> ret = new ArrayList<String[]> ();
            if (n <= 0)
                return ret;
            int[] placed_row = new int[n]; 
            helper(n, 0, placed_row, ret);
            return ret;
        }
        private void helper(int n, int cur_row, int[] placed_row, ArrayList<String[]> ret) {
            if (cur_row == n) {
                String[] item = new String[n];
                for (int i = 0; i < n; i++) {
                    StringBuffer sub_item = new StringBuffer();
                    for (int j = 0; j < n; j++) {
                        if (placed_row[i] == j)
                            sub_item.append('Q');
                        else
                            sub_item.append('.');
                    }
                    item[i] = sub_item.toString();
                }
                ret.add(item);
                return;
            }
            for (int i = 0; i < n; i++) {
                placed_row[cur_row] = i;
                if (checkNotCollision(placed_row, cur_row)) {
                    helper(n, cur_row+1, placed_row, ret);
                }
            }
        }
        
        private boolean checkNotCollision(int[] placed_row, int cur_row) {
            for (int i = 0; i < cur_row; i++) {
                if (placed_row[cur_row] == placed_row[i] || Math.abs(placed_row[cur_row]-placed_row[i]) == cur_row-i)
                    return false;
            } 
            return true;
        }
    }
  • 相关阅读:
    爬取校园新闻首页的新闻的详情,使用正则表达式,函数抽离
    爬取校园新闻首页的新闻
    中文词频统计
    综合练习:英文词频统计
    字符串练习
    1.用Hive对爬虫大作业产生的文本文件2.用Hive对爬虫大作业产生的csv文件进行数据分析,写一篇博客描述你的分析过程和分析结果。
    Hadoop综合大作业加上以前漏掉的作业
    爬虫大作业
    获取全部校园新闻
    爬取校园新闻首页的新闻
  • 原文地址:https://www.cnblogs.com/airwindow/p/4261375.html
Copyright © 2011-2022 走看看