13 字符串查找
原题网址: http://www.lintcode.com/zh-cn/problem/strstr/#
对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1
。
说明
在面试中我是否需要实现KMP算法?
- 不需要,当这种问题出现在面试中时,面试官很可能只是想要测试一下你的基础应用能力。当然你需要先跟面试官确认清楚要怎么实现这个题。
样例
如果 source = "source"
和 target = "target"
,返回 -1
。
如果 source = "abcdabcdefg"
和 target = "bcd"
,返回 1
。
挑战
O(n2)的算法是可以接受的。如果你能用O(n)的算法做出来那更加好。(提示:KMP)
方法一:遍历source,找到第一个与target[0]相同的字符source[j],然后按照target大小依次循环对比,若有一处字符不等,跳出当前循环继续寻找,否则返回j。
1 class Solution {
2 public:
3 /*
4 * @param source: source string to be scanned.
5 * @param target: target string containing the sequence of characters to match
6 * @return: a index to the first occurrence of target in source, or -1 if target is not part of source.
7 */
8 int strStr(const char *source, const char *target) {
9 // write your code here
10 if (source==NULL||target==NULL)
11 {
12 return -1;
13 }
14 int sizes=strlen(source);
15 int sizet=strlen(target);
16 if (sizet==0)
17 {
18 return 0;
19 }
20 if (sizet>sizes)
21 {
22 return -1;
23 }
24 for (int j=0;j<sizes;j++)
25 {
26 if (target[0]==source[j])
27 {
28 int tempIndex=j;//j还要继续向后移动对比,可以通过临时变量来完成;
29 bool flag=true;
30 if ((sizes-j)<sizet) //j开始source中剩余字符少于sizet,返回-1;
31 {
32 return -1;
33 }
34 int i=1;
35 while(i<sizet)
36 {
37 if (target[i++]!=source[++tempIndex])
38 {
39 flag=false;
40 break;
41 }
42 }
43 if (flag)
44 {
45 return j;
46 }
47
48 }
49
50 }
51 return -1;
52 }
53 };
方法2,KMP
参考:
1 https://www.cnblogs.com/libaoquan/p/6980182.html
2 https://www.cnblogs.com/Smallhui/p/5540855.html
3 史上最浅显易懂的KMP算法讲解:字符串匹配算法 多看几遍,注意代码中的next数组存储的是前后缀公共长度减一
这个KMP算法真的是看了一上午加一下午才勉强实现出来,脑仁疼……
1 class Solution {
2 public:
3 /*
4 * @param source: source string to be scanned.
5 * @param target: target string containing the sequence of characters to match
6 * @return: a index to the first occurrence of target in source, or -1 if target is not part of source.
7 */
8
9
10 int strStr(const char *source, const char *target) {
11 // write your code here
12 if (source==NULL||target==NULL)
13 {
14 return -1;
15 }
16 int sizes=strlen(source);
17 int sizet=strlen(target);
18 if (sizet==0)
19 {
20 return 0;
21 }
22 if (sizet>sizes)
23 {
24 return -1;
25 }
26 int *next=getNext(target);
27
28 int j=0;
29 for (int i=0;i<sizes;i++)
30 {
31 while(j>0&&source[i]!=target[j]) //j应该大于0,等于0的话前面没有子串也就不存在公共前后缀,不存在进入while循环的必要;
32 {
33 j=next[j]+1;
34 }
35 if (source[i]==target[j])
36 {
37 j++;
38 }
39 if (j==sizet)
40 {
41 return i-j+1;
42
43 }
44 }
45 return -1;
46 }
47
48 int *getNext(const char *s)
49 {
50 int len=strlen(s);
51 int *next=new int[len]; //存储最长公共前后缀长度减一,所以next[i]为前缀的最后一个元素的索引,next[i]+1为前缀后面第一个元素的索引;
52 next[0]=-1;
53 int k;
54
55 for (int i=1;i<len;i++)
56 {
57 k=next[i-1];
58 while(k>=0&&s[i]!=s[k+1])
59 {
60 k=next[k];
61 }
62 if (s[i]==s[k+1])
63 {
64 next[i]=next[i-1]+1;
65 }
66 else
67 {
68 next[i]=-1;
69 }
70 }
71
72 return next;
73 }
74 };