排序题目:多数元素

文章目录

题目

标题和出处

标题:多数元素

出处:169. 多数元素

难度

2 级

题目描述

要求

给定大小为 n \texttt{n} n 的数组 nums \texttt{nums} nums,返回其中的多数元素。

多数元素是指在数组中出现次数大于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{\texttt{n}}{\texttt{2}} \Big\rfloor ⌊2n⌋ 的元素。可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例

示例 1:

输入: nums = [3,2,3] \texttt{nums = [3,2,3]} nums = [3,2,3]

输出: 3 \texttt{3} 3

示例 2:

输入: nums = [2,2,1,1,1,2,2] \texttt{nums = [2,2,1,1,1,2,2]} nums = [2,2,1,1,1,2,2]

输出: 2 \texttt{2} 2

数据范围

  • n = nums.length \texttt{n} = \texttt{nums.length} n=nums.length
  • 1 ≤ n ≤ 5 × 10 4 \texttt{1} \le \texttt{n} \le \texttt{5} \times \texttt{10}^\texttt{4} 1≤n≤5×104
  • -10 9 ≤ nums[i] ≤ 10 9 \texttt{-10}^\texttt{9} \le \texttt{nums[i]} \le \texttt{10}^\texttt{9} -109≤nums[i]≤109

进阶

你可以使用线性时间复杂度和 O(1) \texttt{O(1)} O(1) 空间复杂度解决此问题吗?

解法一

思路和算法

最直观的解法是统计数组中每个元素的出现次数,然后寻找出现次数大于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 的元素。

遍历数组,使用哈希表记录每个元素的出现次数,遍历结束之后即可得到数组中每个元素的出现次数。然后遍历哈希表,对于哈希表中的每个元素得到出现次数,返回出现次数大于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 的元素。

代码

java 复制代码
class Solution {
    public int majorityElement(int[] nums) {
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        for (int num : nums) {
            counts.put(num, counts.getOrDefault(num, 0) + 1);
        }
        int majority = 0;
        int n = nums.length;
        Set<Integer> set = counts.keySet();
        for (int num : set) {
            if (counts.get(num) > n / 2) {
                majority = num;
                break;
            }
        }
        return majority;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。遍历数组统计每个元素的出现次数需要 O ( n ) O(n) O(n) 的时间,遍历哈希表得到多数元素也需要 O ( n ) O(n) O(n) 的时间。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要创建哈希表记录每个元素的出现次数,哈希表中的元素个数不超过 n n n。

解法二

思路和算法

另一个解法是将数组排序后得到多数元素。排序后的数组满足相等的元素一定出现在数组中的相邻位置,由于多数元素在数组中的出现次数大于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋,因此排序后的数组中存在至少 ⌊ n 2 ⌋ + 1 \Big\lfloor \dfrac{n}{2} \Big\rfloor + 1 ⌊2n⌋+1 个连续的元素都是多数元素,下标 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 的元素一定是多数元素。理由如下:

  • 如果多数元素是数组中的最小元素,则排序后的数组从下标 0 0 0 到下标 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 的元素都是多数元素;

  • 如果多数元素是数组中的最大元素,则排序后的数组从下标 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 到下标 n − 1 n - 1 n−1 的元素都是多数元素;

  • 如果多数元素不是数组中的最小元素和最大元素,则排序后的数组的下标 0 0 0 和下标 n − 1 n - 1 n−1 的元素都不是多数元素,多数元素的开始下标一定小于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋,结束下标一定大于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋,下标 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 的元素一定是多数元素。

因此将数组排序之后返回下标 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 的元素即可。

代码

java 复制代码
class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        return nums[n / 2];
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间。

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间。

解法三

思路和算法

寻找多数元素的另一种解法是摩尔投票算法,其时间复杂度是 O ( n ) O(n) O(n),空间复杂度是 O ( 1 ) O(1) O(1)。

摩尔投票算法由 Robert S. Boyer 和 J Strother Moore 提出,该算法的基本思想是:在每一轮投票过程中,从数组中删除两个不同的元素,直到投票过程无法继续,此时数组为空或者数组中剩下的元素都相等。

摩尔投票算法的具体做法如下。

  1. 维护多数元素 majority \textit{majority} majority 和多数元素的出现次数 count \textit{count} count,初始时 majority \textit{majority} majority 为数组的首个元素, count = 1 \textit{count} = 1 count=1。

  2. 遍历数组中除了首个元素以外的所有元素,当遍历到元素 num \textit{num} num 时,执行如下操作。

    1. 如果 count = 0 \textit{count} = 0 count=0,则将 majority \textit{majority} majority 的值更新为 num \textit{num} num,否则不更新 majority \textit{majority} majority 的值。

    2. 如果 num = majority \textit{num} = \textit{majority} num=majority,则将 count \textit{count} count 加 1 1 1,否则将 count \textit{count} count 减 1 1 1。

由于这道题中多数元素总是存在,因此遍历结束之后, majority \textit{majority} majority 即为多数元素。

如果不保证多数元素一定存在,则当多数元素不存在时,遍历结束之后的 majority \textit{majority} majority 可能为数组中的任意一个元素。此时需要再次遍历数组,统计 majority \textit{majority} majority 在数组中的出现次数,当 majority \textit{majority} majority 的出现次数大于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 时 majority \textit{majority} majority 是多数元素,当 majority \textit{majority} majority 的出现次数小于等于 ⌊ n 2 ⌋ \Big\lfloor \dfrac{n}{2} \Big\rfloor ⌊2n⌋ 时没有多数元素。

考虑示例 1, nums = [ 3 , 2 , 3 ] \textit{nums} = [3, 2, 3] nums=[3,2,3],使用摩尔投票算法寻找多数元素的过程如下。

  1. 初始化 majority = nums [ 0 ] = 3 \textit{majority} = \textit{nums}[0] = 3 majority=nums[0]=3, count = 1 \textit{count} = 1 count=1。

  2. 遍历到 nums [ 1 ] = 2 \textit{nums}[1] = 2 nums[1]=2。

    1. 由于 count = 1 \textit{count} = 1 count=1,因此不更新 majority \textit{majority} majority 的值。

    2. 由于当前元素不等于 majority \textit{majority} majority,因此将 count \textit{count} count 减 1 1 1, count \textit{count} count 变成 0 0 0。

  3. 遍历到 nums [ 2 ] = 3 \textit{nums}[2] = 3 nums[2]=3。

    1. 由于 count = 0 \textit{count} = 0 count=0,因此将 majority \textit{majority} majority 的值更新为当前元素 3 3 3。

    2. 由于当前元素等于 majority \textit{majority} majority,因此将 count \textit{count} count 加 1 1 1, count \textit{count} count 变成 1 1 1。

  4. 遍历结束, majority = 3 \textit{majority} = 3 majority=3,多数元素是 3 3 3。

代码

java 复制代码
class Solution {
    public int majorityElement(int[] nums) {
        int majority = nums[0];
        int count = 1;
        int n = nums.length;
        for (int i = 1; i < n; i++) {
            int num = nums[i];
            if (count == 0) {
                majority = num;
            }
            if (num == majority) {
                count++;
            } else {
                count--;
            }
        }
        return majority;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 一次。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

相关推荐
T.Ree.2 天前
【数据结构】_排序
数据结构·算法·排序算法·排序
laufing5 天前
OD 算法题 B卷【比赛】
数据结构·排序·逻辑分析
Tipriest_13 天前
【C++20新特性】ranges::sort()使用方法,优势,注意点
算法·leetcode·c++20·排序·sort
阳洞洞17 天前
leetcode 148. Sort List
leetcode·链表·归并排序·递归·排序
winfredzhang18 天前
打造高效数据处理利器:用Python实现Excel文件智能合并工具
python·excel·合并·排序·xlsx
GUIQU.19 天前
【每日一题丨2025年5.12~5.18】排序相关题
算法·排序·每日一题
Espresso Macchiato21 天前
Leetcode 3551. Minimum Swaps to Sort by Digit Sum
leetcode·排序·leetcode medium·leetcode 3551·leetcode周赛450
吗喽对你问好1 个月前
华为5.7机考第一题充电桩问题Java代码实现
java·华为·排序
yxc_inspire1 个月前
常见排序算法记录和理解
算法·排序
Tisfy2 个月前
LeetCode 2563.统计公平数对的数目:排序 + 二分查找
python·算法·leetcode·二分查找·题解·排序