Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋
times.
You may assume that the array is non-empty and the majority element always exist in the array.
这是一道编程之美和剑指offer上都有的题目。
直观的思路先对数组进行排序,则中间index上存储的数一定是该出现次数超过一半的数字。但是这种操作的时间复杂度为为排序的时间复杂度O(nlogn),不是很理想。
另外一种思路是思路是对快排的改进,即我们不需要对数组进行彻底排序,只需要找到那个在最终排序完的数组中的中间index的那个元素。使用QuickSort的partition来完成这种任务很合适。每次partition会找到 pivot所在的index,可以通过不断二分选择,使最终的pivot的index为(left+right)/2达到目的。
算法时间复杂度平均情况下为O(n)。也是devide and conquer分治的思想。
另外一种思路是既然该数字在数组中出现次数超过一半,则该数字的出现次数比其他所有数字的次数都多。则每次删除数组中两个不同的数,留下的数组中该数字的出现次数依然超过一半。
具体实现时并不是真正去两两删除,而是用一个times和一个result来模拟。result保存数组中的数字,times保存出现的次数。如果下一个数字和我们保存的result中的值不一样,则times的值减1,否则times加1,如果当前times为0,则将result的值赋为当前值,最终result的值为那个出现出现次数超过一半的数的值。代码如下:
class Solution(object): def majorityElement(self, nums): """ :type nums: List[int] :rtype: int """ times = 1 #开始times初始化 result = nums[0] # for i in nums[1:]: if times == 0: result = i #重新开始 times = 1 #重新开始计数 else: if result == i: times += 1 else: times -= 1 return result
注意如何把这段代码和两两删除不同的元素对应上。实际上从result赋值,times为1,到times降为0这个过程,实现的就是删除元素的过程。比如1234,1到2时,times为0,3时times重新等于1,record为3,4时times又降为0,其实就是两两删除的过程。如果有连续值,555534216,则到1时,times也降为0,相当于(5,3),(5,4),(5,2),(5,1)两两删除了。所以在最后一个 times为1,record换值时,record就是那个出现超过一半的数字,一直到数组尾部,也没有那么多和record不同的元素来和它抵消。算法成立。