一道某高大上互联网公司的笔试题分享
声明:
首先声明,我没有参加此次考试(吾老矣),我只是道听途说,是否真的存在这道试题呢?谁知道呢!在此仅仅是想向大家分享一些知识。
原题大概描述:
给定一个二维数组,里面随机的填写0和1,求取把上下左右连续(斜线不算相连)的1周边0的个数。在这里可以把由1构成数据看成一个岛屿,求岛屿海岸线的长度,即周边0的个数。
举个简单例子:(还有更为复杂的图像)
比如
0 0 0
0 1 1 0
0 1 0 0 0
0 1 1 1 1 0
0 0 0 0 0
连续向连的1,周边有多少个0?(加粗的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,而不是你的代码。