LeetCode(169&229):求众数I&II Majority Element I&II(Java)

234 篇文章 1 订阅
177 篇文章 0 订阅

2019.7.29 #程序员笔试必备# LeetCode 从零单刷个人笔记整理(持续更新)

求众数I(数目大于1/2)的方法主要有三种:

1.数组排序后直接选定正中间的数值

2.哈希表计数

3.Boyer-Moore投票算法(时间复杂度o(n),空间复杂度o(1))

设定侯选数candidate,当票数count为0时更新candidate为当前的数字,票数+1。

出现与candidate相同的数字,票数+1,反之票数-1。

总体上看,每两个不同的数字会进行一次消去,最后剩下最多的众数。


求众数II(数目大于1/3),题目限定的时间和空间复杂度,那就只能用Boyer-Moore投票算法了,而且需要对算法进行改进。思路如下:

首先明确超过n/3的数最多只能有两个,因此需要两个candidate,A和B。

遍历数组,可能情况有3种:

1.出现与A或B相同的数字,则对应的票数+1

2.数字不同,且A或B票数为0,则将当前数字替换为新的candidate

3.数字不同且票数都不为0,则A,B票数均-1,进行消去

遍历结束后选出两个数量最多的candidate,检查其出现次数是否大于n/3,满足则输出。(两个candidate不可能相同且同时大于1/3)


传送门:求众数

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.

给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

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

示例 1:
输入: [3,2,3]
输出: 3

示例 2:
输入: [2,2,1,1,1,2,2]
输出: 2

传送门:求众数II

Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

Note: The algorithm should run in linear time and in O(1) space.

给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。

示例 1:
输入: [3,2,3]
输出: [3]

示例 2:
输入: [1,1,1,3,3,2,2,2]
输出: [1,2]


import java.util.Arrays;
import java.util.HashMap;

/**
 *
 * Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
 * You may assume that the array is non-empty and the majority element always exist in the array.
 * 给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
 * 你可以假设数组是非空的,并且给定的数组总是存在众数。
 *
 */

public class MajorityElement {

    //排序法
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length >> 1];
    }

    //哈希表
    public int majorityElement1(int[] nums) {
        if(nums.length == 1)
            return nums[0];

        HashMap<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            if (!counts.containsKey(num)) {
                counts.put(num, 1);
            }
            else {
                if(counts.get(num) >= (nums.length >> 1))
                    return num;
                counts.put(num, counts.get(num)+1);
            }
        }
        return -1;
    }

    //Boyer-Moore投票算法
    //时间复杂度o(n),空间复杂度o(1)
    public int majorityElement2(int[] nums){
        int count = 0;
        Integer candidate = null;   //用Integer对象可以令candidate初始值不等于任何实数

        //设定侯选数candidate,当票数count为0时更新candidate为当前的数字,票数+1。
        //出现与candidate相同的数字,票数+1,反之票数-1。
        //总体上看,每两个不同的数字会进行一次消去,最后剩下最多的众数
        for(int num : nums){
            candidate = count == 0 ? num : candidate;
            count += (num == candidate) ? 1 : -1;
        }

        return candidate;
    }
    
    /// 题目众数改进为超过1/3的数(Leetcode229)///
    //改进Boyer-Moore投票算法
    //时间复杂度o(n),空间复杂度o(1)


    // 首先明确超过n/3的数最多只能有两个,因此需要两个candidate,A和B。
    // 遍历数组,可能情况有3种:
    // 1.出现与A或B相同的数字,则对应的票数+1
    // 2.数字不同,且A或B票数为0,则将当前数字替换为新的candidate
    // 3.数字不同且票数都不为0,则A,B票数均-1,进行消去
    // 遍历结束后选出两个数量最多的candidate,检查其出现次数是否大于n/3,满足则输出。(两个candidate不可能相同且同时大于1/3)
    public List<Integer> majorityElement3(int[] nums) {
        ArrayList<Integer> answer = new ArrayList<>();
        if(nums == null || nums.length == 0)
            return answer;

        //投票方法选出两个最多的候选人
        int countA = 0;
        int countB = 0;
        Integer candidateA = nums[0];
        Integer candidateB = nums[0];
        for(int num : nums){
            //num等于其中一个candidate
            if(num == candidateA){
                countA++;
            }
            else if(num == candidateB){
                countB++;
            }
            //num与candidate都不相同,根据count选择更新candidate(为0)或者消去一票
            else if(countA == 0){
                candidateA = num;
                countA = 1;
            }
            else if(countB == 0){
                candidateB = num;
                countB = 1;
            }
            else{
                countA--;
                countB--;
            }
        }

        //确认两个candidate票数是否超过1/3
        countA = 0;
        countB = 0;
        for(int num : nums){
            if(num == candidateA)
                countA++;
            else if(num == candidateB)
                countB++;
        }
        //两个candidate不可能相同且同时大于1/3
        if(countA > nums.length / 3)
            answer.add(candidateA);
        if(countB > nums.length / 3)
            answer.add(candidateB);

        return answer;
    }
}



#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值