字符串总结

28. 实现 strStr()

class Solution {
    public int strStr(String haystack, String needle) {
        /**
        分析:
        我的第一想法就是使用滑动窗口解题,事实上确实可以使用滑动窗口。
        但是对于字符串匹配问题,一般的思路就是暴力解法和kmp算法
         */
         // 使用滑动窗口
         int len1 = haystack.length(), len2 = needle.length();
         if(len2 == 0){
             return 0;
         }
         // 定义双指针(窗口指针)
         int p1 = 0, p2 = len2 - 1;
         // 循环遍历结束条件是p2指针达到len1
         while( p2 < len1){
             // 这里要注意,substring()是左闭右开的
             if(haystack.substring(p1,p2+1).equals(needle)){
                 return p1;
             }
             p1++;
             p2++;
         }
         return -1;

    }
}

38. 外观数列(模拟进行循环,变态的过程)

class Solution {
    public String countAndSay(int n) {
        /**
        分析:
        这题能想出来是怪胎把~,使用循环和递归解法。这里使用循环解法。
        外层循环是进行层数(1-n),里层循环是判断是否有重复的数字
         */
         // 初始值为1
         StringBuilder curr = new StringBuilder("1");
         // 定义一个临时字符串用来储存上一次的信息
         StringBuilder prev;
         // 第一层循环,用于迭代1-n,下标从1开始,因为已经初始化了
         for(int i = 1; i < n; i++){
             // 迭代上一次信息
             prev = curr;
             // 构造当前信息
             curr = new StringBuilder();
             // 对上一次信息分析:count和say
             int count = 1;
             char say =prev.charAt(0);
             // 第二层循环用来判断prev是否有重复,有就count++,否则就直接加入curr并且更新say和count
             for(int j = 1; j < prev.length(); j++){
                 // 若是有重复的say
                 if(prev.charAt(j) == say){
                     count++;
                 }else{
                     // 否则就更新curr,say和count
                     curr.append(count).append(say);
                     count = 1;
                     say = prev.charAt(j);
                 }
             }
             // 对最后一次信息进行更新
             curr.append(count).append(say);
         }
        return curr.toString();

    }
    
}

58. 最后一个单词的长度(倒序遍历+双指针)

class Solution {
    public int lengthOfLastWord(String s) {
        /**
        分析:
        题目要求最后一个单词的长度,那不就是倒序遍历的第一个单词的长度~~~
         */
         int end = s.length() - 1;
         // 先去除末尾的空格
         while(end >= 0 && s.charAt(end) == ' '){
             end--;
         }
         int start = end;
         // 定位start为最后一个单词前的空格位置
         while(start >= 0 && s.charAt(start) != ' '){
             start--;
         }
         // 返回距离
         return end - start;

    }
}

165. 比较版本号(实际上就是比较大小)

注意:这里使用了spilt内置函数,若面试不允许使用内置函数,那么就得用方法二了

class Solution {
    public int compareVersion(String version1, String version2) {
        /**
        分析:
        所谓的比较版本号,实际上就是在比较大小。这里数字越靠前的,权重越大,那么完全可以将其权重化。
        有两种解法:
        一种是使用split进行拆分(注意java中的转义写法)
        另一种是使用数字权重比较最终值(降低是空间复杂度)
         */
         // split函数
         String[] v1 = version1.split("\\.");
         String[] v2 = version2.split("\\.");
         int len1 = v1.length;
         int len2 = v2.length;
         for(int i = 0; i < len1 || i < len2; i++){
             // 没有版本号,则默认为0
             int x = 0, y = 0;
             if(i < len1){
                 // 字符串转换为整数
                 x = Integer.parseInt(v1[i]);
             }else{
                 x = 0;
             }
             if(i < len2){
                 // 字符串转换为整数
                 y = Integer.parseInt(v2[i]);
             }else{
                 y = 0;
             }
             // 比较
             if( x != y){
                 return x > y ? 1 : -1;
             }
         }
         return 0;
    }
}

方法二:采用数字权重的办法
这里要注意内层和外层循环各自的作用,不能简单的只用一层循环(这样位数越长数字就越大),比如 7.5.2.3和7.5.3这样的版本号。
实际上,每一层都得去比较,只不过这里的比较换成了有权重的比较

class Solution {
    public int compareVersion(String version1, String version2) {
        /**
        分析:
        所谓的比较版本号,实际上就是在比较大小。这里数字越靠前的,权重越大,那么完全可以将其权重化。
        有两种解法:
        一种是使用split进行拆分(注意java中的转义写法)
        另一种是使用数字权重比较最终值(降低是空间复杂度)
         */
         
        int i = 0,j = 0;
        int len1 = version1.length();
        int len2 = version2.length();
        // 外层循环 控制每一个分位的比较
        while(i < len1 || j < len2){
            int x = 0, y = 0;
            // 内层循环进行权重的叠加
            while(i < len1&&version1.charAt(i) != '.'){
                    // 这里使用前部*10来增加前部的权重
                    x = x*10 + version1.charAt(i) - '0'; 
                    i++;
            }
            // 跳过.号
            ++i;
            while(j < len2&&version2.charAt(j) != '.'){
                    y = y*10 + version2.charAt(j) - '0'; 
                    j++;
                }
            
            // 跳过.号
            ++j;
            if(x != y){
                return x > y ? 1: -1;
            }
        }
        return 0;

        }
        
}

345. 反转字符串中的元音字母(双指针+api转换)

class Solution {
    public String reverseVowels(String s) {
        /**
        分析:
        题目的意思是找出字符串中所有的元音字母,然后在对应位置的下标进行反转。
        第一想法是使用双指针法,在进行逻辑编写的时候还需要注意,将String转换为char数组,char数组转换为string
         */
         int len = s.length();
         int p1 = 0, p2 = len - 1;
        //  StringBuilder sb = new StringBuilder(); 使用sb的缺点就是交换的时候不方便
        // 思路转换,将String 转换为 char数组,这样就可以原地修改了
        // string和char数组互相转换的相关api:s.toCharArray() 和String.valueOf(char[])
        char[] res = s.toCharArray();
         while( p1 < p2){
             while(p1 < p2 && !isVowel(res[p1])){
                 // 首部循环判断是不是元音
                 p1++;
             }
             while(p1 < p2 && !isVowel(res[p2])){
                 // 尾部循环判断是不是元音
                 p2--;
             }
             // 进行交换
             char temp = res[p1];
             res[p1] = res[p2];
             res[p2] = temp;
             // 记得移动位置
             p1++;
             p2--;
         }
         return String.valueOf(res);

    }
    public boolean isVowel(char c){
        if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'|| c == 'A'|| c == 'E' ||
        c == 'I' || c == 'O' || c == 'U'){
            return true;
        }
        return false;
    }
}

459. 重复的子字符串(模拟法,%思想)

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        /**
        分析:
        题解中使用了indexof()的api函数,个人觉得有点炫技了,所以还是采用可常规思路来解题。
        首次就是重复子串构成的字符串必定是某个数的倍数,其次就是确定上一个条件后,依次比较对应的字符是否相同(这里使用了 % 方法,和之前做的环形赛道很像!)
         */
         int len = s.length();
         for( int i = 1; i < len; i++){
             // 长度是i的倍数,说明有可能有戏
             if(len % i == 0){
                 // 循环判断
                 String sub = s.substring(0,i);
                 if(judge(sub,s)){
                     // 是满足条件的直接return(实际上可能有多个满足条件)
                     return true;
                 }
             }
         }
         return false;
    }
    public boolean judge(String sub,String s){
        int sublen = sub.length();
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) != sub.charAt(i % sublen)){
                // 主串和子串是否匹配,这里使用了 % 
                return false;
            }
        }
        return true;
    }
}

541. 反转字符串 II(模拟法。读懂题意是关键)

class Solution {
    public String reverseStr(String s, int k) {
        /**
        分析:
        定义一个反转函数,然后根据题干情况进行依次反转.
        这里的题干情况归纳总结就是:反转下标为2k的倍数,反转长度为k,若k大于子串长度,则反转整个子串
         */
         int len = s.length();
         char[] res = s.toCharArray();
         for(int i = 0; i < len; i += 2 * k){
             // 这里调用了api,确实比较难想到,还是得多练习
             reverse(res,i,Math.min( i + k, len) - 1);
         }
         return new String(res);

    }
    public void reverse(char[] res,int start,int end){
        // 转换为char数组才能原地修改
        while(start < end){
            char temp = res[start];
            res[start] = res[end];
            res[end] = temp;
            // 移动
            start++;
            end--;
        }
    }
}

557. 反转字符串中的单词 III(双指针)

class Solution {
    public String reverseWords(String s) {
        /**
        很明显,双指针的应用
         */
         char[] res = s.toCharArray();
         int len = res.length;
         int p1 = 0, p2 = 0;
         while(p2 < len){
             while( p2 < len && res[p2] != ' ' ){
                 p2++;
             }
             // 反转
             reverse(res,p1,p2-1);
             // p2跳过空格 
             ++p2;
             p1 = p2;
         }
         return new String(res);

    }
    public void reverse(char[] res, int start,int end){
        while(start < end){
            char temp = res[start];
            res[start] = res[end];
            res[end] = temp;
            start++;
            end--;
        }
        
    }
}

14. 最长公共前缀(纵向搜索)

class Solution {
    public String longestCommonPrefix(String[] strs) {
        /**
        分析:
        这是一道字符串的应用,一般的思路是纵向查找,一一比对前k个字母是否相等
         */
         if(strs.length == 0){
             return "";
         }
         for(int i = 0; i < strs[0].length(); i++){
             // str[0]中的第 i 个字符
             char c = strs[0].charAt(i);
             // 纵向搜索
             for(int j = 1; j < strs.length; j++){
                 // i 达到了搜索的长度或者发现有字符不匹配
                 if(i == strs[j].length() || c != strs[j].charAt(i)){
                     // 截取字符串
                     return strs[0].substring(0,i);
                 }
             }
         }
         // 全都匹配
         return strs[0];

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值