算法要求:長字符串的寬度最長是500個字符。
輸入:一個長字符串,寬度不能超過500個字符,一個短字符串
輸出:短字符串在長字符串中出現的次數的後四位,不足四位左邊填充零。
舉例來說:在“wweell”字符串中找“wel”出現的次數,可以匹配到8次,應輸出0008,每個匹配子串的索引序列分別如下
0,2,4
0,2,5
0,3,4
0,3,5
1,2,4
1,2,5
1,3,4
1,3,5
算法分析:能夠想到的最直觀的做法就是先在長串裏找出短串的第一個字符所在的索引,組成一個首字符索引數組,然後分別處理每個首字符索引到長串末尾的子串。處理每個子串最蠻力的辦法當然是遞歸,遞歸有幾點要說明。
1、遞歸的每次必須要有前進的趨勢,所以每次遞歸操作,要把當前掃描的長串的索引加一,以便下面的遞歸使用不同的上下文。
2、遞歸必須有明確的終止,當短串匹配完畢,應該是到達遞歸的最底層了,要遞增一次匹配次數,並且return,爲了調試方便,我們還打印出來了匹配短串在長串中的索引序列。
3、爲了儘可能多的匹配結果,在我們匹配到一個字符的時候,除了把匹配字符加一,掃描索引加一繼續遞歸外,我們還要進行一次匹配字符不加一,掃描索引加一繼續遞歸。
4、當掃描到字串的最後一個字符時,一次匹配已經產生了,但你還要看看長串有沒有掃描完,然後繼續遞歸匹配子串的最後一個字符,以找到更多的匹配。
以上思路的實現代碼很短,如下
internal class Program2 {
private static string math = "welcome to cnblogs";
private static readonly string[] arr = new string[math.Length];
private static int ret;
private static string test_input = "wweellccoommee to cnblogs";
private static void Main() {
ret = 0;
var windex = new List<int>();
for (int i = 0; i < test_input.Length; i++) {
if (test_input[i] == 'w')
windex.Add(i);
}
windex.ForEach(index => {
arr[0] = index.ToString();
Handle(1, index + 1);
});
string strRet = ret.ToString();
if (strRet.Length > 4)
strRet = strRet.Substring(strRet.Length - 4, 4);
if (strRet.Length < 4) strRet = strRet.PadLeft(4, '0');
Console.WriteLine(strRet);
Console.ReadKey();
}
private static void Handle(int k, int start) {
for (int i = start; i < test_input.Length; i++) {
if (k == math.Length - 1 && test_input[i] == math[k]) {
arr[k] = i.ToString();
Console.WriteLine(string.Join(",", arr));
++ret;
if (i < test_input.Length - 1)
Handle(k, ++i);
return;
}
if (test_input[i] == math[k]) {
arr[k] = i.ToString();
Handle(++k, i);
Handle(--k, ++i);
--i;
break;
}
}
}
}
大家有什麼好的思路,給表演一把,另外這個是code jam 2009的一個入圍題目,大家有興趣可以去玩玩。