找出整形数组中占比超过一半的数 | 豆包MarsCode AI刷题

55 阅读4分钟
 问题描述
 小R从班级中抽取了一些同学,每位同学都会给出一个数字。已知在这些数字中,某个数字的出现次数超过了数字总数的一半。现在需要你帮助小R找到这个数字。
 ​
 测试样例
 样例1:
 输入:array = [1, 3, 8, 2, 3, 1, 3, 3, 3]
 输出:3
 ​
 样例2:
 输入:array = [5, 5, 5, 1, 2, 5, 5]
 输出:5
 ​
 样例3:
 输入:array = [9, 9, 9, 9, 8, 9, 8, 8]
 输出:9

算法思路

摩尔投票算法是一种用于在数组中找到出现次数超过一半的元素的高效算法。

摩尔投票算法的原理

候选元素的选择

  • 算法的核心思想是通过不断抵消不同的元素来找到出现次数超过一半的元素。
  • 初始时,选择数组中的第一个元素作为候选元素 candidate,并设置计数器 count 为1。

遍历数组

  • 遍历数组中的每个元素:

  • 如果当前元素与 candidate 相同,则增加 count

  • 如果当前元素与 candidate 不同,则减少 count

  • 如果 count 变为零,则更新 candidate 为当前元素,并将 count 重置为1。

最终候选元素

  • 遍历结束后,candidate 就是出现次数超过一半的元素。
  • 这是因为出现次数超过一半的元素在抵消过程中会始终保持优势,最终成为 candidate

为什么这个算法有效?

  • 抵消机制

    • 假设数组中有一个元素 x 出现次数超过一半。
    • 在遍历过程中,每次遇到一个与 x 不同的元素,count 就会减少1。
    • 由于 x 的出现次数超过一半,最终 x 会抵消掉所有其他元素,使得 count 仍然大于零。
  • 计数器重置

    • count 变为零时,说明当前的 candidate 已经被抵消掉了。
    • 此时,选择一个新的 candidate 并重置 count,继续进行抵消过程。

摩尔投票算法通过抵消不同的元素来找到出现次数超过一半的元素,时间复杂度为 O(n),空间复杂度为 O(1)。

算法步骤

  • 初始化一个候选数字 candidate 和计数器 count

  • 遍历数组中的每个数字:

    • 如果 count 为零,将当前数字设为 candidate,并将 count 设为1。
    • 如果当前数字与 candidate 相同,增加 count
    • 如果当前数字与 candidate 不同,减少 count
  • 最终,candidate 就是我们要找的数字。

代码运行过程(举例)

输入:array = [1, 3, 8, 2, 3, 1, 3, 3, 3] 输出:3

  1. 初始化

    • candidate 初始化为 0
    • count 初始化为 0
  2. 遍历数组

    • 第一个元素 1

      • count0,所以更新 candidate1count1
      • 当前状态:candidate = 1, count = 1
    • 第二个元素 3

      • 3 不等于 candidate(即 1),所以 count1count 变为 0
      • 当前状态:candidate = 1, count = 0
    • 第三个元素 8

      • count0,所以更新 candidate8count1
      • 当前状态:candidate = 8, count = 1
    • 第四个元素 2

      • 2 不等于 candidate(即 8),所以 count1count 变为 0
      • 当前状态:candidate = 8, count = 0
    • 第五个元素 3

      • count0,所以更新 candidate3count1
      • 当前状态:candidate = 3, count = 1
    • 第六个元素 1

      • 1 不等于 candidate(即 3),所以 count1count 变为 0
      • 当前状态:candidate = 3, count = 0
    • 第七个元素 3

      • count0,所以更新 candidate3count1
      • 当前状态:candidate = 3, count = 1
    • 第八个元素 3

      • 3 等于 candidate(即 3),所以 count1count 变为 2
      • 当前状态:candidate = 3, count = 2
    • 第九个元素 3

      • 3 等于 candidate(即 3),所以 count1count 变为 3
      • 当前状态:candidate = 3, count = 3
  3. 返回结果

    • 遍历结束后,candidate3count3
    • 最终返回 candidate,即 3

Solution

 public class Main {
     public static int solution(int[] array) {
         // 初始化候选数字和计数器
         int candidate = 0;
         int count = 0;
 ​
         // 遍历数组
         for (int num : array) {
             // 如果计数器为零,更新候选数字
             if (count == 0) {
                 candidate = num;
                 count = 1;
             } else if (num == candidate) {
                 // 如果当前数字与候选数字相同,增加计数器
                 count++;
             } else {
                 // 如果当前数字与候选数字不同,减少计数器
                 count--;
             }
         }
 ​
         // 返回候选数字
         return candidate;
     }
 ​
     public static void main(String[] args) {
         // 添加你的测试用例
         System.out.println(solution(new int[]{1, 3, 8, 2, 3, 1, 3, 3, 3}) == 3);
         System.out.println(solution(new int[]{5, 5, 5, 1, 2, 5, 5}) == 5);
         System.out.println(solution(new int[]{9, 9, 9, 9, 8, 9, 8, 8}) == 9);
     }
 }