每天学习亿点点day 17: Boyer-Moore 算法和找第K大的数

Posted Tonarinototoro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每天学习亿点点day 17: Boyer-Moore 算法和找第K大的数相关的知识,希望对你有一定的参考价值。

1. Boyer-Moore yyds

这个算法比KMP快了非常多.

当我们把模式串跟文本串匹配的时候最核心的算法部分就是在匹配失败后如何移动模式串去避免一次只移动一个字符所带来的额外时间开销

为了解决这个问题,本算法的主要的思想就是使用了两个并行的启发式算法:

a.坏字符算法

 

 匹配失败的a和b,文本串里的b在模式串里出现了那么找到最右边的b然后对齐

 

 

 

 匹配失败的a和b,文本串里的b在模式串里没有出现,那么直接把a左边的内容全部移到b右边来

b. 好后缀算法

实际上我们在这个部分能看到KMP的身影

 

 这里就是BM的改进之处,在之前的模式串里寻找已经匹配的全部

 

 

 

 这个手段和KMP的想法是具有一致性的,就是直接从头找看有没有已经匹配部分子串重复

可能会有人问(你说的有人不会是你自己吧?).

第二种情况必须要是要从0开始找v嘛?我们可以假设在中间某个位置找到v但是这个时候由于v左边和模式串的末尾地方一样是不匹配的,即使找到了这种位置也没有价值,因为你就算移过来也还是不匹配,那何必移过来。

两个并行算法每次需要移动的时候看这两个谁动的多.

 代码如下:

#include<stdio.h>
#include<string.h>
#define MAX_CHAR 256
#define SIZE 256
#define MAX(x, y) (x)>(y)?(x):(y)

void BoyMoore(char * pattern, int m, char* text, int n);

int main()
{
    char text[256], pattern[256];
    while(1)
    {
        scanf("%s%s",text,pattern);
        if(text==0||pattern==0) break;
        
        BoyMoore(pattern,strlen(pattern),text,strlen(text));
        printf("\\n");
        
    }
    return 0;
}

void print(int * array, int n, char* arrayName)
{
    int i;
    printf("%s: ",arrayName);
    for(i=0;i<n;i++)
    {
        printf("%d ", array[i]);
    }
    printf("\\n");
}
void PreBmBc(char * pattern,int m,int bmBc[])
{
    int i;
    for(i=0;i<MAX_CHAR;i++)
    {
        bmBc[i]=m;
    }
    for(i=0;i<m-1;i++)
    {
        bmBc[pattern[i]]=m-1-i;
    }
}
void suffix_old(char * pattern, int m, int suff[])
{
    int i,j;
    suff[m-1]=m;
    for(i=m-2;i>=0;i--)
    {
        j=i;
        while(j>=0&&pattern[j]==pattern[m-1-i+j]) j--;
        suff[i]=i-j;
    }
}
void suffix(char* pattern, int m, int suff[])
{
    int f,g,i;
    suff[m-1]=m;
    g=m-1;
    for(i=m-2;i>=0;--i)
    {
        if(i>g&&suff[i+m-1-f]<i-g)
        suff[i]=suff[i+m-1-f];
        else
        {
            if(i<g)
            g=i;
            f=i;
            while(g>=0&&pattern[g]==pattern[g+m-1-f])
            --g;
            suff[i]=f-g;
        }
    }
}
void PreBmGs(char *pattern,int m, int bmGs[])
{
    int i,j;
    int suff[SIZE];
    
    suffix(pattern,m,suff);
    
    for(i=0;i<m;i++)
    {
        bmGs[i]=m;
    }
    
    j=0;
    for(i=m-1;i>=0;i--)
    {
        if(suff[i]==i+1)
        {
            for(;j<m-1-i;j++)
            {
                if(bmGs[j]==m)
                bmGs[j]=m-1-i;
            }
        }
    }
    
    for(i=0;i<=m-2;i++)
    {
        bmGs[m-1-suff[i]]=m-1-i;
    }
    
    
    
}
void BoyMoore(char * pattern, int m, char* text, int n)
{
    int i,j, bmBc[MAX_CHAR], bmGs[SIZE];
    PreBmBc(pattern,m,bmBc);
    PreBmGs(pattern,m,bmGs);
    j=0;
    while(j<=n-m)
    {
        for(i=m-1;i>=0&&pattern[i]==text[i+j];i--);
        if(i<0)
        {
            printf("find it at position %d\\n", j);
            j+=bmGs[0];
            return;
        }
        else
        {
            j+=MAX(bmBc[text[i+j]]-m+1+i,bmGs[i]);
        }
    }
    printf("No find!");
} 

 

 

2.找第K大的数

其实思路很简单,利用快排的思想在pivot最后归位的时候判断pivot所在的位置和K的比较,一般用的填坑法的话,pivot最后就是在l处,此时如果l<K则我们到l的右边区间去找,如果l>K, 则我们到左边区间去找.  递归找就完事

如果有重复的数字那么我们就把初始数组处理一下,将不需要的重复的数字剔除掉再使用该方法即可。

代码如下:

#include<iostream>
#include <algorithm>
#include<vector>
using namespace std;
template<typename T>
void Swap(T* A,int l,int r)
{
    T tmp=A[l];
    A[l]=A[r];
    A[r]=tmp;
}
template<typename T>
void QS(T * A,int left,int right)
{
    int l=left,r=right;
    T pivot=A[left];
    if(l>=r)
    return;
    while(l<r)
    {
        while(A[r]>=pivot&&l<r)
        r--;
        A[l]=A[r];
        while(A[l]<pivot&&l<r)
        l++;
        A[r]=A[l];
        
        
    }
    A[l]=pivot;
    QS(A,left,l);
    QS(A,l+1,right);
}
template<typename T>
T* findKBig(T * A,int left,int right,int K)
{
    int l=left,r=right;
    T pivot=A[left];
    while(l<r)
    {
        while(A[r]>=pivot&&l<r)
        r--;
        A[l]=A[r];
        while(A[l]<pivot&&l<r)
        l++;
        A[r]=A[l];
        
        
    }
    A[l]=pivot;
    if(l==K)
    {
    T* anwser=new T;
    *anwser=A[l];
    return anwser;
    }
    else if(l<K)
    {
        return findKBig(A,l+1,right,K);
    }
    else //l>K
    {
        return findKBig(A,left,l,K);
    }
    
}

bool ExistsOrnot(const vector<float>& p,const float& lookat)
{
    for(int i=0;i<p.size();i++)
    {
        if(p[i]==lookat)
        return true;
    }
    return false;
}
int main()
{
    float C[10]={0.3,0.3,0.3,-9.990,22,3,1,-3,9,10};
    vector<float> alreadyKnow;
    int index=0;
    for (int i=0;i<10;i++)
    {
        float insertone=C[i];
        if(ExistsOrnot(alreadyKnow,insertone))
        ;
        else
        alreadyKnow.push_back(insertone);
    }
    float *Creal=new float[alreadyKnow.size()];
    std::copy(alreadyKnow.begin(),alreadyKnow.end(),Creal);
    
    
    QS<float>(Creal,0,alreadyKnow.size()-1);
    for(int i=0;i<alreadyKnow.size();i++)
    cout<<Creal[i]<<endl;
    //the 3 big 
    int k;
    cout<<"tell me the k-th big number you want to find?"<<endl;
    cin>>k;
    cin.clear();
    while(k<1||k>alreadyKnow.size())
    {
        cout<<"you gotta to be kidding me?? constrain your number into 1-"<<alreadyKnow.size();
        cout<<endl;
        cin>>k;
        cin.clear();
    }
    
    
    auto p=findKBig<float>(Creal,0,alreadyKnow.size()-1,k-1);
    if(p!=NULL)
    cout<<"the "<<k<<"big number is "<<*p;
    delete p;
}

 

以上是关于每天学习亿点点day 17: Boyer-Moore 算法和找第K大的数的主要内容,如果未能解决你的问题,请参考以下文章

每天学习亿点点day 13: UE4 渲染pipeline

每天学习亿点点day 5,6: Actor, UobjectBase, component的源码剖析

每天学习亿点点day 16: 脚部IKBone的做法

每天学习亿点点系列——重温单链表

每天学习亿点点系列——单链表OJ题

每天学习亿点点系列——OJ203题:移除链表元素