社群分享 演算法學習心得 N皇后位運算講解

2021-10-12 06:57:57 字數 4576 閱讀 7686

寫注釋並不是每一行都寫上一些注釋,而是在關鍵的地方你要把注釋寫的很明白,讓你以後複習的時候,可以很快的理清思路。下面以兩道題目為例。

for (int i = 0; i < intervals.length; i++) );

} else

}

這道題目我們知道一共就兩種情況,要麼不能合併,要麼可以合併。能合併的情況是前乙個區間的最右邊的值大於當前區間最左邊的值。不能合併的情況就正好相反。

上面這句話是非常抽象的。所以如果我們注釋中能夠舉一些具體的例子來說明,你之後來複習的時候一看例子就會明白自己的思路,這樣會節省很多複習的時間。比如:

(3, 5) (6, 7)這樣的區間就是不能合併,(6, 7)只能重開乙個區間。

(3, 5) (4, 6)這樣的區間就是可以合併的。

以下是最長公共子串行這道題目的相關**:

for (int i = 1; i < length1; i++)  else 

}}

比如上圖中,最後乙個字元相等是什麼情況,不等是什麼情況,相信邏輯上大家都知道。那麼思路是乙個比較抽象的東西,如果能夠舉一些具體的例子放在這裡就更好了。實際的例子就是形象的東西,形象的東西可以幫助我們去理解抽象的東西也有利於我們的複習。

先貼上整體**:

public void dfs(int n, int row, int lie, int pie, int na) 

int bits = (~(lie | pie | na)) & ((1 << n) - 1); // (1)

// 迴圈開始判斷

while (bits != 0)

}

1.**注釋中(1)處**講解:

int bits = (~(lie | pie | na)) & ((1 << n) - 1);              // (1)

n皇后,我們就可以用二進位制的n位來表示。如8皇后,若最終算出來的bits為0 0 0 1 0 0 1 0表示當前層從左往右第4個格仔和第7個格仔是可以放皇后的,其他格仔放進去都會有衝突。

所以,每一層進來,我們都要求出當前層這個int型別的數,通過他的二進位制數來知道當前層是有哪些位子已經被占有了,哪些位子可以放皇后。

**中   lie,  pie, na我們知道分別代表了當前層同一列,右斜上, 左斜上分別有哪些位子是不能放皇后的, 那麼 (lie | pie | na) 就可以得到當前層一共有哪些位子是不能放皇后的。下面舉的例子我們都以8皇后為例。

如: (lie | pie | na) =000000000000000000000000 10101001

前面一大串0是因為int型別是32位的,所以對於8皇后而言,前面的24位都是無用的。上面的情況易知當前層第1個,第3個,第5個,第8個格仔都不可以放皇后。

所以我們對其取反:

則:(~(lie | pie | na)) =111111111111111111111111 01010110, 這樣最低的8位,為1的地方就是當前層可以放皇后的位置。但是這個操作做了之後,前面的24位也變成了1。而這些1是我們不需要的。所以要想辦法將其乾掉。

(1 << n) =000000000000000000000001 00000000(還是以8皇后為例,這裡的n就是8)

那不難得出:

((1 << n) - 1) =000000000000000000000000 11111111

(~(lie | pie | na)) =111111111111111111111111 01010110

(~(lie | pie | na)) & ((1 << n) - 1) =000000000000000000000000 01010110= bits

這個時候算出來的bits, 二進位制位為1的位就真正代表可以放皇后了。

2.**注釋中(2)處**講解:

int p = bits & -bits;                                     // (2)

上面**我們得到了哪些位置可以放皇后。再來回顧下那個二進位制串:

000000000000000000000000 01010110= bits

**(2)這個操作就是位運算操作,可以得到二進位制中最低位的那個1

bits & -bits =000000000000000000000000 00000010= p = 2(十進位制)

3.**注釋中 (3)處**講解:

bits = bits & (bits - 1);                                 // (3)

000000000000000000000000 01010110 = bits

// 既然決定將p這個位置放上皇后,那bits中自然要去掉他,這樣能夠保證回溯回來的時候這個位子也不能再用了

bits = bits & (bits - 1) =000000000000000000000000 01010100

4.**注釋中(4)處**講解:

dfs(n, row + 1, lie | p, (pie | p) << 1, (na | p) >> 1);  // (4)

lie | p就是告訴下一層,有哪些列是被佔著的。

pie | p就是告訴下一層,有些pie的位置是被佔著的。但是我們這個是二進位制位注意,pie的位子下面一層是感知不到的。舉個例子:

假如當前層取到的p的位子是00001000,第五個格仔放了皇后了,那麼對於pie而言,下一層不能訪問的是第4個格仔,也就是00010000這樣的表示:

00001000

00010000

所以 (pie | p) 要左移一位

na正好相反:

00001000

00000100

所以 (na | p) 要右移一位

// 定義結果集

list> res = new arraylist<>();

public list> solvenqueens(int n)

// 申請乙個char棋盤

char chess = new char[n][n];

// 初始化棋盤

for (char everyrow : chess)

// 開始回溯

dfs2(n, 0, 0, 0, 0, chess);

return res;

}public void dfs2(int n, int row, int lie, int pie, int na, char chess)

// 得到當前層的bits

int bits = (~(lie | pie | na)) & ((1 << n) - 1);

int count = 0;

while (bits != 0)

}

1.**注釋中(1)位置的**講解

我們每一層都要在當前行的某一列放乙個皇后,所以我們要根據p這個數字求出他對應的二進位制中1所在的位置,1的位置就是代表當前行皇后的列。舉個例子:

00000010, 這個二進位制數的十進位制代表2。

實際上就是 1 * 2^1 = 2; 也就是1的位置是從右往左第1位(下標從0開始)。

而我們要求的實際上就是根據十進位制的2求這個1 (指數),也就是對應二進位制中1所在位置。這個就是用到了取對數

指數 =log2 (p) = log2 (2) = 1

所以我們根據p就可以求出指數,也就是二進位制中1的位子,也就是可以放皇后的下標(列)

index = math.log(p) / math.log(2) = log2 (p)

log2 (p) = loge (p) / loge (2);

剛剛也說到,對00000010這個數取對數得到的1。這個是從右往左的位置,但我們的列數下標是要從左往右的

col = n - index - 1;

col = 8 - 1 -1 = 6;

這樣符合我們的預期

00000010本就代表第7列,也就是陣列中下標為6的地方可以放皇后

排序演算法學習心得

近期終於弄懂了六種演算法,寫個小部落格記錄下 一 六種演算法解析 1 直接插入排序 2 演算法特點 保證每一次遍歷後,前面的資料都是排序好的 2 public static int insert int arr arr pos arr i arr i temp return arr 3 氣泡排序 1...

回溯演算法學習心得

回溯演算法的原理 回溯演算法是一種選優搜尋法,按照選優條件向前搜尋,以達到目標。但當探索到某一步的時候,發現原先選擇並不優活著達不到目標的時候,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法。廢話不多說,直接上解決回溯演算法的框架。解決乙個回溯問題,實際上就是乙個決策樹的遍歷過程。你只需要思...

演算法學習 N皇后問題

問題 d 八皇后 時間限制 1 sec 記憶體限制 32 mb 題目描述 會下西洋棋的人都很清楚 皇后可以在橫 豎 斜線上不限步數地吃掉其他棋子。如何將8個皇后放在棋盤上 有8 8個方格 使它們誰也不能被吃掉!這就是著名的八皇后問題。對於某個滿足要求的8皇后的擺放方法,定義乙個皇后串a與之對應,即a...