LeetCode 笔记系列 14 N-Queen II [思考的深度问题]
题目: Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.

就是让你输出N皇后问题的解法数目。
直接求解,每次还记录整个棋盘位置那种方法就不说了,必须超时。
有一个牛逼大了的超级无敌帅的位移动解法。我们暂且不表。看看我当时想的一个解法。
首先,对于皇后的那个递归方法,我有三个变量分别表示1.一个int值,表示递归到当前的level,当前的哪几个col被占领了,例如11011就表示我们下一个Q只能放在第三个(从第一个位置开始数)位置上了;2.一个hash table, 表示左对角线到目前为止,是否有Queen占领过了;2.一个hash table,表示右对角线是否有Queen占领过了。然后每次都去查询row上的可用格子,再去看看两个hash table上的可用格子,一起决定这一层我们选取那一(几)个作为备选项。
说说那个表示对角线的hash table,是一个Integer到boolean的映射。因为,所有某条固定左对角线上的点(row, col),row - col都是定值,那么可以用row - col表示一条左对角线嘛!同理可以用row + col表示右对角线嘛。

然后任意一个点,我们就知道它左右对角线的key了,就可以去那个hash 表里面查看是不是有Queen占领过啦。
所以,给出一个当前被占领的状态,一个左对角线被占领的状态,一个右对角线被占领的状态,我们就可以计算出下一步在哪里放Queen啦。方法如下:
private static int available(int cur_row_status,
HashMap<Integer, Boolean> left_digra_status, HashMap<Integer, Boolean> right_digra_status, int row, int n){
int avail = cur_row_status;
for(int j = 0; j < n; j++){
if((left_digra_status.containsKey(row + j) && left_digra_status.get(row + j))
|| (right_digra_status.containsKey(row - j) && right_digra_status.get(row - j))) avail = set(avail, j);
}
return avail;
}
available方法
例如,返回如果是而110011(二进制),那么中间两位是可以放Q的。
那,我们就可以定义递归函数咯哦。
private static void collectSolutions(int cur_row_status,
HashMap<Integer, Boolean> left_digra_status, HashMap<Integer, Boolean> right_digra_status,
int row, int n, int[] count){
if(row == n) {
count[0]++;
return;
}
int avail = available(cur_row_status, left_digra_status,right_digra_status, row, n);
for(int i = 0; i < n; i++){
if(!isSet(avail, i)){
left_digra_status.put(row + i, true);
right_digra_status.put(row - i, true);
collectSolutions(set(cur_row_status, i), left_digra_status, right_digra_status, row + 1,
n, count);
left_digra_status.put(row + i, false);
right_digra_status.put(row - i, false);
}
}
}
collectSolutions
count里面就放我们的计数。注意每次递归子函数返回后,要重新设置对角线。col的那个状态不用重置了,因为java函数不会改变int值的。
主函数这样写:
public static int totalNQueens(int n) {
// Start typing your Java solution below
// DO NOT write main() function
int cur_row_status = 0;
int[] count = new int[1];
HashMap<Integer, Boolean> left_digra_status = new HashMap<Integer, Boolean>();
HashMap<Integer, Boolean> right_digra_status = new HashMap<Integer, Boolean>();
collectSolutions(cur_row_status, left_digra_status, right_digra_status, 0, n, count);
return count[0];
}
然后我觉得我这方法已经不错了吧,结果还是让大集合潮湿了。
牛逼闪闪,刺瞎我的24k钛合金狗眼的位移算法来鸟。
public int totalNQueens(int n){
cnt = 0;
upper = (1<<n)-1 ;
Queen(0,0,0);
return cnt;
}
//为啥说大牛niub呢,看看我下面那个,再对比ld和rd,人大牛一眼就看出来了,没必要保存
//所有对角线信息啊。下一个状态,完全由当前状态决定!!
private void Queen(int row, int ld, int rd){//ld, left 对角线; rd, right 对角线
int pos, p;
if(row!=upper)
{
//so pos in binary is like, under current row/ld/rd restriction, what is available slot to put Q
pos = upper & (~(row | ld |rd));
while(pos!=0)//available is 1
{
p = pos & (-pos);//from right to left, the first "1" in pos
//now, we occupy the most right available position
pos = pos - p;//now take this available as ”Q“,pos kind of like a available slot marker
Queen(row+p,(ld+p)<<1,(rd+p)>>1);
}
}
else ++cnt;
}
Niubility N Queen
好一个不明觉厉,男默女泪的算法!
。。。。。
首先,再次承认和牛人的差距。
其次,反思,反思,深刻地反思。为毛牛人就知道这一点呢?其实所有中间信息都可以用一个整数来表示啊。
特别是那个左右对角线的事情,弄的本娃很郁闷。仔细想想,可不是嘛,当设置了一个Q以后,就是设置其左下方和右下方不能访问嘛。随着层次的深入(向最后一行靠近),对角线的状态可不就是左对角线左移,右对角线右移嘛。天,好有画面感的事情。
这里还有个小技巧。11100这个二进制数,怎么知道从右向左边第一个1的位置啊?
p = (pos) & (-pos)
我真是不知道这个,如果你也不知道负数在计算机中的表示方法的话,建议google之。
哦,这里有个关于这个算法的图图,看看有帮助。http://www.matrix67.com/blog/archives/266
我想去买这位blogger的书了。
总结:
1. 思考要有深度。就是说,理解一下,当前的信息到底是怎么样得出来的,而不是看表象。
2. 要有画面感。
LeetCode 笔记系列 14 N-Queen II [思考的深度问题]的更多相关文章
- LeetCode 笔记系列13 Jump Game II [去掉不必要的计算]
题目: Given an array of non-negative integers, you are initially positioned at the first index of the ...
- LeetCode 笔记系列 18 Maximal Rectangle [学以致用]
题目: Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones ...
- LeetCode 笔记系列16.3 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]
题目:Given a string S and a string T, find the minimum window in S which will contain all the characte ...
- LeetCode 笔记系列六 Reverse Nodes in k-Group [学习如何逆转一个单链表]
题目:Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. ...
- LeetCode 笔记系列16.2 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]
题目:Given a string S and a string T, find the minimum window in S which will contain all the characte ...
- LeetCode 笔记系列16.1 Minimum Window Substring [从O(N*M), O(NlogM)到O(N),人生就是一场不停的战斗]
题目: Given a string S and a string T, find the minimum window in S which will contain all the charact ...
- LeetCode 笔记系列15 Set Matrix Zeroes [稍微有一点hack]
题目:Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. Fol ...
- LeetCode 笔记系列12 Trapping Rain Water [复杂的代码是错误的代码]
题目:Given n non-negative integers representing an elevation map where the width of each bar is 1, com ...
- LeetCode 笔记系列八 Longest Valid Parentheses [lich你又想多了]
题目:Given a string containing just the characters '(' and ')', find the length of the longest valid ( ...
随机推荐
- redis 做为缓存服务器 注项!
作为缓存服务器,如果不加以限制内存的话,就很有可能出现将整台服务器内存都耗光的情况,可以在redis的配置文件里面设置: # maxmemory <bytes> #限定最多使用1.5GB内 ...
- js基本知识2
一.提示框 1. 弹出警示框 alert(); window.alert(); window 窗口 2. 控制台输出 console.log() 3. 文档打印 document 文档 documen ...
- 从零开始,跟我一起做jblog项目(一)引言
从零开始,跟我一起做jblog项目(一)引言 想做一个java版的blog,源自一个很久之前的想法 当时刚学习JAVA的web编程 想买自己的域名,自己的VPS,安装自己的WEB服务 用google ...
- Oracle 11g安装图文攻略
一.Oracle 下载 注意Oracle分成两个文件,下载完后,将两个文件解压到同一目录下即可. 路径名称中,最好不要出现中文,也不要出现空格等不规则字符. 官方下地址: http://www.ora ...
- linux进程同步机制_转
转自:Linux进程同步机制 具体应用可参考:线程同步 IPC之信号量 为了能够有效的控制多个进程之间的沟通过程,保证沟通过程的有序和和谐,OS必须提供一 定的同步机制保证进程之间不会自说 ...
- [算法]滴滴笔试题——求最大子串和(O(n)复杂度)
扫描法.一次扫描数组即可得出答案,复杂度O(n).这种方法用文字描述不容易说清楚,下面用每一步运算的图示来表达.伪代码如下: maxsofar=end=; ,n) end=max(end+x[i],) ...
- Redis学习笔记——简介及配置
1.Redis简介 Redis概述 Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的应用程序的完美解决方案.Redis从它的许多竞争继承来的三个主要特点:Redis数据库 ...
- C++ 运算符重载三(链式编程)
//运算符重载之链式编程 #include<iostream> using namespace std; //对于友元函数重载运算符只适用于左操作数是系统变量的场景 //因为成员无法在系统 ...
- Unity UGUI 实现简单拖拽功能
说到拖拽,那必然离不开坐标,UGUI 的坐标有点不一样,它有两种坐标,一种是屏幕坐标,还有一种就是 UI 在Canvas内的坐标(暂时叫做ugui坐标),这两个坐标是不一样的,所以拖拽就需要转换. 因 ...
- 学习:在Eclipse中用TODO标签管理任务(Task)。
1.Windows->Perferences->Java->Compile->Task Tags,我们就可以自定义任务标签,Eclipse中可以支持HIgh,Normal,Lo ...