日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

利用位运算解决 N 皇后问题

發(fā)布時(shí)間:2023/12/31 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用位运算解决 N 皇后问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目

LeetCode 51. N-Queens

分析

N 皇后問(wèn)題是考查遞歸回溯的經(jīng)典問(wèn)題,深度優(yōu)先搜索的難點(diǎn)在于如何剪枝,在這個(gè)問(wèn)題里面的剪枝,我們需要利用額外的空間去記錄當(dāng)前行的有效空位,只要一行當(dāng)中找不到有效空位,遞歸將不會(huì)繼續(xù)下去。一般的解法是開(kāi)一個(gè) n*n 的數(shù)組,優(yōu)化一點(diǎn)解法是利用三個(gè)數(shù)組,分別表示左上,上,右上對(duì)當(dāng)前位置的影響情況,這里有一個(gè)點(diǎn)就是一個(gè)位置會(huì)對(duì)其左下,下,右下產(chǎn)生影響,其中,下最好記錄,即當(dāng)前空位的列,左下有一個(gè)規(guī)律是,row + col 的和是固定的,例如,(0,3),(1,2),(2,1), 它們的行號(hào)和列號(hào)加起來(lái)都是一個(gè)相同的值,右下的規(guī)律是row - col,或者 col - row 是固定的,看圖也很好理解,往右下的話,行列都會(huì)遞增,而且每次遞增幅度都是 1,Java 代碼如下:

public List<List<String>> solveNQueens(int n) {if (n <= 0) {return new ArrayList<>();}boolean[] col = new boolean[n]; // 上boolean[] pie = new boolean[2 * n]; // 左上boolean[] na = new boolean[2 * n]; // 右上List<String> result = new ArrayList<>();List<List<String>> results = new ArrayList<>();helper(results, result, col, pie, na);return results; }private void helper(List<List<String>> results,List<String> result,boolean[] col,boolean[] pie,boolean[] na) {if (col.length == result.size()) {results.add(new ArrayList<String>(result));return;}int currentRow = result.size();for (int i = 0; i < col.length; ++i) {int pieId = currentRow + i, naId = currentRow - i + col.length;if (!col[i] && !pie[pieId] && !na[naId]) {char[] row = new char[col.length];Arrays.fill(row, '.');row[i] = 'Q';result.add(new String(row));col[i] = true; pie[pieId] = true; na[naId] = true;helper(results, result, col, pie, na);col[i] = false; pie[pieId] = false; na[naId] = false;result.remove(result.size() - 1);}} } 復(fù)制代碼

優(yōu)化

這里開(kāi)始引入我們今天的重點(diǎn),那就是能不能不用額外的空間進(jìn)行記錄;可以假想 N 其實(shí)沒(méi)多大(LeetCode 的 testcases 也只有 9 個(gè)),這道題的深度優(yōu)先搜索的時(shí)間復(fù)雜度其實(shí)可以看成指數(shù)冪,因此 N 不會(huì)特別大;這里有個(gè)非常巧妙的點(diǎn)就是利用位運(yùn)算,是怎么想到的呢?首先要明確一點(diǎn)就是,一個(gè)空位只有兩種狀態(tài),即有皇后和無(wú)皇后,我們之前是利用 boolean 數(shù)組,這個(gè)很直觀很容易想到,但是用三個(gè)整數(shù)來(lái)代替上面的三個(gè) boolean 數(shù)組是否可行?在 N 不是特別大的情況是完全可行的,以 Java 為例,我們可以用 int 中的 32 個(gè) bits 來(lái)分別表示上面代碼中的 boolean 的每個(gè)空位,代碼如下,這里 0 表示有效,1 表示無(wú)效:

private List<String> result = new ArrayList<>(); private List<List<String>> results = new ArrayList<>();public List<List<String>> solveNQueens(int n) {if (n <= 0) {return new ArrayList<>();}dfs(n, 0, 0, 0);return results; }private void dfs(int n, int col, int pie, int na) {if (n == result.size()) {results.add(new ArrayList<String>(result));return;}// 獲得所有的有效空位// (col | pie | na) 可以得到所有被占的空位,取反之后將有效空位置為 1// 與上 (1 << n) - 1,是設(shè)定考慮范圍,比如 8 皇后,那么只用考慮低 8 位即可int bit = ((~(col | pie | na)) & ((1 << n) - 1));// bit > 0 表示有空位while (bit > 0) {// 選擇最低位的一個(gè)空位int tmp = bit & (-bit);// 構(gòu)建當(dāng)前行的答案String str = constructString(tmp, n);result.add(str);// col | tmp 是將 col 中當(dāng)前選擇的這一列置為 1,也就是無(wú)效// (pie | tmp) << 1 是設(shè)置之前行和當(dāng)前行對(duì)左下的影響// (na | tmp) >> 1 是設(shè)置之前行和當(dāng)前行對(duì)右下的影響dfs(n, col | tmp, (pie | tmp) << 1, (na | tmp) >> 1);result.remove(result.size() - 1);// 將當(dāng)前選擇的這個(gè)最低位置為 0bit &= bit - 1;} }private String constructString(int i, int n) {char[] row = new char[n];Arrays.fill(row, '.');int tmp = 1, indx = 0;while (i != 0) {if ((tmp & i) != 0) {row[indx] = 'Q';}i >>= 1;indx++;}return new String(row); } 復(fù)制代碼

這樣不但是節(jié)省了空間,而且從時(shí)間上來(lái)看,它只考慮了有效空位,和之前代碼的 for-loop 遍歷一行當(dāng)中所有位置來(lái)比較的話,也有提升

轉(zhuǎn)載于:https://juejin.im/post/5cbab9a8e51d456e361ed8e5

總結(jié)

以上是生活随笔為你收集整理的利用位运算解决 N 皇后问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。