zoukankan      html  css  js  c++  java
  • [九度][何海涛] 数组中出现次数超过一半的数字

    题目描述:

    数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

    输入:

    每个测试案例包括2行:

    第一行输入一个整数n(1<=n<=100000),表示数组中元素的个数。

    第二行输入n个整数,表示数组中的每个元素,这n个整数的范围是[1,1000000000]。

    输出:

    对应每个测试案例,输出出现的次数超过数组长度的一半的数,如果没有输出-1。

    样例输入:
    9
    1 2 3 2 2 2 5 4 2
    
    样例输出:
    2


    这道题可以分两种方法做。方法1:类似于消除原理,既然某个数字大于长度的一半,那么我们就遍历数组,如果两个数不相等则消除,最后剩下的数就是我们要的。当然如果不存在这样的数,这是不行的。所以最后要再遍历一遍验证这个数的出现次数是否大于数组的一半。
     1 #include <iostream>
     2 using namespace std;
     3 
     4 bool check(int num[], int key, int n)
     5 {
     6     int count = 0;
     7     for(int i = 0; i < n; i++)
     8         count += (key == num[i]);
     9 
    10     return 2 * count > n;
    11 }
    12 
    13 int main()
    14 {
    15     int firstCount = 0;
    16     int secondCount = 0;
    17     int firstNum;
    18     int secondNum;
    19     int num[100000];
    20 
    21     int n;
    22     while(cin >> n)
    23     {
    24         firstCount = 0;
    25         secondCount = 0;
    26         for(int i = 0; i < n; i++)
    27         {
    28             cin >> num[i];
    29             if (firstCount > 0 && num[i] == firstNum)
    30             {
    31                 firstCount++;
    32             }
    33             else if (secondCount > 0 && num[i] == secondNum)
    34             {
    35                 secondCount++;
    36             }
    37             else if (firstCount == 0)
    38             {
    39                 firstNum = num[i];
    40                 firstCount = 1;
    41             }
    42             else if (secondCount == 0)
    43             {
    44                 secondNum = num[i];
    45                 secondCount = 1;
    46             }
    47             else
    48             {
    49                 int minCount = min(secondCount, firstCount);
    50                 secondCount -= minCount;
    51                 firstCount -= minCount;
    52                 if (secondCount == 0)
    53                 {
    54                     secondNum = num[i];
    55                     secondCount = 1;
    56                 }
    57                 else
    58                 {
    59                     firstNum = num[i];
    60                     firstCount = 1;
    61                 }
    62             }
    63         }
    64 
    65         int minV = min(firstCount, secondCount);
    66         firstCount -= minV;
    67         secondCount -= minV;
    68 
    69         if (firstCount > 0)
    70         {
    71             if (check(num, firstNum, n))
    72                 cout << firstNum << endl;
    73             else
    74                 cout << -1 << endl;
    75         }
    76         else if (secondCount > 0)
    77         {
    78             if (check(num, secondNum, n))
    79                 cout << secondNum << endl;
    80             else
    81                 cout << -1 << endl;
    82         }
    83         else
    84             cout << -1 << endl;
    85     }
    86 }

    方法2:用qsort的partition的方法找出第k大数,k就是数组中间的数,对于n为偶数是中间两个的任意一个数,奇数的话就只有一个。那么,因为数的个数超过一半,那么中间那个数肯定是超过一半的那个数,否则这个数就不存在了。最后遍历一遍数组来验证一下。partition的平摊复杂度为O(n)。最后算法总体复杂度O(n)

     1 #include <iostream>
     2 #include <ctime>
     3 #include <cmath>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 void partition(int num[], int left, int right, int k)
     8 {
     9     if (left >= right)
    10         return;
    11 
    12     int randNum = left + (rand() % (right - left + 1));
    13 
    14     int t = num[left];
    15     num[left] = num[randNum];
    16     num[randNum] = t;
    17 
    18     int i = left;
    19     int j = right;
    20 
    21     int key = num[left];
    22 
    23     while(i <= j)
    24     {
    25         if (num[i] <= key)
    26             i++;
    27         else
    28         {
    29             int t = num[j];
    30             num[j] = num[i];
    31             num[i] = t;
    32 
    33             j--;
    34         }
    35     }
    36 
    37     num[left] = num[j];
    38     num[j] = key;
    39 
    40     if (j == k)
    41         return;
    42     else
    43     {
    44         partition(num, left, j - 1, k);
    45         partition(num, j + 1, right, k);
    46     }
    47 }
    48 
    49 int main()
    50 {
    51     int n;
    52     int num[100000];
    53 
    54     while(cin >> n)
    55     {
    56         for(int i = 0; i < n; i++)
    57             cin >> num[i];
    58 
    59         srand(time(NULL));
    60         partition(num, 0, n - 1, n / 2);
    61 
    62         int key = num[n / 2];
    63 
    64         int count = 0;
    65         for(int i = 0; i < n; i++)
    66             count += (key == num[i]);
    67 
    68         if (2 * count > n)
    69             cout << key << endl;
    70         else
    71             cout << -1 << endl;
    72     }
    73 }
  • 相关阅读:
    leetcode刷题11. 盛最多水的容器
    docker报错Service 'pwn_deploy_chroot' failed to build: Get https://registry-1.docker.io/v2/library/ubuntu/manifests/16.04:net/http: request canceled
    常用断点记录
    c++继承学习
    leetcode刷题正则表达式
    x64类型的程序逆向思考
    vs2013下配置x64版c++
    MFC学习RepositionBars
    flask权限控制
    leetcode刷题七<整数反转>
  • 原文地址:https://www.cnblogs.com/chkkch/p/2782198.html
Copyright © 2011-2022 走看看