首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

笔考试题(1)

2012-11-19 
笔试题(1)题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。?思路:??? 这是一道广为流

笔试题(1)

题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。

?

思路:

??? 这是一道广为流传的面试题,包括百度、微软和Google在内的多家公司都曾经采用过这个题目。要较短的时间里很好地解答这道题,除了较好的编程能力之外,还需要较快的反应和较强的逻辑思维能力。

??? 看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)。

??? 接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。有了这个辅助的哈希表之后,我们只需要遍历数组中的每个数字,找到它在哈希表中对应的位置并增加它出现的次数。这种哈希表的方法在数组的所有数字都在一个比较窄的范围内的时候很有效。本博客系列的第13题就是一个应用哈希表的例子。不过本题并没有限制数组里数字的范围,我们要么需要创建一个很大的哈希表,要么需要设计一个很复杂的方法来计算哈希值。因此总体说来这个方法还不是很好。

??? 前面两种思路都没有考虑到题目中数组的特性:数组中有个数字出现的次数超过了数组长度的一半。也就是说,有个数字出现的次数比其他所有数字出现次数的和还要多。因此我们可以考虑在遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数。当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1。如果下一个数字和我们之前保存的数字不同,则次数减1。如果次数为零,我们需要保存下一个数字,并把次数设为1。由于我们要找的数字出现的次数比其他所有数字出现的次数之和还要多,那么要找的数字肯定是至少最后一次把次数设为1时对应的数字。

?

基于这个思路,我们不难写出如下代码:

/** * @author jefferent@tom.com * * Time: 2011-7-20 下午04:13:38 */public int findNumber(List<Integer> list){int count = 0; //记录当前数字出现次数int currentNum = list.get(0); //当前数值for(Integer item : list){if(currentNum != item){if(count == 0){currentNum = item;}count--;}else{count++;}}return currentNum;}

?

热点排行