剑指 offer 面试题39 数组中出现次数超过一半的数字

数组中出现次数超过一半的数字

个人博客


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

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
题解
  • 摩尔投票法(不修改原数组)

    • 算法思想
      • 由于数组中众数超过数组的一半,让所有的数字投票,如果众数持有票面额为+1,非众数的持有的票面额为-1,则所有的数字的票的面额一定大于 0
    • 复杂度分析
      • 时间复杂度 O(n)
      • 空间复杂度O(1)
    class Solution {
        public int majorityElement(int[] nums) {
            int number = 0;
            int time = 0;
            for(int i = 0; i < nums.length; i++){
                if(time == 0){
                    number = nums[i];
                    time++;
                }else if(nums[i] == number){
                    time++;
                }else{
                    time--;
                }
            }
            return number;
        }
    }
    

    大佬写法

    class Solution {
        public int majorityElement(int[] nums) {
            int x = 0, votes = 0;
            for(int num : nums){
                if(votes == 0) x = num;
                votes += num == x ? 1 : -1;
            }
            return x;
        }
    }
    
  • Partition法(会修改原数组)

    • 算法思想

      • 借鉴快速排序,当快速排序后pivot 的位置就是第 k 大元素的位置
      • 当 k<n/2,那么中位数大于 k
      • 否则相反
    • 复杂度分析

      • 时间复杂度 O(n):

        • 第一次分区查找,我们需要对大小为 n 的数组执行分区操作,需要遍历 n 个元素。第二次分区查找,我们只需要对大小为 n/2 的数组执行分区操作,需要遍历 n/2 个元素。依次类推,分区遍历元素的个数分别为、n/2、n/4、n/8、n/16.……直到区间缩小为 1。如果我们把每次分区遍历的元素个数加起来,就是:n+n/2+n/4+n/8+…+1。这是一个等比数列求和,最后的和等于 2n-1。所以,上述解决思路的时间复杂度就为 O(n)。

      • 空间复杂度:O(1)

    class Solution {
        public int majorityElement(int[] nums) {
            return quickSearch(nums,0,nums.length-1,nums.length/2);
        }
        int quickSearch(int[] nums,int low,int high,int target){
            if(low > high)return 0;
            int k = partition(nums,low,high);
            if(k == target){
                return nums[k];
            }else if(k < target){
                return quickSearch(nums,k+1,high,target);
            }else{
                return quickSearch(nums,low,k-1,target);
            }
        }
        int partition(int[] nums,int start,int end){
    
            int index = end;
            int small = start,pivot = nums[index];
            for(int i = start; i < index;i++){
                if(nums[i] < pivot){
                    if(small == i){
                        small++;
                    }else{
                        int temp = nums[i];
                        nums[i] = nums[small];
                        nums[small] = temp;
                        small++;
                    }
                }
            }
            if(small < index ){
                int temp = nums[small];
                nums[small] = nums[index];
                nums[index] = temp;
            }
            return small;
        }
        
    }
    

    bjKDce

总结
  • 快速排序应该多默写几次呀
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值