• 【面试题39:数组当中数字超过一半的数字】


       求数组当中元素个数超过一半的数字,例如一个长度为7的数组:{1,2,2,2,2,4,5};其中元素2的个数为4,长度超过了一半;

    我的做法是:(假设输入是vector<int> vec)构建一个map<int, int>;key对应vec当中元素,value对应vec当中元素出现次数。我们遍历vec_,然后直接执行map_[ele_]++。遍历完之后,再遍历map就很容易找出这个数。

     1 int MoreThanHalfNum_Solution1(vector<int>& vec_)
     2 {
     3     // 异常处理
     4     if (vec_.empty())
     5         return -1;
     6 
     7     map<int, int> map_;
     8     for (auto ele_ : vec_)
     9     {
    10         map_[ele_]++;
    11     }
    12 
    13     int half_num_ = vec_.size() / 2;
    14     for (auto ele_ : map_)
    15     {
    16         if (ele_.second > half_num_)
    17         {
    18             return ele_.first;
    19         }
    20     }
    21     // 可能不存在这样的数
    22     return -1;
    23 }

    这种做法的缺点是:我在这里利用了map这种关联容器。在插入新元素的时候,如果已经存在相同key的元素,这时候会插入失败。不管怎样,插入新元素的时候,都会遍历map一次。

    改进做法:例如:对于数组{1,1,1,2,2,3,4,4,4,4};遍历数组,设置times_ =  0;

    1、如果 当前元素和上一个元素相同,则 times_ ++;

    2、如果 当前元素和上一个元素不同,则 times_ --;

    3、如果times_ = 0,则将上一个元素刷新为当前元素,times_ = 1;

     1 //统计元素 result_ 在 vec_数组当中是否超过半数
     2 bool CheckMoreHalf(vector<int>& vec_, int retsult_)
     3 {
     4     if (vec_.empty())
     5         return -1;
     6 
     7     int count = 0;
     8     for (auto ele_:vec_)
     9     {
    10         if ( ele_ == retsult_)
    11         {
    12             count++;
    13         }
    14     }
    15 
    16     if (2*count >= vec_.size())
    17     {
    18         return true;
    19     }
    20     else
    21     {
    22         return false;
    23     }
    24 
    25 }
    View Code
     1 int MoreThanHalfNum_Solution2(vector<int>& vec_)
     2 {
     3     if (vec_.empty())
     4         return -1;
     5 
     6     int ret_ = vec_[0];
     7     int times_ = 1;
     8     for (auto ele_:vec_)
     9     {
    10         if (times_ == 0)
    11         {
    12             ret_ = ele_;
    13             times_ = 1;
    14         }
    15         else if (ele_ == ret_)
    16             times_++;
    17         else
    18             times_--;
    19     }
    20     if (!CheckMoreHalf(vec_, ret_))
    21     {
    22         ret_ = -1;
    23     }
    24     return ret_;
    25 }

    方法2的优点是时间复杂度明显是O(n);其实方法1的时间复杂度表面上看是O(n);由于每一次循环都会调用map底层排序(基于红黑树)。所以,方法一的复杂度远不止O(n);有关几种常用排序算法,这里不作讨论了。

    现在我们做实验,将数组size设置到20000+

      1 #include<map>
      2 #include<vector>
      3 #include<iostream>
      4 
      5 using namespace std;
      6 
      7 #include<boost/timer.hpp>
      8 
      9 int MoreThanHalfNum_Solution1(vector<int>& vec_)
     10 {
     11     // 异常处理
     12     if (vec_.empty())
     13         return -1;
     14 
     15     map<int, int> map_;
     16     for (auto ele_ : vec_)
     17     {
     18         map_[ele_]++;
     19     }
     20 
     21     int half_num_ = vec_.size() / 2;
     22     for (auto ele_ : map_)
     23     {
     24         if (ele_.second > half_num_)
     25         {
     26             return ele_.first;
     27         }
     28     }
     29     // 可能不存在这样的数
     30     return -1;
     31 }
     32 
     33 //统计元素 result_ 在 vec_数组当中是否超过半数
     34 bool CheckMoreHalf(vector<int>& vec_, int retsult_)
     35 {
     36     if (vec_.empty())
     37         return -1;
     38 
     39     int count = 0;
     40     for (auto ele_:vec_)
     41     {
     42         if ( ele_ == retsult_)
     43         {
     44             count++;
     45         }
     46     }
     47 
     48     if (2*count >= vec_.size())
     49     {
     50         return true;
     51     }
     52     else
     53     {
     54         return false;
     55     }
     56 
     57 }
     58 
     59 int MoreThanHalfNum_Solution2(vector<int>& vec_)
     60 {
     61     if (vec_.empty())
     62         return -1;
     63 
     64     int ret_ = vec_[0];
     65     int times_ = 1;
     66     for (auto ele_:vec_)
     67     {
     68         if (times_ == 0)
     69         {
     70             ret_ = ele_;
     71             times_ = 1;
     72         }
     73         else if (ele_ == ret_)
     74             times_++;
     75         else
     76             times_--;
     77     }
     78     if (!CheckMoreHalf(vec_, ret_))
     79     {
     80         ret_ = -1;
     81     }
     82     return ret_;
     83 }
     84 
     85 int main()
     86 {
     87     vector<int> vec_{ 1,3,4,5,6,6,6,6,6,6,6,2,7 };
     88     for (int i = 0; i < 20000; i++)
     89     {
     90         vec_.push_back(8);
     91     }
     92 
     93     boost::timer timer1;
     94     cout << "MoreThanHalfNum_Solution1 : " << MoreThanHalfNum_Solution1(vec_) << endl;
     95     cout << "the cost of time is:" << timer1.elapsed() << endl;
     96 
     97     boost::timer timer2;
     98     cout << "MoreThanHalfNum_Solution2 : " << MoreThanHalfNum_Solution2(vec_) << endl;
     99     cout << "the cost of time is:" << timer2.elapsed() << endl;
    100 
    101     return 1;
    102 }

    Debug X64模式:

     

    以上四次实验:从上往下,输入数组规模一次增大,分别为:2000、4000、20000、40000;

    可以看到第二种算法速度总是第一种的5倍以上;所以,c++ STL虽然用起来舒服,但是还是要站在效率的角度上,适当使用STL,且要用对、用准相应容器类型。

  • 相关阅读:
    设计模式观察者模式在Java中的使用示例
    设计模式装饰者模式在Java中的使用示例
    git 恢复误删的远程分支
    从基础到实战 手把手带你掌握新版Webpack4.0
    掘金小册 – Taro 多端开发实现原理与项目实战
    react+tsx中使用betterscroll
    Taro3最新版本开发企业级出行全栈项目
    babelpolyfill的几种使用方式
    Vue3 + React18 + TS4 入门到实战
    typescript学习
  • 原文地址:https://www.cnblogs.com/winslam/p/10119287.html
Copyright © 2020-2023  润新知