• 【LeetCode】19. Majority Element·多数元素


    ​活动地址:CSDN21天学习挑战赛

     题目描述

    英文版描述

    Given an array nums of size n, return the majority element. The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array.

    英文版地址

    https://leetcode.com/problems/majority-element/

    中文版描述

    给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。

    示例 1:

    输入:nums = [3,2,3]

    输出:3

    示例 2:

    输入:nums = [2,2,1,1,1,2,2]

    输出:2

    提示:

    • n == nums.length

    • 1 <= n <= 5 * 10^4

    • -10^9 <= nums[i] <= 10^9

    中文版地址

    https://leetcode.cn/problems/majority-element/

    解题思路

    比较直接的想法是遍历数组,然后存进一个Map<数字,出现次数>,然后判断哪个出现次数大于数组长度的一半。 思考下如何优化?

    • 添加判断,如果当前计数的数字已经大于或者等于数组长度的一半,就结束遍历

    解题方法

    俺这版

    1. class Solution {
    2. public int majorityElement(int[] nums) {
    3. Map map = new HashMap<>();
    4. int length = nums.length;
    5. if (length == 1) {
    6. return nums[0];
    7. }
    8. for (int i = 0; i < length; i++) {
    9. int num = nums[i];
    10. if (map.containsKey(num)) {
    11. Integer count = map.get(num);
    12. count = count + 1;
    13. if (count > length / 2) {
    14. return num;
    15. }
    16. map.put(num, count);
    17. } else {
    18. map.put(num, 1);
    19. }
    20. }
    21. return 0;
    22. }
    23. }

    复杂度分析

    • 时间复杂度:O(n),n是数组的长度,遍历数组并添加进Map,总体时长不会超过n

    • 空间复杂度:O(n),n是数组的长度,遍历数组并添加进Map,Map所占空间不会超过n

    官方版

    方法一:哈希表

    1. class Solution {
    2. private Map countNums(int[] nums) {
    3. Map counts = new HashMap();
    4. for (int num : nums) {
    5. if (!counts.containsKey(num)) {
    6. counts.put(num, 1);
    7. } else {
    8. counts.put(num, counts.get(num) + 1);
    9. }
    10. }
    11. return counts;
    12. }
    13. public int majorityElement(int[] nums) {
    14. Map counts = countNums(nums);
    15. Map.Entry majorityEntry = null;
    16. for (Map.Entry entry : counts.entrySet()) {
    17. if (majorityEntry == null || entry.getValue() > majorityEntry.getValue()) {
    18. majorityEntry = entry;
    19. }
    20. }
    21. return majorityEntry.getKey();
    22. }
    23. }

    方法二:排序

    1. class Solution {
    2. public int majorityElement(int[] nums) {
    3. Arrays.sort(nums);
    4. return nums[nums.length / 2];
    5. }
    6. }

    方法三:随机化

    由于一个给定的下标对应的数字很有可能是众数,我们随机挑选一个下标,检查它是否是众数,如果是就返回,否则继续随机挑选。

    1. class Solution {
    2. private int randRange(Random rand, int min, int max) {
    3. return rand.nextInt(max - min) + min;
    4. }
    5. private int countOccurences(int[] nums, int num) {
    6. int count = 0;
    7. for (int i = 0; i < nums.length; i++) {
    8. if (nums[i] == num) {
    9. count++;
    10. }
    11. }
    12. return count;
    13. }
    14. public int majorityElement(int[] nums) {
    15. Random rand = new Random();
    16. int majorityCount = nums.length / 2;
    17. while (true) {
    18. int candidate = nums[randRange(rand, 0, nums.length)];
    19. if (countOccurences(nums, candidate) > majorityCount) {
    20. return candidate;
    21. }
    22. }
    23. }
    24. }

    方法四:分治

    使用经典的分治算法递归求解,直到所有的子问题都是长度为 1 的数组。长度为 1 的子数组中唯一的数显然是众数,直接返回即可。如果回溯后某区间的长度大于 1,我们必须将左右子区间的值合并。如果它们的众数相同,那么显然这一段区间的众数是它们相同的值。否则,我们需要比较两个众数在整个区间内出现的次数来决定该区间的众数。

    1. class Solution {
    2. private int countInRange(int[] nums, int num, int lo, int hi) {
    3. int count = 0;
    4. for (int i = lo; i <= hi; i++) {
    5. if (nums[i] == num) {
    6. count++;
    7. }
    8. }
    9. return count;
    10. }
    11. private int majorityElementRec(int[] nums, int lo, int hi) {
    12. // base case; the only element in an array of size 1 is the majority
    13. // element.
    14. if (lo == hi) {
    15. return nums[lo];
    16. }
    17. // recurse on left and right halves of this slice.
    18. int mid = (hi - lo) / 2 + lo;
    19. int left = majorityElementRec(nums, lo, mid);
    20. int right = majorityElementRec(nums, mid + 1, hi);
    21. // if the two halves agree on the majority element, return it.
    22. if (left == right) {
    23. return left;
    24. }
    25. // otherwise, count each element and return the "winner".
    26. int leftCount = countInRange(nums, left, lo, hi);
    27. int rightCount = countInRange(nums, right, lo, hi);
    28. return leftCount > rightCount ? left : right;
    29. }
    30. public int majorityElement(int[] nums) {
    31. return majorityElementRec(nums, 0, nums.length - 1);
    32. }
    33. }

    方法五:Boyer-Moore 投票算法

    1. class Solution {
    2. public int majorityElement(int[] nums) {
    3. int count = 0;
    4. Integer candidate = null;
    5. for (int num : nums) {
    6. if (count == 0) {
    7. candidate = num;
    8. }
    9. count += (num == candidate) ? 1 : -1;
    10. }
    11. return candidate;
    12. }
    13. }

    总结

    这是我碰到官方提供方法最多的一次,,,没有之一=[,,_,,]:3 排序的那个方法中真的太机智叻>>>冒个泡.。oO感慨下 随机化那个方法= = ,呃,建议运气不太行(比如年会只能抽到幸运奖/安慰奖的同学)别试 

  • 相关阅读:
    jQuery选择器参考手册
    第一天:Python元学习——通用人工智能的实现
    【韩老师设计模式8】模板方法和命令模式,ConfigurableApplicationContext,JdbcTemplate
    搭建国外服务器
    2024年孝感市建筑类中级职称申报资料私企VS国企
    redis一条set命令的执行过程
    在微信公众号怎么实现全民经纪人功能
    Elasticsearch:运用向量搜索通过图像搜索找到你的小狗
    力扣题库2. 两数相加
    SpringBoot2.0---------------6、SpringBoot开发小技巧
  • 原文地址:https://blog.csdn.net/aqin1012/article/details/126380977