藍橋杯 演算法訓練 ALGO-87 字串統計
阿新 • • 發佈:2018-12-21
演算法訓練 字串統計
時間限制:1.0s 記憶體限制:512.0MB
問題描述
給定一個長度為n的字串S,還有一個數字L,統計長度大於等於L的出現次數最多的子串(不同的出現可以相交),如果有多個,輸出最長的,如果仍然有多個,輸出第一次出現最早的。
輸入格式
第一行一個數字L。
第二行是字串S。
L大於0,且不超過S的長度。
輸出格式
一行,題目要求的字串。
輸入樣例1:
4
bbaabbaaaaa
輸出樣例1:
bbaa
輸入樣例2:
2
bbaabbaaaaa
輸出樣例2:
aa
資料規模和約定
n<=60
S中所有字元都是小寫英文字母。
提示
列舉所有可能的子串,統計出現次數,找出符合條件的那個
分析:本題類似KMP演算法,在主串中搜索子串。區別在於,這裡的子串有很多,只要符合條件的子串,我們都要搜尋一遍。然後統計他們出現的次數,將出現次數最多的子串輸出。
思路:將子串按照長度不同分別遍歷,若主串長度為
,則
主串中長度大於等於
的子串長度 有
種,
長度為k的的種類中有
個子串,
分別判斷這些子串的重複次數。遍歷時從前向後,以滿足題意輸出第一次出現最早的。
這裡可以優化一下,如果發現重複的子串,可以把後面的該子串置空,下次遍歷到它的時候可以直接跳過,減少操作次數。
遍歷完長度為k的子串,保留出現次數最多的子串和其出現次數,在全部子串列舉結束後,對不同長度子串中出現次數最多的子串再進行比較,保留所有子串中出現次數最多的子串。這裡從子串長度最長的開始,以滿足題意輸出最長的。
#include <iostream>
#include <cstring>
using namespace std;
string fun(string S, int L)
{
int len = S.length();
string *aaa = new string[len-L+1];
int *nnn = new int[len-L+1], bbb = len-L;
for(int k = 1, l = 0; k > L-len; k--, l++)
{
int num =len - L + k; //子串個數
string *temp = new string[num]; //建立子串
int *n = new int[num], result = 0; //計算重複個數
//分離子串
for(int i = 0; i < num; i++)
{
temp[i].insert( 0, S, i, L+l); //把string S中第i個開始長度為L的字串拷貝給temp[i]
n[i] = 0; //初始化重複個數為0
}
//計算每個子串重複次數
for(int i = 0; i < num; i++)
{
if(temp[i] != "") //不為空就計算重複數
for(int j = i + 1; j < num; j++)
{
if(temp[j] != "" && temp[i] == temp[j]) //如果重複
{
n[i]++;
temp[j] = ""; //前面已經有相同的不需比較
}
}
}
//比較,第幾個子串重複數最多
int a = n[0];
for(int i = 1; i < num; i++)
{
if(a < n[i])
{
a = n[i];
result = i;
}
}
nnn[l] = a;
// aaa[l] = temp[result];
aaa[l].insert( 0, temp[result]);
delete n;
delete []temp;
}
//最後的篩選
for(int l = len-L, ccc = nnn[len-L]; l >= 0; l--)
{
if(ccc < nnn[l])
{
ccc = nnn[l];
bbb = l;
}
}
//返回該子串的內容
return aaa[bbb];
}
int main()
{
int L;
cin >> L;
string S;
cin >> S;
cout << fun(S, L) << endl;
return 0;
}