多数元素(找出一个数组中的众数)

给定一个大小为 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;
        }
    };
    
posted @ 2021-11-26 16:48  博客是个啥?  阅读(154)  评论(0编辑  收藏  举报