Open azl397985856 opened 2 years ago
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) == 0:
return 0
if len(haystack) < len(needle):
return -1
# RK
hash_val = 0
target = 0
for i in range(len(haystack)):
if i < len(needle):
hash_val = hash_val*26 + ord(haystack[i]) - ord('a')
target = target*26 + ord(needle[i]) - ord('a')
else:
tmp = ord(haystack[i]) - ord('a')
hash_val = 26*(hash_val - ( ord(haystack[i-len(needle)]) - ord('a') )*(26**(len(needle) - 1))) + tmp
if i>= len(needle)-1 and hash_val == target:
return i - len(needle) + 1
return 0 if hash_val == target else -1
# BF
for i in range(len(haystack) - len(needle) + 1):
if haystack[i:i+len(needle)] == needle:
return i
return -1
title: "Day 83" date: 2021-12-01T15:26:54+08:00 tags: ["Leetcode", "c++", "KMP"] categories: ["91-day-algorithm"] draft: true
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
示例 1:
输入:haystack = "hello", needle = "ll"
输出:2
示例 2:
输入:haystack = "aaaaa", needle = "bba"
输出:-1
示例 3:
输入:haystack = "", needle = ""
输出:0
提示:
0 <= haystack.length, needle.length <= 5 * 104
haystack 和 needle 仅由小写英文字符组成
- 1、经典一看,发现是KMP算法的喜悦,将 haystack 替换为 s 主串,needle替换为模式串。
class Solution {
public:
int strStr(string s, string p) {
int n = s.size(), m = p.size();
if(m == 0) return 0;
s.insert(s.begin(), ' ');
p.insert(p.begin(), ' ');
vector<int> next(m + 1);
for(int i = 2, j = 0; i <= m; i++) {
while(j && p[i] != p[j + 1]) j = next[j];
if(p[i] == p[j + 1]) j++;
next[i] = j;
}
for(int i = 1, j = 0; i <= n; i++) {
while(j && s[i] != p[j + 1]) j = next[j];
if(s[i] == p[j + 1]) j++;
if(j == m) return i - m;
}
return -1;
}
};
使用滚动哈希,其中哈希的算法可以使用位运算来计算。
class Solution { public int strStr(String haystack, String needle) { //使用RK(滚动哈希) 自己设计一个哈希算法 来判读needle if(needle.length()==0)return 0; int n_val = 0, h_val = 0; for(int i=0;i<needle.length();i++){ n_val ^= needle.charAt(i); } int size = needle.length(); boolean istrue = true; for(int i=0;i<haystack.length();i++){ h_val ^= haystack.charAt(i); if(i<size&&istrue){ if(i==size-1){ istrue = false; if(h_val==n_val&&haystack.substring(i-size+1,i+1).equals(needle)){ return i-size+1; } } continue; } h_val ^=haystack.charAt(i-size); if(h_val==n_val&&haystack.substring(i-size+1,i+1).equals(needle)){ return i-size+1; } } return -1; } }
时间复杂度:O(n)
空间复杂度:O(1)
思路: brute force, could be improved with KMP algorithm
class Solution {
public int strStr(String haystack, String needle) {
if (needle.length() == 0) return 0;
if (haystack.length() == 0) return -1;
int m = haystack.length(), n = needle.length();
for (int i = 0; i <= m - n; i++) {
for (int j = 0; j < n && haystack.charAt(i+j) == needle.charAt(j); j++) {
if (j == n - 1) {
return i;
}
}
}
return -1;
}
}
Time Complexity: O(n*m), n and m are the length of two input strings Space Complexity: O(1)
https://leetcode.com/problems/implement-strstr/
Sliding window
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if(n < m){
return -1;
}
if(m == 0){
return 0;
}
for(int i = 0; i <= n - m; i++){
if(isValid(haystack, i, needle, m)){
return i;
}
}
return -1;
}
private boolean isValid(String haystack, int start, String needle, int n){
for(int i = 0; i < n; i++){
if(haystack.charAt(start + i) != needle.charAt(i)){
return false;
}
}
return true;
}
}
Rolling hash
class Solution {
// hashcode = char[i]*31^n-1 + char[i+1]*31^n-2 + ... + char[n-1]*31^0;
int prime = 31;
int base = 1000000;
int power = 1;
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if (n < m) {
return -1;
}
if (m == 0) {
return 0;
}
for(int i = 0; i < m; i++){
power = (power * prime) % base;
}
int hash1 = initHash(haystack, m);
int hash2 = initHash(needle, m);
if (hash1 == hash2 && isEqual(haystack, 0, needle)) {
return 0;
}
for (int i = 1; i <= n - m; i++) {
hash1 = recalHash(haystack, i - 1, i + m - 1, hash1, m);
if (hash1 == hash2 && isEqual(haystack, i, needle)) {
return i;
}
}
return -1;
}
private boolean isEqual(String haystack, int startIndex, String needle) {
for (int i = 0; i < needle.length(); i++) {
if (haystack.charAt(startIndex + i) != needle.charAt(i)) {
return false;
}
}
return true;
}
private int recalHash(String text, int oldIndex, int newIndex, int oldHash, int len) {
int hash = (oldHash * prime + text.charAt(newIndex)) % base; // add new char first
hash = (hash - text.charAt(oldIndex) * power) % base; // remove old char later (use power)
if(hash < 0) {
hash += base;
}
return hash;
}
private int initHash(String text, int m) {
int hash = 0;
for (int i = 0; i < m; i++) {
hash = (hash * prime + text.charAt(i)) % base;
}
return hash;
}
}
RK:
class Solution {
public int strStr(String haystack, String needle) {
int hLen = haystack.length();
int nLen = needle.length();
if(hLen<nLen)return -1;
int targetHash = hash(needle,0,nLen-1);
int curHash = 0;
for(int i=0;i<=hLen-nLen;i++){
int end = i + nLen - 1;
if(i==0){
curHash = hash(haystack,0,end);
}else {
curHash += (haystack.charAt(end) - haystack.charAt(i-1));
}
if(curHash == targetHash && haystack.substring(i,end+1).equals(needle)){
return i;
}
}
return -1;
}
int hash(String str,int start,int end){
int ret = 0;
for(int i=start;i<=end;i++){
ret+=(str.charAt(i) - 'a');
}
return ret;
}
}
BF:
class Solution {
public int strStr(String haystack, String needle) {
if(needle == null || needle.length() == 0)return 0;
int hLen = haystack.length();
int nLen = needle.length();
if(hLen<nLen)return -1;
for(int i=0;i<=hLen - nLen;i++){
int k = 0;
for(int j=0;j<nLen;j++){
if(haystack.charAt(i+j) == needle.charAt(j)){
k++;
}else {
break;
}
}
if(k == nLen)return i;
}
return -1;
}
}
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
const strStr = function(haystack, needle) {
if (haystack == null || needle == null) return -1;
const m = needle.length;
if (m === 0) return 0;
const MOD = 1e7 + 7;
const BASE = 31;
const maxBase = getMaxBase(m);
const needleCode = getHashCode(needle);
let hashCode = 0;
for (let i = 0; i < haystack.length; i++) {
hashCode = (hashCode * BASE + haystack.charCodeAt(i)) % MOD; // abc + d
if (i < m - 1) continue; // no need to check if less than needle length
if (i >= m) { // abcd - a, exceed needle length, remove left most char
hashCode = (hashCode - (haystack.charCodeAt(i - m) * maxBase)) % MOD;
if (hashCode < 0) hashCode += MOD; // in case hash turns negative from subtraction above
}
// double check the string match
if (hashCode === needleCode && haystack.slice(i - m + 1, i + 1) === needle) return i - m + 1;
}
return -1;
function getMaxBase(len) {
let maxBase = 1;
for (let i = 0; i < len; i++) {
maxBase = (maxBase * BASE) % MOD; // 31^m
}
return maxBase;
}
function getHashCode(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = (hash * BASE + str.charCodeAt(i)) % MOD;
}
return hash;
}
};
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) == 0:
return 0
for i in range(len(haystack) - len(needle) + 1):
if haystack[i: i + len(needle)] == needle:
return i
return -1
class Solution:
def strStr(self, haystack, needle):
if needle == "":
return 0
for i in range(len(haystack)-len(needle)+1):
for j in range(len(needle)):
if haystack[i+j] != needle[j]:
break
if j == len(needle)-1:
return i
return -1
Time: O(m*n)
Space: O(1)
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
for (int i = 0; i + m <= n; i++) {
boolean flag = true;
for (int j = 0; j < m; j++) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
return -1;
}
}
时间复杂度: O(m*n)
空间复杂度: O(1)
class Solution {
public int strStr(String haystack, String needle) {
int len_h = haystack.length();
int len_n = needle.length();
if (len_n == 0) {
return 0;
}
if (len_n > len_h) {
return -1;
}
for (int i = 0; i < len_h - len_n; i++) {
if (haystack.substring(i, i + len_n).equals(needle)) {
return i;
}
}
return -1;
}
}
Time: O(m*n)
Space: O(1)
class Solution {
public int strStr(String haystack, String needle) {
if(needle.length() == 0) return 0;
if(haystack.length() == 0) return -1;
for(int i = 0; i <= haystack.length() - needle.length(); i++){
int j = 0;
for(;j < needle.length();j++){
if(haystack.charAt(i + j) != needle.charAt(j)){
break;
}
}
if(j == needle.length())return i;
}
return -1;
}
}
class Solution {
public int strStr(String haystack, String needle) {
int n = needle.length();
if(n == 0) return 0;
int h = haystack.length();
char[] hay = haystack.toCharArray();
char[] ne = needle.toCharArray();
// 生成next数组 最长相同前后缀问题
int[] next = new int[n] ;
for(int l = 0, r = 1; r < n;) {
// l 和 r 不同 找l 前一个元素 对应的最长相同前后缀 转到该元素处的下一个来比较
// 如abcabcabf 到了abcabf != abcabc f应该转到第一个c处来和长串比较 但是 abc != abf 因此再次回退到0
while(l > 0 && ne[l] != ne[r]) l = next[l - 1];
if(ne[l] == ne[r]) l++;
next[r] = l; // 如果退到0 位置 直接填入就好 否则 应该比较的是l的下一个位置 因此先把l++
r++;
}
for(int i = 0, j = 0; i < h;) {
// 不相等 转到前一位的最长公共子串的下一位
// 如 issip 到了p 不相等 应该转到和s 比较 因为i是一样的
while(j > 0 && hay[i] != ne[j]) j = next[j - 1];
if(hay[i] == ne[j]) j++; // 匹配上了 子串指针后移一位
if(j == n) return i - n + 1; // 整个子串needle匹配上了 ne[n-1] 都相等了 此时j++ 后等于n
i ++;
}
return -1;
}
}
字符串hash比较简单 就不写了
https://leetcode-cn.com/problems/implement-strstr/
1.BF
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if len(needle) ==0:
return 0
for i in range(len(haystack)-len(needle) +1):
if haystack[i:i+len(needle)] == needle:
return i
return -1
时间复杂度:O((m-n)*n) 空间复杂度:O(1)
2.RF f(T[s..s + m]) = T[s] 10 ^ (m - 1) + T[s + 1] 10 ^ (m - 2) ... + T[s + m - 1] f(T[s+1..s + m]) = T[s+1] 10 ^ (m - 1) + T[s + 2] 10 ^ (m - 2) ... + T[s + m] = (f(T[s..s + m]) - T[s] 10 ^ (m - 1)) 10 + T[s + m ]
def strStr(self, haystack: str, needle: str) -> int:
# Robin-Krap (RK)算法
count = 0
hay_length = len(haystack)
nee_length = len(needle)
pathash = hash(needle)
for i in range(hay_length-nee_length+1):
strhash = hash(haystack[i:i+nee_length])
# 使用hash值判断代替字符的遍历判断
if strhash != pathash:
continue
else:
for j in range(nee_length):
if haystack[i+j] != needle[j]:
break
else:
count += 1
if count == nee_length:
return i
if count != nee_length:
return -1
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
for i in range(len(haystack) - len(needle) + 1):
if haystack[i: i + len(needle)] == needle:
return i
return -1
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
# for i in range (len(haystack) - len(needle) + 1):
# if haystack[i:len(needle) + i] == needle:
# return i
# return -1
if needle in haystack:
return haystack.index(needle)
return -1
class Solution {
public:
int strStr(string s, string p) {
int n = s.size(), m = p.size();
for(int i = 0; i <= n - m; i++){
int j = i, k = 0;
while(k < m and s[j] == p[k]){
j++;
k++;
}
if(k == m) return i;
}
return -1;
}
};
/**
C++ Code:
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.empty()) {
return 0;
}
int lenh = haystack.length();
int lenn = needle.length();
if (lenh < lenn) {
return -1;
}
for (int i = 0; i <= lenh - lenn; ++i) {
int j = 0;
while (j < lenn && haystack[i + j] == needle[j]) {
++j;
}
if (j == lenn) {
return i;
}
}
return -1;
}
};
复杂度分析
令 n 为数组长度。
KMP
代码
func strStr(haystack, needle string) int { n, m := len(haystack), len(needle) if m == 0 { return 0 } pi := make([]int, m) for i, j := 1, 0; i < m; i++ { for j > 0 && needle[i] != needle[j] { j = pi[j-1] } if needle[i] == needle[j] { j++ } pi[i] = j } for i, j := 0, 0; i < n; i++ { for j > 0 && haystack[i] != needle[j] { j = pi[j-1] } if haystack[i] == needle[j] { j++ } if j == m { return i - m + 1 } } return -1 }
复杂度
时间:O(n+m)
空间:O(m)
func strStr(haystack string, needle string) int {
return strings.Index(haystack, needle)
}
int strStr(string& haystack, string& needle)
{
if (needle == "") return 0;
int l = 0, r = needle.length() - 1;
while(r < haystack.length())
{
int tmp = l;
int flag = 0;
while(haystack[tmp] == needle[flag] && (tmp <= r))
{
flag++;
tmp++;
}
if(tmp == r + 1)
return l;
l++;
r++;
}
return -1;
}
class Solution { public int strStr(String haystack, String needle) { if (needle == null || needle.trim() == "") { return 0; }
if (haystack == null || haystack.trim() == "") {
return -1;
}
return haystack.indexOf(needle);
}
}
brute force
int strStr(string haystack, string needle) {
if (needle.size() == 0) return 0;
if (haystack.size() < needle.size()) return -1;
for (int i = 0; i < haystack.size() - needle.size() + 1; ++i) {
if (haystack.substr(i, needle.size()) == needle) return i;
}
return -1;
}
class Solution {
public int strStr(String haystack, String needle) {
char[] haystackChar = haystack.toCharArray();
char[] needleChar = needle.toCharArray();
for(int i = 0;i + needleChar.length <= haystackChar.length;i++) {
boolean flag = true;
for(int j = 0;j < needleChar.length;j++) {
if(haystackChar[i + j] != needleChar[j]) {
flag = false;
break;
}
}
if(flag) return i;
}
return -1;
}
}
class Solution {
public int strStr(String haystack, String needle) {
int lenHaystack = haystack.length();
int lenNeedle = needle.length();
// needle equal to zero
if(needle.length() == 0){
return 0;
}
// haystack shorter than
if(lenNeedle < lenNeedle){
return -1;
}
for(int i = 0; i < lenHaystack - lenNeedle + 1; i++){
for(int j =0; j < lenNeedle; j++){
if(haystack.charAt(i+j) != needle.charAt(j)){
break;
}
}
}
}
}
var strStr = function (haystack, needle) {
if (needle.length === 0)
return 0;
const getNext = (needle) => {
let next = [];
let j = -1;
next.push(j);
for (let i = 1; i < needle.length; ++i) {
while (j >= 0 && needle[i] !== needle[j + 1])
j = next[j];
if (needle[i] === needle[j + 1])
j++;
next.push(j);
}
return next;
}
let next = getNext(needle);
let j = -1;
for (let i = 0; i < haystack.length; ++i) {
while (j >= 0 && haystack[i] !== needle[j + 1])
j = next[j];
if (haystack[i] === needle[j + 1])
j++;
if (j === needle.length - 1)
return (i - needle.length + 1);
}
return -1;
};
class Solution {
public:
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
if (m == 0) {
return 0;
}
vector<int> pi(m);
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && needle[i] != needle[j]) {
j = pi[j - 1];
}
if (needle[i] == needle[j]) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack[i] != needle[j]) {
j = pi[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
};
时间复杂度:O(N+M)
空间复杂度:O(M)
int strStr(string haystack, string needle) {
int n = haystack.size(), m = needle.size();
for (int i = 0; i + m <= n; ++i) {
bool flag = true;
for (int j = 0; j < m; ++j) {
if (haystack[i + j] != needle[j]) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
return -1;
}
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if not len(needle):
return 0
try:
return haystack.index(needle)
except Exception:
pass
return -1
滑动窗口
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function(haystack, needle) {
let hLen = haystack.length, nLen = needle.length, res = -1;
if (hLen < nLen) return -1;
if (nLen === 0) return 0;
for(let i = 0; i < hLen - nLen + 1; i++) {
if (haystack.slice(i, i + nLen) === needle) {
res = i
break
}
}
return res;
};
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
for (int i = 0; i + m <= n; i++) {
boolean flag = true;
for (int j = 0; j < m; j++) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
return -1;
}
}
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
if (m == 0) {
return 0;
}
int[] pi = new int[m];
for (int i = 1, j = 0; i < m; i++) {
while (j > 0 && needle.charAt(i) != needle.charAt(j)) {
j = pi[j - 1];
}
if (needle.charAt(i) == needle.charAt(j)) {
j++;
}
pi[i] = j;
}
for (int i = 0, j = 0; i < n; i++) {
while (j > 0 && haystack.charAt(i) != needle.charAt(j)) {
j = pi[j - 1];
}
if (haystack.charAt(i) == needle.charAt(j)) {
j++;
}
if (j == m) {
return i - m + 1;
}
}
return -1;
}
}
class Solution:
'''滚动hash'''
def strStr(self, haystack: str, needle: str) -> int:
lenH = len(haystack)
lenN = len(needle)
if not lenN:
return 0
if lenH < lenN:
return -1
target_hash = 0
hay_hash = 0
base = 101
for i in range(lenN):
target_hash = target_hash * 26 + (ord(needle[i])-ord('a'))
target_hash %= base
hay_hash = hay_hash * 26 + (ord(haystack[i])-ord('a'))
hay_hash %= base
if target_hash == hay_hash and haystack[:lenN] == needle:
return 0
for i in range(1, lenH-lenN+1):
hay_hash = (hay_hash - (ord(haystack[i-1]) -ord('a'))*(26**(lenN-1)))*26 + (ord(haystack[i+lenN-1]) -ord('a'))
hay_hash %= base
if hay_hash == target_hash and haystack[i:i+lenN] == needle:
return i
return -1
时间 O(m+n) 空间 O (1)
C++ Code:
class Solution {
public:
vector<int> next;
void queryNext(string needle)
{
int n = needle.size();
int k = -1, j = 0;
next.assign(n,-1);
while(j<n-1)
{
if(k==-1||needle[j]==needle[k])
{
k++;
j++;
if(needle[j]==needle[k])
next[j] = next[k];
else
next[j] = k;
}
else
k = next[k];
}
}
int strStr(string haystack, string needle) {
queryNext(needle);
int i = 0, j = 0, hn = haystack.size(), nn = needle.size();
while(i<hn&&j<nn)
{
if(j==-1||haystack[i]==needle[j])
{
i++;
j++;
}
else
j = next[j];
}
if(j==nn)
return i - j;
return -1;
}
};
暴力解法。在haystack中找到substring,然后与needle比较。
class Solution {
public int strStr(String haystack, String needle) {
if (needle == null || needle.isEmpty()) {
return 0;
}
int m = haystack.length();
int n = needle.length();
if (m < n) {
return -1;
}
for (int i = 0; i <= m - n; i++) {
String subStr = haystack.substring(i, i + n);
if (subStr.equals(needle)) {
return i;
}
}
return -1;
}
}
复杂度分析
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
示例 1:
输入:haystack = "hello", needle = "ll" 输出:2 示例 2:
输入:haystack = "aaaaa", needle = "bba" 输出:-1 示例 3:
输入:haystack = "", needle = "" 输出:0
提示:
0 <= haystack.length, needle.length <= 5 * 104 haystack 和 needle 仅由小写英文字符组成
参考题解:
【宫水三叶】简单题学 KMP 算法 - 实现 strStr() - 力扣(LeetCode) (leetcode-cn.com)
多图预警👊🏻详解 KMP 算法 - 实现 strStr() - 力扣(LeetCode) (leetcode-cn.com)
(4 封私信 / 60 条消息) 如何更好地理解和掌握 KMP 算法? - 知乎 (zhihu.com)
知乎的这个写的很好
class Solution {
// KMP 算法
// ss: 原串(string) pp: 匹配串(pattern)
public int strStr(String ss, String pp) {
if (pp.isEmpty()) return 0;
// 分别读取原串和匹配串的长度
int n = ss.length(), m = pp.length();
// 原串和匹配串前面都加空格,使其下标从 1 开始
ss = " " + ss;
pp = " " + pp;
char[] s = ss.toCharArray();
char[] p = pp.toCharArray();
// 构建 next 数组,数组长度为匹配串的长度(next 数组是和匹配串相关的)
int[] next = new int[m + 1];
// 构造过程 i = 2,j = 0 开始,i 小于等于匹配串长度 【构造 i 从 2 开始】
for (int i = 2, j = 0; i <= m; i++) {
// 匹配不成功的话,j = next(j)
while (j > 0 && p[i] != p[j + 1]) j = next[j];
// 匹配成功的话,先让 j++
if (p[i] == p[j + 1]) j++;
// 更新 next[i],结束本次循环,i++
next[i] = j;
}
// 匹配过程,i = 1,j = 0 开始,i 小于等于原串长度 【匹配 i 从 1 开始】
for (int i = 1, j = 0; i <= n; i++) {
// 匹配不成功 j = next(j)
while (j > 0 && s[i] != p[j + 1]) j = next[j];
// 匹配成功的话,先让 j++,结束本次循环后 i++
if (s[i] == p[j + 1]) j++;
// 整一段匹配成功,直接返回下标
if (j == m) return i - m;
}
return -1;
}
}
时间复杂度:$O(m + n)$
空间复杂度:$O(m)$
kmp
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if len(needle)==0:
return 0
nexts=[0]*len(needle)
i=0
j=-1
nexts[0]=-1
while i<len(needle)-1:
if j==-1 or needle[i]==needle[j]:
i+=1
j+=1
nexts[i]=j
else:
j=nexts[j]
m=len(haystack)
n=len(needle)
i=0
j=0
while i<m and j<n:
if j==-1 or haystack[i]==needle[j]:
i+=1
j+=1
else:
j=nexts[j]
if j==n:
return i-j
else:
return -1
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length(), m = needle.length();
for (int i = 0; i + m <= n; i++) {
boolean flag = true;
for (int j = 0; j < m; j++) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
return -1;
}
}
# Understand:
0 <= haystack.length, needle.length <= 5 * 10^4
haystack and needle consist of only lower-case English characters.
index of the first occurrence of needle
cannot find => -1
needle "" -> return 0
Tests:
"mississippi"
"issip"
4
# Plan & Match:
bruteforce:
traverse the haystack,
for each char in haystack matching with needle.charAt(0):
traverse from that char
how to search the needle efficiently?
# Evaluate:
## Time: O(haystack.length() * needle.length())
## Space: O(1)
==============Rabin-Karp=======to fina all the matches
0 <= haystack.length, needle.length <= 5 * 10^4
haystack and needle consist of only lower-case English characters.
-> use the power of 26 for hashing
2^63 - 1 < 26 ^ (5 * 10^4)
class Solution {
// =====Rabin-Karp=======to fina all the matches=======
public int strStr(String haystack, String needle) {
// edge cases
if (needle.length() == 0) {
return 0;
}
if (haystack.length() == 0 || needle.length() > haystack.length()) {
return -1;
}
int prime = 101;
int base = 26; // only lower-case English characters.
long initHaystackHash = getInitialHash(haystack, 0, needle.length() - 1, base, prime);
long initNeedleHash = getInitialHash(needle, 0, needle.length() - 1, base, prime);
for (int start = 0; start <= haystack.length() - needle.length(); start++) {
// for each start (except start == 0) recalculate the hash
// O(1)
if (start > 0) {
// recalculate hash by one step
// - leftmost
initHaystackHash -= haystack.charAt(start - 1);
// / base
initHaystackHash /= base;
// + new rightmost
// initHaystackHash += (haystack.charAt(start + needle.length() - 1) * Math.pow(base, needle.length() - 1) % prime) % prime;
// initHaystackHash %= prime;
initHaystackHash += haystack.charAt(start + needle.length() - 1) * Math.pow(base, needle.length() - 1);
}
if (initHaystackHash == initNeedleHash && haystack.substring(start, start + needle.length()).equals(needle)) {
return start;
}
}
return -1;
}
// % a prime to reduce the complexity
// "abc"
// 'a' + 'b' * base + 'c' * base * base
// inclusive
// O(needle) time complexity
private long getInitialHash(String str, int startIndex, int endIndex, int base, int prime) {
long hashRes = 0L;
for (int i = startIndex; i <= endIndex; i++) {
// hashRes += (str.charAt(i) * (Math.pow(base, i - startIndex) % prime)) % prime;
// hashRes %= prime;
hashRes += str.charAt(i) * (Math.pow(base, i - startIndex));
}
return hashRes;
}
public int strStr0(String haystack, String needle) {
// two edge cases
if (needle.length() == 0) {
return 0;
}
if (haystack.length() == 0 || needle.length() > haystack.length()) {
return -1;
}
for (int i = 0; i <= haystack.length() - needle.length(); i++) {
int needleIndex = 0;
int haystackIndex = i;
while (haystack.charAt(haystackIndex) == needle.charAt(needleIndex)) {
needleIndex++;
haystackIndex++;
if (needleIndex == needle.length()) {
return haystackIndex - needle.length();
}
}
}
return -1;
}
// another way
public int strStr1(String haystack, String needle) {
// two edge cases
if (needle.length() == 0) {
return 0;
}
if (haystack.length() == 0 || needle.length() > haystack.length()) {
return -1;
}
// Logic: i is the starting index in haystack that potentially match the first char of needle
// j is the length of the matched needle part
// time complexity O(m * n), m is the length of haystack, n is the length of needle
for (int i = 0; i <= haystack.length() - needle.length(); i++) {
for (int j = 0; j < needle.length() && haystack.charAt(i + j) == needle.charAt(j); j++) {
if (j == needle.length() - 1) return i;
}
}
return -1;
}
}
class Solution: def strStr(self, haystack, needle): """ :type haystack: str :type needle: str :rtype: int """ lenA, lenB = len(haystack), len(needle) if not lenB: return 0 if lenB > lenA: return -1
for i in range(lenA - lenB + 1):
if haystack[i:i + lenB] == needle:
return i
return -1
javascript
/*
* @lc app=leetcode.cn id=28 lang=javascript
*
* [28] 实现 strStr()
*/
// @lc code=start
/**
* @param {string} haystack
* @param {string} needle
* @return {number}
*/
var strStr = function(haystack, needle) {
if (needle === '') {
return 0
}
hLen = haystack.length
nLen = needle.length
for (let i = 0; i < hLen - nLen + 1; i++) {
if (haystack.slice(i, i + nLen) === needle) {
return i
}
}
return -1
};
// @lc code=end
BF,用RK由于大数类耗时多超时
import java.math.BigInteger;
class Solution {
public int strStr(String haystack, String needle) {
int n = haystack.length();
int m = needle.length();
if (m == 0) {
return 0;
}
if (n < m) {
return -1;
}
for (int i = 0; i < n - m + 1; i++) {
int j = 0;
while (j < m) {
if (haystack.charAt(i + j) != needle.charAt(j)) {
break;
}
j++;
}
if (j == m) {
return i;
}
}
return -1;
}
}
time:O(n*m),n是
class Solution {
public int strStr(String haystack, String needle) {
if(needle==null || needle.length()==0)
return 0;
int m = haystack.length();
int n = needle.length();
if(m<n)
return -1;
for(int i=0;i<=m-n;i++) {
if(haystack.substring(i,i+n).equals(needle))
return i;
}
return -1;
}
}
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if not haystack and not needle:
return 0
if not haystack or len(haystack) < len(needle):
return -1
if not needle:
return 0
hash_val = 0
target = 0
prime = 101
for i in range(len(haystack)):
if i < len(needle):
hash_val = hash_val * 26 + (ord(haystack[i]) - ord("a"))
target = target * 26 + (ord(needle[i]) - ord("a"))
else:
hash_val = (
hash_val - (ord(haystack[i - len(needle)]) - ord("a")) * 26 ** (len(needle) - 1)
) * 26 + (ord(haystack[i]) - ord("a"))
if i >= len(needle) - 1 and hash_val == target :
return i - len(needle) + 1
return -1
func strStr(haystack, needle string) int {
n, m := len(haystack), len(needle)
outer:
for i := 0; i+m <= n; i++ {
for j := range needle {
if haystack[i+j] != needle[j] {
continue outer
}
}
return i
}
return -1
}
def strStr(self, haystack: str, needle: str) -> int:
if not haystack and not needle:
return 0
if not haystack or len(haystack) < len(needle):
return -1
if not needle:
return 0
hash_val = 0
target = 0
prime = 2**31 - 19
for i in range(len(haystack)):
if i < len(needle):
hash_val = hash_val * 26 + (ord(haystack[i]) - ord("a"))
hash_val %= prime
target = target * 26 + (ord(needle[i]) - ord("a"))
target %= prime
# print(target)
else:
hash_val = (
hash_val - (ord(haystack[i - len(needle)]) - ord("a")) * (26 ** (len(needle) - 1))
) * 26 + (ord(haystack[i]) - ord("a"))
hash_val %= prime
if i >= len(needle) - 1 and hash_val == target:
# print(target, hash_val)
return i - len(needle) + 1
# print(target, hash_val)
return 0 if hash_val == target else -1
KMP
class Solution {
public:
int strStr(string haystack, string needle) {
if (needle.length() == 0)
return 0;
vector<int> next(needle.length(), 0);
next[0] = -1;
// Generate next array
for (int i = 1; i < needle.length(); i++) {
int k = next[i - 1];
while (k != -1 && needle[i-1] != needle[k]){
k = next[k];
}
/*if (needle[i] == needle[k + 1])
next[i] = next[k + 1];
else */
next[i] = k + 1;
}
int i = 0;
int j = 0;
// Match the string
while (i < haystack.length() && j < (int) needle.length()) {
if (j == -1 || haystack[i] == needle[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if (j == needle.length())
return i - needle.length();
return -1;
}
};
O(m+n), m is the length of needle, o(m) is used to generate the next array; n is the length of haystack
O(m), used to store the next array.
28 实现 strStr(
入选理由
暂无
题目地址
[-BF&RK)
https://leetcode-cn.com/problems/implement-strstr/](-BF&RK)
https://leetcode-cn.com/problems/implement-strstr/)
前置知识
题目描述
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = "hello", needle = "ll" 输出: 2 示例 2:
输入: haystack = "aaaaa", needle = "bba" 输出: -1 说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。