Description

  For a given source string and a target string, you should output the first index(from 0) of target string in source string.If target does not exist in source, just return -1.

对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。  

Clarification

  Do I need to implement KMP Algorithm in a real interview?

  • Not necessary. When you meet this problem in a real interview, the interviewer may just want to test your basic implementation ability. But make sure you confirm with the interviewer first.

在面试中我是否需要实现KMP算法?

  • 不需要,当这种问题出现在面试中时,面试官很可能只是想要测试一下你的基础应用能力。当然你需要先跟面试官确认清楚要怎么实现这个题。

Example

  Example 1:

  Input:source = "source" , target = "target"

  Output:-1

  Explanation:If the source does not contain the target content, renturn -1.

  Example 2:

  Input:source = "abcdabcdefg" , target = " bcd"

  Output:1

  Explanation:If the source contains the target content, return the location where the target first appeared in the source.

Challenge

  O(n2) is acceptable. Can you implement an O(n) algorithm? (hint: KMP)

O(n2)的算法是可以接受的。如果你能用O(n)的算法做出来那更加好。(提示:KMP)

题解

  对于字符串查找问题,可使用双重 for 循环解决,效率更高的则为 KMP 算法。双重 for 循环的使用较有讲究,因为这里需要考虑目标字符串比源字符串短的可能。对目标字符串的循环肯定是必要的,所以可以优化的地方就在于如何访问源字符串了。简单直观的解法是利用源字符串的长度作为 for 循环的截止索引,这种方法需要处理源字符串中剩余长度不足以匹配目标字符串的情况,而更为高效的方案则为仅遍历源字符串中有可能和目标字符串匹配的部分索引。

实现

  Python:

 1 class Solution:
 2     def strStr(self, source, target):
 3         if source is None or target is None:
 4             return -1
 5 
 6         for i in range(len(source) - len(target) + 1):
 7             for j in range(len(target)):
 8                 if source[i + j] != target[j]:
 9                     break
10             else:  # no break
11                 return i
12         return -1

  C:

 1 int strStr(char* haystack, char* needle) {
 2     if (haystack == NULL || needle == NULL) return -1;
 3 
 4     const int len_h = strlen(haystack);
 5     const int len_n = strlen(needle);
 6     for (int i = 0; i < len_h - len_n + 1; i++) {
 7         int j = 0;
 8         for (; j < len_n; j++) {
 9             if (haystack[i+j] != needle[j]) {
10                 break;
11             }
12         }
13         if (j == len_n) return i;
14     }
15 
16     return -1;
17 }

  C++:

  

 1 class Solution {
 2 public:
 3     int strStr(string haystack, string needle) {
 4         if (haystack.empty() && needle.empty()) return 0;
 5         if (haystack.empty()) return -1;
 6         if (needle.empty()) return 0;
 7         // in case of overflow for negative
 8         if (haystack.size() < needle.size()) return -1;
 9 
10         for (int i = 0; i < haystack.size() - needle.size() + 1; i++) {
11             string::size_type j = 0;
12             for (; j < needle.size(); j++) {
13                 if (haystack[i + j] != needle[j]) break;
14             }
15             if (j == needle.size()) return i;
16         }
17         return -1;
18     }
19 }

  Java:

 1 public class Solution {
 2     public int strStr(String haystack, String needle) {
 3         if (haystack == null && needle == null) return 0;
 4         if (haystack == null) return -1;
 5         if (needle == null) return 0;
 6 
 7         for (int i = 0; i < haystack.length() - needle.length() + 1; i++) {
 8             int j = 0;
 9             for (; j < needle.length(); j++) {
10                 if (haystack.charAt(i+j) != needle.charAt(j)) break;
11             }
12             if (j == needle.length()) return i;
13         }
14 
15         return -1;
16     }
17 }

 

源码分析

  1. 边界检查:haystack(source)needle(target)有可能是空串。

  2. 边界检查之下标溢出:注意变量i的循环判断条件,如果用的是i < source.length()则在后面的source.charAt(i + j)时有可能溢出。
  3. 代码风格:
    1. 运算符==两边应加空格
    2. 变量名不要起s1、s2这类,要有意义,如target、source
    3. Java 代码的大括号一般在同一行右边,C++ 代码的大括号一般另起一行
    4. int i, j;`声明前有一行空格,是好的代码风格
  4. 是否在for的条件中声明i,j,这个视情况而定,如果需要在循环外再使用时,则须在外部初始化,否则没有这个必要。

  需要注意的是有些题目要求并不是返回索引,而是返回字符串,此时还需要调用相应语言的substring方法。Python3 中用range替换了xrange,Python2 中使用xrange效率略高一些。 另外需要注意的是 Python 代码中的else接的是for 而不是if, 其含义为no break, 属于比较 Pythonic 的用法。

复杂度分析:

  双重 for 循环,时间复杂度最坏情况下为O((n−m)∗m)。

posted on 2020-03-29 15:27  白日梦想家_G  阅读(156)  评论(0编辑  收藏  举报