leetcode28

题目链接:https://leetcode.com/problems/implement-strstr/

Implement strStr().

Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.


思路:按照简单的做可以很简单,就是找一个字符串中是否包含另一个字符串,并返回其位置。按照复杂的做那么就是KMP了, 所以 看出题人的意思了.

代码如下:

  1. class Solution {  
  2. public:  
  3.     int strStr(string haystack, string needle) {  
  4.         int i = -1, len1 = haystack.size(), len2 = needle.size();  
  5.         while(++i <= len1-len2)  
  6.         {  
  7.             string tem = haystack.substr(i, len2);  
  8.             if(tem == needle) return i;  
  9.         }  
  10.         return -1;  
  11.     }  
  12. };  
class Solution {
public:
    int strStr(string haystack, string needle) {
        int i = -1, len1 = haystack.size(), len2 = needle.size();
        while(++i <= len1-len2)
        {
            string tem = haystack.substr(i, len2);
            if(tem == needle) return i;
        }
        return -1;
    }
};

KMP

[cpp] view plain copy


print?

  1. class Solution {  
  2. public:  
  3.     int strStr(string haystack, string needle) {  
  4.         int i, k = 0, len1 = haystack.size(), len2 = needle.size();  
  5.         if(len2==0 || haystack == needle) return 0;  
  6.         vector<int> index(len2, 0);  
  7.         for(i = 1; i < len2; i++)  
  8.         {  
  9.             while(k>0 && needle[i]!=needle[k]) k = index[k-1];  
  10.             index[i] = (k+=needle[i]==needle[k]);  
  11.         }  
  12.         for(i = 0, k = 0; i < len1; i++)  
  13.         {  
  14.             while(k>0 && haystack[i]!=needle[k]) k = index[k-1];  
  15.             k += needle[k] == haystack[i];  
  16.             if(k == len2) return i-len2+1;  
  17.         }  
  18.         return -1;  
  19.     }  
  20. }; 

转自小榕流光的博客
<think>嗯,我现在需要解决如何在Java中实现LeetCode28题,也就是实现strStr()函数。这个问题要求在一个字符串中找到另一个子串的首次出现位置,并返回其起始索引。如果找不到的话,就返回-1。此外,当子串是空字符串时,应该返回0。这跟C语言的strstr()和Java的indexOf()的行为一致。 首先,我应该回忆一下字符串匹配的常见方法。根据引用内容,提到了暴力匹配和KMP算法。用户提供的示例中有暴力匹配的Java代码,看起来是正确的。我需要先理解暴力匹配的思路,然后看看是否需要考虑更高效的算法比如KMP,但根据问题描述,用户可能主要想了解基础实现,或者更高效的解法。 暴力匹配的思路是从主字符串s的每个可能的起始位置开始,逐个字符与子串t比较。如果某个位置开始的连续字符与t完全匹配,就返回该位置。如果遍历完所有可能的位置都没有找到匹配,就返回-1。这个过程的时间复杂度是O(m*n),其中m和n分别是s和t的长度。对于LeetCode的题目来说,可能在某些测试用例下效率不够,但题目可能接受暴力解。 然后,用户提供的引用中有一个Java版本的暴力匹配代码,这个代码是否正确呢?让我仔细看一下。代码中的循环条件是i <= m - n,其中m是s的长度,n是t的长度。这里应该是对的,因为当主字符串剩下的长度不足子串长度时,就不需要再检查了。然后内部循环检查每个字符是否匹配,如果所有字符都匹配(j == n),就返回i。否则,继续下一个起始位置。这应该是对的。 另外,当子串为空时,根据引用[2]、[3]、[4],应该返回0。所以在代码中,需要先处理这种情况。用户提供的示例代码可能没有处理,因为在参数中可能子串t不会是空的?或者题目中的输入可能保证?比如题目描述中提到当needle是空字符串时返回0,所以在Java实现中,应该首先检查子串是否为空,如果是,直接返回0。 那用户的示例代码中的参数是s和t,是否处理了t为空的情况?在代码中,假设输入的t的长度是n,当n是0的时候,循环不会执行,直接返回-1。但根据题目要求,当子串为空时应该返回0。所以示例代码可能没有处理这种情况,需要添加这个条件判断。 因此,正确的Java代码应该先判断子串是否为空的特殊情况,然后再进行暴力匹配。例如,在函数开始处,如果t的长度是0,则返回0。否则继续后面的循环。 另外,用户提供的引用中有关于KMP算法的内容,比如引用[2]和引用[5]。KMP算法的时间复杂度是O(m+n),比暴力匹配更高效,但实现起来复杂一些。用户可能想知道如何用KMP来实现这个问题,但根据问题,用户可能希望得到暴力解法和KMP解法的说明。 因此,在回答中,我应该先给出暴力匹配的Java代码,并指出需要注意空字符串的情况,然后可以介绍KMP算法的实现,以供用户选择更优的解法。 接下来,我需要检查暴力匹配的示例代码是否正确。例如,在Java代码中,循环变量i的范围是否正确?假设s的长度是m,t的长度是n,那么i的取值范围应该是从0到m-n,包含m-n吗?例如,当i = m-n时,剩下的字符刚好有n个,可以进行比较。所以循环条件应该是i <= m - n。示例代码中的循环条件是正确的。 此外,内部循环的变量j从0到n-1,检查每个字符是否匹配。如果所有字符都匹配,则j会等于n,此时返回i。否则,继续外层循环。这部分是正确的。 现在,针对用户的问题,总结步骤: 1. 处理特殊情况:如果子串为空,返回0。 2. 主循环遍历s中的每个可能的起始位置i(从0到m-n)。 3. 对于每个i,检查接下来的n个字符是否与t完全匹配。 4. 如果找到匹配,返回i;否则继续。 5. 遍历结束后未找到,返回-1。 然后,KMP算法的实现需要构建部分匹配表(前缀函数),然后利用这个表在匹配失败时跳过不必要的比较。具体步骤包括: 1. 预处理子串,生成next数组。 2. 使用双指针i和j,分别遍历s和t。 3. 当字符匹配时,同时移动i和j。 4. 当不匹配时,根据next数组回退j的位置。 5. 当j等于t的长度时,找到匹配,返回i - j的位置。 这部分实现较为复杂,需要正确构建next数组。例如,next数组的每个元素表示在当前位置匹配失败时,子串应该回退到哪个位置。构建next数组的过程是通过子串本身的前缀和后缀的最长公共长度。 因此,在回答中,可以给出两种方法的实现,并比较它们的优缺点。暴力匹配实现简单,适合较短字符串;KMP效率更高,适合大文本。 最后,根据用户提供的引用,例如引用[5]提到了KMP的应用,可以引用相关内容说明KMP的优势。同时,要注意代码的正确性,比如处理空字符串的情况。 总结,用户需要的答案应包括: - 问题描述和要求。 - 处理空子串的特殊情况。 - 暴力匹配的Java实现,并解释其步骤。 - KMP算法的Java实现,并解释其原理。 - 两种方法的比较和应用场景。 现在,将这些内容组织成一个结构清晰的回答,并确保符合用户提到的系统级指令,例如行内公式用$...$,独立公式用$$...$$,以及生成相关问题。</think>### Java实现LeetCode28题字符串匹配问题(strStr) #### 问题分析 题目要求在字符串`haystack`中找出子串`needle`第一次出现的索引。若子串为空,返回0;若未找到,返回-1。这与Java的`indexOf()`方法行为一致[^2][^3][^4]。 --- #### 方法一:暴力匹配(时间复杂度$O(m \cdot n)$) ##### 实现步骤 1. **处理边界条件**:若子串为空,直接返回0 2. **主循环遍历**:`haystack`的每个可能的起始位置`i`(范围$0 \leq i \leq m-n$) 3. **字符匹配检查**:从`i`开始逐个字符比较 4. **匹配成功判断**:若所有字符匹配则返回当前索引 ##### Java代码实现 ```java public class Solution { public int strStr(String haystack, String needle) { int m = haystack.length(); int n = needle.length(); if (n == 0) return 0; // 处理空子串[^3] for (int i = 0; i <= m - n; i++) { int j; for (j = 0; j < n; j++) { if (haystack.charAt(i + j) != needle.charAt(j)) break; } if (j == n) return i; } return -1; } } ``` --- #### 方法二:KMP算法(时间复杂度$O(m + n)$) ##### 核心思想 通过预处理子串生成**部分匹配表(next数组)**,利用匹配失败时的已知信息跳过不必要的比较[^2][^5]。 ##### 实现步骤 1. **构建next数组**:记录子串前缀与后缀的最长公共长度 2. **双指针匹配**:`i`遍历主串,`j`遍历子串 3. **失败回退**:根据`next[j-1]`调整`j`的位置 ##### Java代码实现 ```java public class Solution { public int strStr(String haystack, String needle) { int m = haystack.length(), n = needle.length(); if (n == 0) return 0; int[] next = getNext(needle); int i = 0, j = 0; while (i < m && j < n) { if (j == -1 || haystack.charAt(i) == needle.charAt(j)) { i++; j++; } else { j = next[j]; } } return j == n ? i - j : -1; } private int[] getNext(String pattern) { int n = pattern.length(); int[] next = new int[n]; next[0] = -1; int i = 0, j = -1; while (i < n - 1) { if (j == -1 || pattern.charAt(i) == pattern.charAt(j)) { i++; j++; next[i] = j; } else { j = next[j]; } } return next; } } ``` --- #### 方法对比 | 方法 | 时间复杂度 | 空间复杂度 | 适用场景 | |------------|------------|------------|------------------------| | 暴力匹配 | $O(m \cdot n)$ | $O(1)$ | 短文本、简单场景 | | KMP算法 | $O(m + n)$ | $O(n)$ | 长文本、频繁匹配操作 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值