今天作一個LeetCode題發現一個小技巧,特來與大家分享一下。java
作的LeetCode題是關於二維矩陣的圖論建模,像下面這樣的:算法
二維矩陣能夠不產生一個圖結構,直接在二維矩陣上計算。相應地,會設定一個布爾值數組visited[ i ] [ j ],表示某一個位置是否被遍歷,true表示被遍歷,false表示未被遍歷。segmentfault
咱們首先看看圖論建模是如何建模的, 二維數組會有兩個索引下標i和j,分別對陣爲行和列。咱們會設定一個常量C,而這個常量正是列的長度,即nums[i].length。數組
對二維矩陣每個位置均可以用 i * C + j 表示,以下圖:微信
若是圖結構想轉換成二維矩陣也能夠這樣表示,假設圖結構的一個節點的鍵爲g,位於二維矩陣的,第幾行用 g / C 表示,第幾列用 g % C 表示。動畫
i = g / C; // 得到第幾行 j = g % C; // 得到第幾列
三維矩陣也是經過這樣的方式進行圖論建模,會設定兩個常量,一個是 j 的長度,另外一個是 i 和 j 的面積。這裏就不進行多介紹了,由於本篇介紹布爾值數組壓縮狀態的小技巧,再講三維矩陣的圖論建模就偏了,瞭解二維矩陣就行了。spa
在進行二維矩陣的圖論建模中,若是不轉成圖形結構,直接在二維矩陣上計算,咱們會設定一個布爾類型的二維數組visited,數組的值表示圖的某個節點是否遍歷過。code
接着咱們能夠把true看做是1,false看做是0,而後轉成一維數組,以下表示:blog
[ 0 0 0 0 0 0 0 0 0 0 => [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 0 0 0 0 0 ]
而後能夠把這看做是二進制,將一維數組直接轉成一個數字。索引
最重要的是,轉成了一個數字,如何查看某個節點是否被遍歷過,又如何將某個節點設成0和1。
咱們能夠這樣作,假設visited一維數組爲[0 0 0 1 0],表示第3位已經遍歷過,轉成二進制表示爲0b01000,轉成十進制表示爲8。
咱們看第0位是不是0,將visited與0b00001進行與運算,返回結果,若是結果爲0說明沒有遍歷過;若是結果不爲0遍歷過。
0b01000 & 0b00001 ---------- => 8 & (2^0) = 0 0b00000
咱們看第3位是不是0,將visited與0b01000進行與運算,返回結果。
0b01000 & 0b01000 ---------- => 8 & (2^3) = 8 0b01000
能夠總結爲:
visited & (2^i) == 0 ? 未遍歷過 : 遍歷過; // visited表示一個數字,i 表示第幾位 2^i 也能夠用 1<<i 表示 即: visited & (1<<i) == 0 ? 未遍歷過 : 遍歷過;
那如何將某個節點設成1或0呢?
咱們將第1位設爲1,表示第1位剛遍歷過,
0b01000 + 0b00010 ---------- => 8 + (2^1) = 10 0b01010 注意:要提早判斷第1位是否爲1,若是不是能夠設爲1,若是是則忽略。
將第2位設爲1,表示第2位剛遍歷過,
0b01010 + 0b00100 ---------- => 10 + (2^2) = 14 0b01110
能夠總結爲:
// 若是第i位爲0,設爲1: if(visited & (2^i) == 0) // visited表示一個數字,i 表示第幾位 visited += 2^i; // 2^i 也能夠用 1<<i 表示 if(visited & (1<<i) == 0) visited += 1<<i;
同理,將第i爲設爲0,能夠總結爲:
// 若是第i位爲1,設爲0: if(visited & (2^i) != 0) // visited表示一個數字,i 表示第幾位 visited -= 2^i; // 2^i 也能夠用 1<<i 表示 if(visited & (1<<i) != 0) visited -= 1<<i;
觸類旁通,學會了二進制數組壓縮成一個數字的狀態,多進制數組也一樣能夠壓縮狀態,只須要找到最大的那個數就能夠了。
若是找到最大的數爲5,那就成六進制;若是找到最大的數爲25,那就成二十六進制。若是數字確實比較大,也能夠考慮最小的數,進行一一映射。
經過這樣的狀態壓縮,不少指數級別的空間複雜度直接降爲O(1),省空間了。
關注「算法無遺策」,一塊兒領悟算法的魅力,你們加油 (●'◡'●)
喜歡本文的朋友,微信搜索「算法無遺策」公衆號,收看更多精彩的算法動畫文章