程序分析
计算字符串中子串出现的次数,一种直观的方法是遍历整个字符串,在每个位置检查子串是否匹配。另一种方法是利用字符串匹配算法来优化搜索过程,减少时间复杂度。
方法一:暴力法
解题思路:
- 在主串中依次遍历每个位置,以该位置为起点,检查是否存在与子串相同的子串。
- 比较简单直观,但时间复杂度较高。
实现代码:
#include <stdio.h>
#include <string.h>int countSubstring(char *str, char *sub) {int count = 0;int len_str = strlen(str);int len_sub = strlen(sub);for (int i = 0; i <= len_str - len_sub; i++) {int j;for (j = 0; j < len_sub; j++) {if (str[i + j] != sub[j])break;}if (j == len_sub)count++;}return count;
}int main() {char str[] = "ababababa";char sub[] = "aba";int result = countSubstring(str, sub);printf("Number of occurrences: %d\n", result);return 0;
}
优缺点:
- 优点:实现简单,容易理解。
- 缺点:时间复杂度高,O(n*m),其中n为主串长度,m为子串长度。
方法二:KMP算法
解题思路:
- KMP算法利用了子串内部的信息,通过预处理生成一个部分匹配表,然后根据部分匹配表进行匹配,减少了不必要的比较。
- 预处理过程时间复杂度为O(m),匹配过程时间复杂度为O(n+m),总体时间复杂度为O(n+m),其中n为主串长度,m为子串长度。
实现代码:
#include <stdio.h>
#include <string.h>void buildTable(char *sub, int *table) {int len = strlen(sub);table[0] = 0;int j = 0;for (int i = 1; i < len; i++) {while (j > 0 && sub[i] != sub[j])j = table[j - 1];if (sub[i] == sub[j])j++;table[i] = j;}
}int countSubstringKMP(char *str, char *sub) {int count = 0;int len_str = strlen(str);int len_sub = strlen(sub);int table[len_sub];buildTable(sub, table);int j = 0;for (int i = 0; i < len_str; i++) {while (j > 0 && str[i] != sub[j])j = table[j - 1];if (str[i] == sub[j])j++;if (j == len_sub) {count++;j = table[j - 1];}}return count;
}int main() {char str[] = "ababababa";char sub[] = "aba";int result = countSubstringKMP(str, sub);printf("Number of occurrences: %d\n", result);return 0;
}
优缺点:
- 优点:时间复杂度较低,O(n+m),其中n为主串长度,m为子串长度。
- 缺点:实现相对复杂,需要了解和实现KMP算法。
方法三:Boyer-Moore算法
解题思路:
实现代码(Boyer-Moore算法的实现相对复杂,这里不做展示)。
优缺点:
- 优点:性能较好,适用于长主串和短子串的情况。
- 缺点:实现复杂,需要深入理解算法原理。