LeetCode - 169. Majority Element (计数 + 位运算 + Partition + 分治)

LeetCode - 169. Majority Element (计数 + 位运算 + Partition + 分治)


题目链接
题目

在这里插入图片描述


直接排序

方法一: 直接排序,取中间的数,最简单的方法。

class Solution{
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
}
HashMap计数

方法二: HashMap计数,然后检查value(次数) > n/2即可。

class Solution {
    // HashMap count
    public int majorityElement(int[] nums) {
        HashMap<Integer, Integer> counts = new HashMap<>();
        for(int num : nums){
            counts.put(num, counts.getOrDefault(num, 0) + 1);
            if(counts.get(num) > nums.length/2)
                return num;
        }
        return -1;
    }
}
利用二进制位运算

方法三: 利用二进制位运算,检查每一个二进制位是否为1,如果是就累加count, 如果>n/2就置为1

在这里插入图片描述

class Solution {
    // bit
    public int majorityElement(int[] nums) {
        int major = 0;
        for(int i = 0; i < 32; i++){ 
            int mask = 1 << i;
            int count = 0;
            for(int num : nums) if( (num&mask) != 0)
                count++;
            if(count > nums.length/2)
                major |= mask;
        }
        return major;
    }
}
维护更新方法

方法四: 很巧妙的方法:

  • 维护一个count值和当前最多major,然后如果当前值 ==major,则累加count
  • 如果不是,就--count,最后的答案就是major,这是最好的方法,时间复杂度O(N),空间O(1)
class Solution{
    // O(1) count  --> best Solution
    public int majorityElement(int[] nums) {
        int count = 0;
        int major = nums[0];
        for(int num : nums){ 
            if(num == major) count += 1;
            else if(--count == 0){ 
                count = 1;
                major = num;
            }
        }
        return major;
    }
}
利用快排的Partition

方法五: 利用快排的双路快速排序,也就是按照key将数组划分成,左边都<=key,右边都>=key的数组,然后看返回的这个划分索引是不是等于n/2即可,如果不是,就按照类似二分的思想继续查找。

class Solution {
    // use partition 
    public int majorityElement(int[] nums) {
        int mid = nums.length >> 1;
        int L = 0;
        int R = nums.length - 1;
        int p = partition(nums, L, R);
        while(p != mid){       
            if(p > mid)
                R = p - 1;
            else 
                L = p + 1;
            p = partition(nums, L, R);
        }
        return nums[mid];
    }
    
    // 双路快排 : 左边部分 <= key, 右边部分 >= key
    private int partition(int[] arr, int L, int R){
        int key = arr[L];
        int less = L + 1;
        int more = R;
        while(true){
            while(less < R && arr[less] < key) less++; // 找到第一个>=key的
            while(more > L && arr[more] > key) more--; // 找打第一个<=key的
            if(less >= more) 
                break;
            swap(arr, less++, more--);
        }
        swap(arr, L, more); // 最后将key放在中间
        return more;
    }

    private void swap(int[] arr, int a, int b){ 
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }
}
分治方法

方法六: 分治解法

  • 递归求出左边的值LS和右边的值RS,如果左右相等,则直接返回;
  • 否则,统计当前[L, R]区间中LSRS哪一个更多,哪个多就返回哪个;
class Solution {
    // divide and conquer
    public int majorityElement(int[] nums) {
        return divc(nums, 0, nums.length - 1); 
    }
    private int divc(int[] nums, int L, int R){ 
        if(L == R) // 只有一个元素, 直接返回
            return nums[L];
        int mid = L + (R - L)/2;
        int LS = divc(nums, L, mid);
        int RS = divc(nums, mid+1, R);
        if(LS == RS) // 两边的众数相同,直接返回即可
            return LS;
        int c1 = 0, c2 = 0;
        for(int i = L; i <= R; i++){ 
            if(nums[i] == LS) c1++;
            if(nums[i] == RS) c2++;
        }
        return c1 > c2 ? LS : RS;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值