聲明:
首先聲明,我沒有參加此次考試(吾老矣),我只是道聽途說,是否真的存在這道試題呢。誰知道呢。在此僅僅是想向大家分享一些知識。 原題大概描述:
給定一個二維數組,裡面隨機的填寫0和1,求取把上下左右連續(斜線不算相連)的1周邊0的個數。在這裡可以把由1構成資料看成一個島嶼,求島嶼海岸線的長度,即周邊0的個數。 引子:
看過人機博弈-吃子棋遊戲(二)算氣的博友,應該瞬間就有思路了吧。其實圍棋的算氣,在沒有眼位的情況下,就是計算算實心島嶼的海岸線。在有眼位的情況下,圍棋算氣也是計算空心島嶼內部的海岸線長度和外部海岸線長度。什麼是圍棋的眼位,請百度之,我們不繼續討論圍棋的眼位了。
解決思路:
我並不知道詳細的題目,所以對於此題空心島嶼的內部海岸線長度是否需要特殊處理無從知曉。不過,在算氣的時候檢測是否存在眼位並不難,加標示即可。如果確實是包含空心的島嶼,即形成眼位的圍棋,我們可以進行特殊處理。我們只要將總氣數扣除內部眼位的氣數就ok了,怎麼扣除是個問題。
在這裡,我說個思路,不一定夠好,但可以解決問題。
1.確定內部海岸線的最小包圍盒(這裡有可能存有外部海岸線,但可以排除大部分外部海岸線),可以節省很多運算。
2.檢測包圍盒內海岸線點是否可以抵達包圍盒的曼哈頓距離最短的邊界,如果可以抵達,且與之相串連的海岸線上的點均可抵達,它們都是外部海岸線。
3.否則,如果無法走至包圍盒的此邊界,則證明其被包圍,屬於內部海岸線,且與之相連的點均屬於內部海岸線。
4.依據上述方法檢測包圍盒內部的不重複的所有點,即可得出哪些是內部海岸線。
我們知道這個演算法效率不高(配合最小包圍盒,以及連通點性質相同,實際上尋路的次數應該很少),但它是正確的,被包圍的海岸線內部的點,就像困在島嶼裡的小怪物,永遠無法逃出來。而外部海岸線上的點僅僅會認為島嶼是個障礙物而已。
這個演算法可以處理任意複雜的圖形,就算山路18彎,外部點也會曆經周折到達海岸線,空心島有好多空心,也不會搞錯內部點or外部點。
針對第二點用深度優先搜尋或是Astar演算法均可以,我們目的是找到路就行,而不是找到最短的路。
總結:
我發博文的時候,並沒有把圍棋中算氣演算法抽象成為一個 1,0筆試題。大膽猜測一下,也許出題人正是看到相關博文,才萌生了出此題的想法。我想在CSDN上應該有一部分人更關注筆試題面試題相關的內容,而忽略了本有實質性內容而不是針對筆試題的文章,希望大家能夠從各種部落格中提取出抽象的知識,以不變應萬變。
如果你有更好的思路,可以留言討論下。
再補充一個例子,很久以前我參加某公司筆試,遇到一題如下,給定一個數組,數組中的數值是隨機的且亂序的,要求把偶數排在數組的前面,奇數排在數組的後面,還希望你的演算法時間複雜度盡量低。可以使用C/C++語言作答。
你怎麼看這到題,如果你瞬間就有極好的方法,我得恭喜您,因為幾年前的我確實想了很長時間才寫出了正確但時間複雜度比標準答案略高的代碼,後來閱讀一些資料,說標準答案使用首尾兩個指標解決這個問題。恩,今天我要說的是,標準答案該更新了,或是題目該加以更多限制了。看了代碼你就明白了。
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 int main() 5 { 6 vector<int> nums{1,2,3,4,5,6,7,8,9,10}; 7 random_shuffle(nums.begin(),nums.end()); 8 partition(nums.begin(),nums.end(),[](int ele)->bool{return ele%2==0;}); 9 for(auto& ele:nums){cout<<ele<<" ";};10 cout<<endl;11 }
僅僅10行代碼,包括一切。僅僅第8行代碼,就完成這道題。哈哈,我不希望出題人看見這篇部落格。因為也許他會無德的在題目後面加上一句話禁止使用STL。
而如果你是即將參加筆試的小同志,記得帶上STL攻城利器, 讓守城的人亮瞎雙眼。
有一點請放心,出題人在怎麼最佳化的代碼,也很難(但還是有可能,某些很專業化的問題,但是這種問題一般不會是面試題吧)在效能上超過STL。一是出題人的水平怎能和STL編寫者比。二是,C++編譯器更懂得最佳化STL,而不是你的代碼。