1. 程式人生 > >藍橋杯 演算法訓練 ALGO-87 字串統計

藍橋杯 演算法訓練 ALGO-87 字串統計

演算法訓練 字串統計
時間限制: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演算法,在主串中搜索子串。區別在於,這裡的子串有很多,只要符合條件的子串,我們都要搜尋一遍。然後統計他們出現的次數,將出現次數最多的子串輸出。
思路:將子串按照長度不同分別遍歷,若主串長度為 n n ,則
  主串中長度大於等於 L

L 子串長度 n L + 1 n-L+1

  長度為k的的種類中有 n L + k n-L+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;
}