2015阿里筆試題

題目:給定兩個字符串,求兩個字符串最長連續字符串的數目。比如:query爲“acbac”,text爲“acaccbabb”,那麼最長的連續子序列爲“cba”,輸出3。請注意程序效率。


題目解析:

一開始看到這個題,可能會想到最長公共子序列的方法,其實是不對的。因爲這裏要求必須連續,而最長公共子序列爲不連續的。狀態轉移方程不對。


方案一:暴力求法

可以分別將query的第0位到第n-1位爲起始字符串,在text中遍歷,尋找最長的子串。

時間複雜度較高O(m*n).


方案二:動態規劃

這裏很不容易想到動態規劃,dp[i][j]這麼和dp[i-1][j]/dp[i][j-1]/dp[i-1][j-1]尋找關係?不能隨便刪掉一個字符。

這裏就需要思維的擴展了,當j+1時,dp[i][j+1] 和dp[i][j]什麼關係呢?也就是j序列多了一個字符,要麼不影響最大長度,dp[i][j+1] = dp[i][j]; 要麼第j+1個字符結尾的長度變大。那麼就需要以j+1結尾的字符,在0.....i之間遍歷。找到最大長度。

根據這個思路,就能寫出動態規劃算法。

#include <iostream>

using namespace std;

int TailLengh(string test,int pos1,string goal,int pos2){
    int i = pos1,j = pos2,end = j;
    int mark,temp = 0;
    int max = 0;

    while(i>=0){
        if(test[i] == goal[j]){
            temp = 0;
            mark = i;
            while(i>=0 && j >=0 && test[i--] == goal[j--])
                ++temp;
            if(j<0)
                return temp;
            if(temp > max)
                max = temp;
            i = mark;
            j = end;
        }
        --i;
    }
    return max;
}


int FindLongest(string test,string goal){
    if(test.size() == 0 || goal.size() == 0)
        return 0;
    int len_t = test.size();
    int len_g = goal.size();
    int **dp = new int*[len_t+1];
    for(int i =0;i <= len_t;i++)
        dp[i] = new int[len_g+1];

    for(int i = 0;i <= len_t;i++)
        dp[i][0] = 0;
    for(int j = 0;j <= len_g;j++)
        dp[0][j] = 0;

    for(int i = 1;i <= len_t;i++){
        for(int j = 1;j <= len_g;j++){
            int temp = TailLengh(test,i-1,goal,j-1);
            dp[i][j] = temp > dp[i][j-1] ? temp : dp[i][j-1];
        }
    }
    int res = dp[len_t][len_g];
    for(int i = 0;i <= len_t;i++)
        delete []dp[i];
    delete []dp;
    return res;
}



int main()
{
    string test = "sdfasdfadsffortqest";
    string goal = "ccsdfasdfadsffortquery";
    cout << FindLongest(test,goal) << endl;
    return 0;
}








發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章