leetcode-字符串

28.实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
字符串的题很多要考虑空字符串的情况,在这道题中needle为空返回0。
暴力求解,如果不匹配就返回长字符串开始匹配的下一位和关键字符串的第一位。

class Solution {    public int strStr(String haystack, String needle) {        if(needle.length()==0)        return 0;        else{        String s=new String();        for(int i=0;i<haystack.length();i++)        {            s=haystack.substring(i);            if(s.startsWith(needle))            return i;        }        return -1;}    }}

看到有比较简化的KMP算法,大概理解了一下思路,发现很多人都讲得不好,把一个简单的道理绕来绕去,不过发现要自己来将也没那么容易。
ABABAABABF i 主串
ABABF j 关键字符串
01 234 下标
暴力算法:当关键字指针j移动到某一位与主串i不匹配时(i=j=4),意味着主串和关键字都要回退,然后再关键字字符串从头再与主串开始匹配(i-j+1=1,j=0),我们这么做主要是担心主串在已匹配的字符串中有某一位到i-1可能与关键字从头开始重合,(如主串的AB与子串前面的AB相同,若主串i=4,5,6时ABF,则匹配)
KMP算法:那么如果我们找到在紧跟着不匹配位的前面(即j=i=4前面,主串和关键字相同)和在关键字的开头相同的尽可能长的子串(AB),这就是可能重合的最大部分,那么在关键字重新与主串重合位再开始比较即可(将j=0,1与i=2,3重合)由于主串的不匹配的位前面子串和关键字子串相同,所以在未开始匹配前,就可以先在关键字中找某个位与开头重合部分(这个找是从0往前与从不匹配位往回找尽可能长的重合子串),用next[]记录开头子串的下一位。

public static int[] getNext(String ps) {
    char[] p = ps.toCharArray();
    int[] next = new int[p.length];
    next[0] = -1;
    int j = 0;
    int k = -1;
    while (j < p.length - 1) {
       if (k == -1 || p[j] == p[k]) {
           next[++j] = ++k;
       } else {
           k = next[k];
       }
    }
    return next;
}
public static int KMP(String ts, String ps) {
    char[] t = ts.toCharArray();
    char[] p = ps.toCharArray();
    int i = 0; // 主串下标
    int j = 0; // 关键字串的下标
    int[] next = getNext(ps);
    while (i < t.length && j < p.length) {
       if (j == -1 || t[i] == p[j]) { 
           i++;
           j++;
       } else {
           j = next[j]; 
       }
    }
    if (j == p.length) {
       return i - j;
    } else {
       return -1;
    }
}

14.最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 “”。
注意数组为空时也是返回""。
先匹配第一二个字符串的公共子序列,再将这个子序列与下一个字符串匹配。匹配的时候可以不用从前往后一个个字符串比较,可以从后往前直接startsWith,不匹配再substring(0,–len)注意包前不包后。

class Solution {    public String longestCommonPrefix(String[] strs) {        if(strs.length==0)        return "";        else{        int len1=strs[0].length(),len2=strs.length;        String s=new String();        s=strs[0];        for(int i=1;i<len2;i++)            while(!strs[i].startsWith(s))            s=s.substring(0,--len1);        if(len1>0)        return s;        else return "";}    }}

看到官方题解还有纵向匹配的:先匹配所有的第一个字符,再进行下一个。这个其实就是while和for的位置换一下,不过这种匹配就要一个个字符串地比较。

发布了45 篇原创文章 · 获赞 4 · 访问量 1059

猜你喜欢

转载自blog.csdn.net/weixin_43838915/article/details/104564504
今日推荐