leetcode
leetcode 2851 ~ 2900
主要元素

主要元素

难度:

标签:

题目描述

A majority element is an element that makes up more than half of the items in an array. Given a integers array, find the majority element. If there is no majority element, return -1. Do this in O(N) time and O(1) space.

Example 1:

Input: [1,2,5,9,5,9,5,5,5]
Output: 5

 

Example 2:

Input: [3,2]
Output: -1

 

Example 3:

Input: [2,2,1,1,1,2,2]
Output: 2

代码结果

运行时间: 28 ms, 内存: 17.6 MB


/*
 * 思路:虽然 Java Stream API 不适用于所有 O(1) 空间复杂度的场景,但我们可以通过转换为基本数组操作来使用流。
 * 这里我们依然使用摩尔投票算法,但将其包装在流中处理。
 */
import java.util.stream.IntStream;

public class MainElementFinderStream {
    public int findMajorityElement(int[] nums) {
        // 第一步:找到候选元素
        int[] candidateAndCount = IntStream.of(nums).collect(() -> new int[]{0, 0}, (acc, num) -> {
            if (acc[1] == 0) {
                acc[0] = num;
            }
            acc[1] += (num == acc[0]) ? 1 : -1;
        }, (acc1, acc2) -> {});

        int candidate = candidateAndCount[0];

        // 第二步:验证候选元素是否为主要元素
        long count = IntStream.of(nums).filter(num -> num == candidate).count();

        return count > nums.length / 2 ? candidate : -1;
    }

    public static void main(String[] args) {
        MainElementFinderStream finder = new MainElementFinderStream();
        int[] nums1 = {1, 2, 5, 9, 5, 9, 5, 5, 5};
        int[] nums2 = {3, 2};
        int[] nums3 = {2, 2, 1, 1, 1, 2, 2};
        System.out.println(finder.findMajorityElement(nums1)); // 输出 5
        System.out.println(finder.findMajorityElement(nums2)); // 输出 -1
        System.out.println(finder.findMajorityElement(nums3)); // 输出 2
    }
}

解释

方法:

这个题解采用了摩尔投票算法(Boyer-Moore Voting Algorithm),用于找出数组中的主要元素。算法的基本思路是维护一个候选主要元素和一个计数器。遍历数组时,若计数器为零,则将当前元素设置为候选元素,并将计数器设为1。如果计数器不为零,当遇到与候选元素相同的数时,计数器加1;否则,计数器减1。这样,遍历结束后,候选元素可能是主要元素。然而,由于计数器的减少可能导致非主要元素成为候选,因此需要再次遍历数组来确认候选元素的出现次数是否真的超过了数组长度的一半。若是,则返回该元素;若不是,则返回-1。

时间复杂度:

O(N)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在摩尔投票算法中,遇到与候选元素不同的元素时,计数器需要减1?
摩尔投票算法的核心思想是通过对抗消除的方式,找出可能的主要元素。当计数器为正时,表示当前候选元素存在超过其他所有不同元素的数量。遇到一个与候选元素不同的元素时,理论上这两个元素会相互抵消掉一部分影响力,因此需要将计数器减1。这样做的目的是尝试抵消与当前候选元素可能存在的数量对等的其他元素,以帮助确定真正的主要元素。
🦆
在算法的第二次遍历中,是如何确认候选元素是否真的是主要元素的?
在摩尔投票算法的第一次遍历后,我们得到了一个可能的候选元素,但这个候选元素可能并非真正的主要元素。因此,在第二次遍历中,我们需要统计这个候选元素在数组中的出现次数,确认它的数量是否确实超过了数组长度的一半。仅当候选元素的出现次数大于数组长度的一半时,我们才可以确定它是主要元素。否则,返回-1表示没有主要元素。
🦆
如果数组中的元素都不相同,摩尔投票算法的候选元素会是怎样的?
如果数组中的每个元素都是唯一的,那么摩尔投票算法在第一次遍历过程中的候选元素将频繁更换,最终的候选元素将是数组中的最后一个元素。这是因为每次遇到新的元素都会导致当前候选元素的计数器归零,然后将新的元素设置为候选元素。但在第二次遍历的验证中,由于没有任何元素的出现次数超过数组长度的一半,算法最终将返回-1。

相关问题