数组中有一个数字出现次数超过数组长度一半,找出这个数字(用C语言解决)。要求时间复杂度尽量小。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组中有一个数字出现次数超过数组长度一半,找出这个数字(用C语言解决)。要求时间复杂度尽量小。相关的知识,希望对你有一定的参考价值。

找出在一个数组中出现次数超过一半的数,可以这样理解,找一个数的中位数,基于这样思想最直观的做法是排序后找中间的数既可,但最好时间复杂度也得O(NlogN)
所以用一种简单的办法来解决
定义两个变量,从第一个数开始找,并记录第一个数为result为需要找的数,它出现的次数初始化times=1,以后只要找到和result相等的数rimes++,否则times--,当times等于0的时候,改变result等于当前指向的数,继续找
参考技术A 先排序,然后求最大平台。求最大平台的时间复杂性为O(n),这样排序的时间复杂性就是本问题的时间复杂性。所以用时间复杂性最小的排序方法排序吧。

出现次数超过一半的数字

题目

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

思路 

  1. 数组中出现次数超过一半,所以数组中间的数字一定就是那个出现次数超过数组一半的数字
  2. 基于快排算法中的Partition函数,使得比选中的数字小的数字都在它左边,比选中的数字大的数字都在它的右边
  3. 如果选中的数字的下标刚好是n/2,那么这个数字就是数组中的中位数
  4. 如果它的下标大于n/2,那么中位数应该位于它的左边,继续在左边寻找
  5. 如果它的下标小于n/2,那么中位数应该位于它的右边,继续在右边寻找
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution
{
    public:
        int more_half_num(vector<int> &v);
        int partition(vector<int> &v,int start,int end);
        bool check_more_than_half(vector<int> &v,int num);
        bool check_valid(vector<int> &v);
};
int Solution::more_half_num(vector<int> &v)
{
    if(!check_valid(v))
        return 0x3f3f;
    
    int mid=v.size()>>1;
    int start=0;
    int end=v.size()-1;
    int index=partition(v,start,end);
    while(index!=mid)
    {
        if(index>mid)
            index=partition(v,start,index-1);
        else
            index=partition(v,index+1,end);
    }
    int result=v[mid];
    if(check_more_than_half(v,result))
        return result;
    return 0x3f3f;
}
bool Solution::check_more_than_half(vector<int> &v,int num)
{
    int count=0;
    for(auto k:v)
    {
        if(k==num)
            ++count;
    }
    if(count<<1<v.size())
        return false;
    return true;
    
}
int Solution::partition(vector<int> &v,int start,int end)
{
    if(v.empty()||v.size()<=0||start<0||end>=v.size())
    {
        cerr<<"invalid parameter"<<endl;
        return -1;
    }
    
    int t=v[start];
    while(start<end)
    {
        while(start<end&&t<=v[end])
            --end;
        if(start<end)
            v[start++]=v[end];
            
        while(start<end&&t>v[start])
            ++start;
        if(start<end)
            v[end--]=v[start];
    }
    v[start]=t;
    return start;
}
bool Solution::check_valid(vector<int> &v)
{
    if(v.empty()||v.size()<0)
        return false;
    return true;
}
int main()
{
    vector<int> v{1,2,3,6,6,6,6,6,5};
    Solution s;
    int t=s.more_half_num(v);
    if(t!=0x3f3f)
        cout<<t<<endl;
    return 0;
}

  数组中出现次数超过一半,所以该数字出现的次数超过数组长度的一半,也就是它出现的次数比其他所有数字出现次数的和还要多;遍历数组的时候保存两个值:一个是数字,一个是次数。如果下一个数字和保存的数字相同,则次数加1;不相同则减1;如果次数为0,则保存下一个数字,次数设置为1。因为数字超过一半,所以最后一次数字大于1对应的数字则为符合题目要求的数字。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution
{
    public:
        int more_half_num(vector<int> &v);
        bool check_more_than_half(vector<int> &v,int num);
        bool check_valid(vector<int> &v);
};
int Solution::more_half_num(vector<int> &v)
{
    if(!check_valid(v))
        return 0x3f3f;
    
    int result=v[0];
    int count=1;
    for(int i=1;i<v.size();++i)
    {
        if(count==0)
        {
            result=v[i];
            count=1;
        }
        else if(result==v[i])//如果记录的值与统计值相等,记数值增加
            ++count;
        else//如果不相同就减少,相互抵消
            --count;
    }
    
    if(check_more_than_half(v,result))
        return result;
    return 0x3f3f;
}
bool Solution::check_more_than_half(vector<int> &v,int num)
{
    int count=0;
    for(auto k:v)
    {
        if(k==num)
            ++count;
    }
    if(count<<1<v.size())
        return false;
    return true;
    
}
bool Solution::check_valid(vector<int> &v)
{
    if(v.empty()||v.size()<0)
        return false;
    return true;
}
int main()
{
    vector<int> v{6,1,1,6,2,6,3,6,6,5};
    Solution s;
    int t=s.more_half_num(v);
    if(t!=0x3f3f)
        cout<<t<<endl;
    return 0;
}

 三

  定义一个栈,先把数组的第一个元素入栈

  1. 如果下一个元素与栈顶元素相同,下一个元素入栈
  2. 否则,栈顶元素出栈
  3. 如果最后栈不为空,栈顶元素就是重复超过一半的数字(而且最后栈中的元素的个数就是此元素超过其它元素个数总和的数)
#include <iostream>
#include <stack>
#include <vector>
using namespace std;

class Solution
{
    public:
        int more_half_num(vector<int> &v);
};
int Solution::more_half_num(vector<int> &v)
{
    if(v.empty()||v.size()<0)
        return 0x3f3f;
        
    stack<int> s;
    s.push(v[0]);
    for(int i=1;i<v.size();++i)
    {
        if(!s.empty())
        {
            if(s.top()==v[i])
                s.push(v[i]);
            else
                s.pop();
        }
        else
            s.push(v[i]);
    }
    if(!s.empty())
        return s.top();
    return 0x3f3f;
}
int main()
{
    vector<int> v{1,2,3,6,6,6,6,6,5};
    Solution s;
    int t=s.more_half_num(v);
    if(t!=0x3f3f)
        cout<<t<<endl;
    return 0;
}

 

 

以上是关于数组中有一个数字出现次数超过数组长度一半,找出这个数字(用C语言解决)。要求时间复杂度尽量小。的主要内容,如果未能解决你的问题,请参考以下文章

数组中次数超过数组长度一半的数字

数组中出现次数超过数组长度一半的数字

数组中出现次数超过数组长度一半的值

数组中出现次数超过一半的数字

数组中出现次数超过一半的数字-剑指Offer

39 数组中出现次数超过一半的数字(时间效率)