https://leetcode.com/problems/majority-element/description/
给定一个n维的数组,寻找出现次数最多的那个元素。那个出现最多的元素至少会在数组中出现一半,要我们求出这个元素。
下面有好几种方法:
1.暴力搜索的方法
对数组中的元素进行遍历,然后分别求出每个元素出现的次数,如果该次数大于列表的一半,则输出这个数字。其具体代码如下:
class Solution:
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
major_num=len(nums)//2 %python3里的“/ "表示 浮点数除法,返回浮点结果;" // "表示整数除法
for num in nums:
s=sum(1 for elem in nums if elem==num ) %这里表示的是每次if判断正确就sum+1
if (s>major_num):
return num
结果是时间复杂度超过了。
2.HashMap方法
Hash算法实际上就是利用Key计算位置的算法,它利用了字典键-值对的特性。在这里我们采用了python内置模块collections中的Counter类方法。Collections包含了除了dict,set,list,tuple以外的一些特殊的容器类型。具体可参见文档:http://docs.python.org/2/library/collections.html。下面主要介绍一下我们使用的Counters类。
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。因此本题的代码可以写成:
class Solution:
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
counts=collections.Counter(nums)
return max(counts.keys(),key=counts.get)
为了更好的理解代码,我们可以把上述程序改写为:
import collections
class Solution:
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
counts=collections.Counter(nums) %从一个可迭代对象(list,tuple,dict,字符串)创建Counter类
return max(counts.keys(),key=lambda x:counts.get(x))
Counter类的存储是一个字典,而get方法是字典中用来得到值的。lambda方法定义了一个匿名类,counts.get(x)得到了counts中所有的值,keys代表了counts中所有的键,max函数如果有关键字key,用法就是按照key来选最大值,而key是get函数,得到的是值,因此最后一句话就返回了值最大的key,也就是出现次数最多的数。
3.排序法
因为出现次数最多的数字占据了整个数组的一半之多,那么将数组进行排序后,其中间的那个数一定就是我们要找的数字。其代码为:
class Solution:
def majorityElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums.sort()
return (nums[len(nums)//2])
4.最大投票算法(需要学习的算法)Moore's voting algorithm
该算法主要用来解决在元素列表中找到出现元素次数最多的元素。具体可以看http://www.cs.utexas.edu/~moore/best-ideas/mjrty/index.html。算法的思想是:每次都找出一对不同的元素,从数组中删掉,直到数组为空或只有一种元素。
不难证明,如果存在元素e出现频率超过半数,那么数组中最后剩下的就只有e。当然,最后剩下的元素也可能并没有出现半数以上。比如说数组是[1, 2, 3],最后剩下的3显然只出现了1次,并不到半数。排除这种false positive情况的方法也很简单,只要保存下原始数组,最后扫描一遍验证一下就可以了。
因此该程序为:
class Solution {
public int majorityElement(int[] nums) {
int len = nums.length, candidate=nums[0], count=1;
for(int i=1; i
如果要采用这个算法,题目中出现次数大于列表的一半是必要条件,因为我们每次在移除时,最坏的情况是每次移除一个出现次数最多的数和一个非目标数,要确保剩下的数为出现次数最多的数,则需要它大于列表的一半。
关于这个算法的改进与变形,可以参看:https://blog.csdn.net/huanghanqian/article/details/74188349