【LeetCode-面试经典150题-day6】

14.最长公共前缀

题意:

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

【输入样例】

strs = ["flower","flow","flight"]

【输出样例】

"fl"

解题思路:

横向扫描,依次遍历字符串数组中的每个字符串,对于每个遍历到的字符串,更新最长公共前缀,当遍历完所有的字符串后,即可得到字符数组中的最长公共前缀;

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs == null || strs.length == 0){
            return "";
        }
        String strPre = strs[0];
        int count = strs.length;
        for(int i=1;i<count;++i){
            strPre = longPre(strPre,strs[i]);
            if(strPre.length() == 0){
                return "";
            }
        }
        return strPre;

    }
    private String longPre(String str1,String str2){
        int len = Math.min(str1.length(),str2.length());
        int index = 0;
        while(index < len && str1.charAt(index) == str2.charAt(index)){
            ++index;
        }
        return str1.substring(0,index);
    }
}

时间: 击败了100.00%

内存: 击败了97.06%

解题思路:

二分查找,最长公共前缀的长度不会超过字符串数组中的最短字符串的长度。用minLength表示字符串数组中的最短字符串的长度,则可以在[0,minLength]的范围内通过二分查找得到最长公共前缀的长度。

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs == null || strs.length == 0){
            return "";
        }
        int minLength = Integer.MAX_VALUE;
        for(String str:strs){
            minLength = Math.min(minLength,str.length());
        }
        int low = 0,high = minLength;
        while(low < high){
            int mid = (high - low + 1)/2 +low;
            if(longPre(strs,mid)){
                low = mid;
            }else{
                high = mid - 1;
            }
        }
        return strs[0].substring(0,low);
    }
    private boolean longPre(String[] strs,int length){
         String str0 = strs[0].substring(0,length);
         int count = strs.length;
         for(int i=1;i<count;++i){
             String str = strs[i];
             for(int j=0;j<length;++j){
                 if(str0.charAt(j) != str.charAt(j)){
                     return false;
                 }
             }
         }
         return true;
    }
}

 时间: 击败了68.45%

内存: 击败了33.22%

 151.反转字符串中的单词

题意:

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

【输入样例】

s="the sky is blue "

【输出样例】

"blue is sky the"

解题思路:

1.遍历枚举,从字符串的最后一位开始遍历;

2.找到第一个非空字符,开始记录,当前索引end=i为找到单词的最后一位;

3. 继续遍历,直到找到下一个空格,当前索引start = ++i为找到的单词的上一位;

4.将单词截取,添加到新字符串中,注意单词后面要加一个空格;

5.遍历结束后,因为每个单词后面都加了一个空格,所以要把最后一位单词后的空格删了。

class Solution {
    public String reverseWords(String s) {
        StringBuffer str = new StringBuffer();
        int start,end;//每个单词的开始和结束索引

        for (int i = s.length() - 1; i >= 0; --i) {
            //当遍历到不是空格的时候,开始记录单词
            if(s.charAt(i) == ' '){
                //不做任何处理,继续遍历下一位
                continue;
            }
            //走到这一步,证明找到了不是空格的字符
            end = i;
            //继续遍历,找到下一个空格,证明找到了一个单词
            while(i>=0 && s.charAt(i) != ' '){
                --i;//不是空格且索引没越界,继续遍历
            }
            //跳出上述的while循环,证明i<0或者找到了空格了,把单词的开始索引记录一下
            start = ++i;//因为while里执行了--i,这里要加上
            str.append(s.substring(start,end+1)+" ");//每个单词后面有一个空格
        }
        //遍历结束了,要删掉最后一个单词后面的空格
        str.deleteCharAt(str.length()-1);
        return str.toString();
    }
}

 时间:击败了81.92%

内存:击败了44.08%

 6.N形变换

题意:

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

【输入样例】

s="PAYPALISHIRING",numRows =3

【输出样例】

"PAHNAPLSIIGYIR"

解题思路:

想用压缩二维矩阵解决,先打个地基,直接用二维矩阵实现,其实二维矩阵最难的就是根据numRows的值判断每一列填入的行号,因为每一列都有数,但是除了0,n-1,(n-1)*2等列数是全部填满(字符足够的情况下),其余是斜着填充的。

1. 当numRows=1时,只有一行,直接return;当numRows>=s.length()时,字符串只填入第一列,读取结果也一样,直接return;

2. 在矩阵上写字符,先向下写numRows个,然后向右上继续填写numRows-2个字符(占numRows-2列),-2是因为第一行和最后一行都不写入,因此,Z字形变换的周期T=numRows+numRows-2=2numRows-2,每个周期占用1+numRows-2=numRows-1列。

3. 共有s.length()/T个周期,向上取整,矩阵共有s.length()/T*(numRows-1)列

class Solution {
    public String convert(String s, int numRows) {
        int n = s.length(),r = numRows;
        if(r == 1 || r >= n){
            return s;
        }
        int t = 2*r-2;
        int c = ((n-1)/t + 1) * (r-1);
        char[][] mat = new char[r][c];
        for(int i=0,x=0,y=0;i<n;++i){
            mat[x][y] = s.charAt(i);
            if(i % t < r-1){
                ++x;//向下移动
            }else{
                --x;
                ++y;//向右上移动
            }
        }
        StringBuffer ans = new StringBuffer();
        for(char[] row:mat){
            for(char ch : row){
                if(ch != 0){
                    ans.append(ch);
                }
            }
        }
        return ans.toString();
    }
}

时间:击败了14.23%

内存:击败了9.66% 

 解题思路:压缩二维矩阵

因为每次读取都是按行读取,将矩阵每一行初始化为空列表,每次往列表末尾添加字符

class Solution {
    public String convert(String s, int numRows) {
        int n = s.length(),r = numRows;
        if(r == 1 || r >= n){
            return s;
        }
        StringBuffer[] mat = new StringBuffer[r];
        for(int i=0;i<r;++i){
            mat[i] = new StringBuffer();
        }
        for(int i=0,x=0,t=r*2-2;i<n;++i){
            mat[x].append(s.charAt(i));
            if(i % t < r - 1){
                ++x;//下一行
            }else{
                --x;//上一行
            }
        }
        StringBuffer ans = new StringBuffer();
        for(StringBuffer row:mat){
            ans.append(row);//一整行一整行读
        }
        return ans.toString();
    }
}

时间:击败了45.67%

内存:击败了72.19% 

28.找出字符串中第一个匹配项的下标

题意:

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 

【输入样例】

haystack="sadbutsad",needle="sad"

【输出样例】

0

解题思路:

emmmmm,先暴力枚举哈哈哈。

class Solution {
    public int strStr(String haystack, String needle) {
        int i,j,start;//分别指向haystack和needle字符串
        for(i = 0;i<haystack.length();++i){
            //首先要找到第一个与needle第一个字符匹配的字符
            if(haystack.charAt(i) != needle.charAt(0)) continue;//继续往下遍历
            //走到这一步,表示上面的i,与needle的第一个字符匹配
            j=0;
            start = i;//haystack
            //遍历,并且不能越界
            while( start<haystack.length() && j<needle.length()&& haystack.charAt(start) == needle.charAt(j) ){
                ++start;
                ++j;
            }
            //跳出循环之后,要判断,如果是j越界了,证明找到了,直接return start
            if(j == needle.length()){
               return i;
            }else if(i == haystack.length()){
                //j没有越界,i越界了,找不到了
                return -1;
            }
            //继续循环
        }
        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;
    }
}

/*作者:力扣官方题解
链接:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/solutions/732236/shi-xian-strstr-by-leetcode-solution-ds6y/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/

 时间:击败了43.29%

内存:击败了34.26%

解题思路:KMP算法

哈哈哈我写不明白,参考b站代码随想录Carl的讲解

帮你把KMP算法学个通透!(理论篇)_哔哩哔哩_bilibili

 int n = haystack.length(),m=needle.length();
        int[] next = new int[m];//前缀数组
        for(int i = 1, j = 0;i<m;++i){
            while(j > 0 && needle.charAt(i) != needle.charAt(j)){
                j = next[j - 1];
            }
            if(needle.charAt(i) == needle.charAt(j)){
                ++j;
            }
            next[i] = j;
        }
        for(int i = 0, j= 0; i < n; ++i){
            while(j > 0 && haystack.charAt(i) != needle.charAt(j)){
                j = next[j-1];
            }
            if(haystack.charAt(i) == needle.charAt(j)){
                ++j;
            }
            if(j == m){
                return i - m + 1;
            }
        }

 时间:击败了100.00%

内存:击败了14.82%

 125.验证回文串

题意:

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 

【输入样例】

s="A man, a plan, a canal:Panama"

【输出样例】

true

解题思路:

双指针判断,记得遇到非字母数字字符跳过。

class Solution {
    public boolean isPalindrome(String s) {
        if(s == null){
            return true;
        }
        s = s.toLowerCase();
        int i=0,j=s.length()-1,flag=1;
        while(i<=j){
            while(i<j && !Character.isLetterOrDigit(s.charAt(i))){
                ++i;
            }
            while(i<j && !Character.isLetterOrDigit(s.charAt(j))){
                --j;
            }
            if(s.charAt(i) != s.charAt(j)){
                return false;
            }
            ++i;
            --j;
        }
        return true;
    }
}

时间:击败67.53%

内存:击败69.62% 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值