编程之美2.3——寻找水军(抵消法)

1.在数组中寻找出现次数超过一半的一个元素。

2.在数组中寻找出现次数超过1/4的三个元素。

【思路】

1)常规做法:先将数组排序,时间O(nlogn);再遍历一次,统计每个元素出现的次数,得到题目要求。

2)时间O(n)的做法:抵消法。对于第一题,每次抵消两个不同的数,剩下的数组主元素出现次数还是超过一半。即缩小题目规模的思想。

对于第二题,则每次抵消4个数,转化为规模较小的问题。

抵消两个数的代码很简单:

int findOverHalf(int *ID, int N){
    int ntimes=0;
    int candi;
    for(int i=0; i<N; i++){
        if(ntimes==0){
            candi=ID[i];
            ntimes=1;
        }
        else{
            if(candi==ID[i])
                ntimes++;
            else
                ntimes--;
        }
    }
    return candi;
}

抵消四个数比较麻烦,难写周全:

【other code】

struct candidate{
    int a,atimes;
    int b,btimes;
    int c,ctimes;
    void init(){
        atimes=0;
        btimes=0;
        ctimes=0;
    }
    bool istheSame(int num){
        if(a==num&&atimes!=0){atimes++; return false;}
        if(b==num&&btimes!=0){btimes++;return false;}
        if(c==num&&ctimes!=0){ctimes++;return false;}

        if(atimes==0){a=num;atimes++; return false;}
        if(btimes==0){b=num;btimes++;return false;}
        if(ctimes==0){c=num;ctimes++;return false;}
        return true;
    }
    void del(){
        atimes--;
        btimes--;
        ctimes--;
    }
}person;

candidate findOverQuarters(int *ID, int N){
    person.init();
    for(int i=0; i<N; i++){
        if(person.istheSame(ID[i]))
            person.del();
    }
    return person;
}
int main(){
    int ID[]={1,1,2,2,2,3,3,3,4,4,4};
    person=findOverQuarters(ID,11);
    cout<<person.a<<person.b<<person.c<<endl;
    system("pause");
    return 0;
}

测试运行代码是4,2,3.

【总结】

要学习人家代码的封装方法。

原文地址:https://www.cnblogs.com/ketchups-notes/p/4502817.html