多数元素(找出一个数组中的众数)
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/majority-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
暴力哈希
-
思路:遍历数组,将每个元素出现的次数存入哈希表,之后遍历哈希表,找出出现次数大于n/2的元素
-
代码:
func majorityElement(nums []int) int { mymap:=make(map[int]int) for i:=0;i<len(nums);i++{ mymap[nums[i]]++ } for k,value:=range mymap{ if value>len(nums)/2{ return k } } return -1 }
空间复杂度为O(n),空间复杂度也为O(n)
排序
-
思路:先将数组排序,然后遍历排序后的数组,记录构成长度大于n/2的子序列的值。
-
代码:
func majorityElement(nums []int) int { sort.Ints(nums) len:= len(nums) num:=1 ret:=nums[0] for i:=1;i<len;i++{ if nums[i]!=nums[i-1]{ num=1 }else{ num++ if num>len/2{ ret=nums[i] } } } return ret }
适用Go语言自带排序,时间复杂度为O(nlogn),空间复杂度也是O(nlogn).
随机化
-
思路:我们随机从数组中取数,判断这个数是不是众数,众数出现的概率大于1/2
-
代码:
//判断是不是众数 func isMajorityElement(nums []int, num int) bool{ len:= len(nums) count:=0 for i:=0;i<len;i++{ if nums[i]==num{ count++ if count>len/2{ return true } } } return false } func majorityElement(nums []int) int { len := len(nums) for{ //生成随机数 r:=rand.Int31()%int32(len) //如果是随机数,就返回 if isMajorityElement(nums, nums[int(r)]) { return nums[r] } } }
这个方法中,如果我们运气很差,那就一直随机不到众数,如果运气好,那就很快随机到众数,找到众数的随机次数为Σi*1/2i 就是2,所以随机次数的期望是一个常数,每一次随机后,需要O(n)的时间判断。
时间复杂度为O(n),空间复杂度为O(1)
分治法
-
思路:把一个数组分成两部分,如果a是数组的众数,那a至少是其中一部分的众数,如果a不是左边的也不是右边的,那a在整个数组中也不能是众数。
适用经典的分支算法递归求解,知道所有子问题的长度为1,数组长度为1,那众数就是那个唯一元素。从左右两部分得到众数,在判断这个众数是不是整个数组的众数。
-
代码:
class Solution { private: //获取在l到r之间出现的次数 int contNums(vector<int>&nums,int target,int l,int r){ int ret=0; for(int i=l;i<=r;i++){ if(target==nums[i]){ ret++; } } return ret; } //获取数组中的众数 int findMajority(vector<int>& nums,int l,int r){ //只有一个元素,返回这个元素 if(l==r){ return nums[l]; } int mid=(l+r)/2; //得到左右两部分的众数 int lf= findMajority(nums,l,mid); int lr= findMajority(nums,mid+1,r); //如果左边得到得众数,是真个数组的众数,就返回 if(contNums(nums,lf,l,r)>(r-l+1)/2){ return lf; }else if(contNums(nums,lr,l,r)>(r-l+1)/2){ return lr; } return -1; } public: int majorityElement(vector<int>& nums) { return findMajority(nums,0,nums.size()-1); } };
时间复杂度为O(n*logn),空间复杂度为O(longn) ps:我自己不知道怎么分析,直接抄来的结果
Boyer-Moore 投票算法
-
思路:维护一个conut和candidate,candidate可以先随便赋一个值,遍历数组,count为0时,先将当前元素赋给candidate。之后判断当前元素是否等于candidate,若相等,count++,否则count--。遍历结束,candidate就是我们要的众数。详细证明请百度。
-
代码:
class Solution { int majorityElement(vector<int> &nums) { int count=0; int candidate=nums[0]; for(int i=0;i<nums.size();i++){ if(count==0){ candidate=nums[i]; } if(candidate==nums[i]){ count++; }else{ count--; } } return candidate; } };