2021年5月4号,力扣刷题记录---Java---字符串

好久好久才来更新,实际上我已经写了一些题,只是还没有回顾,这些题算是开始回顾复习的开始,给自己定一个目标,最多五天补充自己复习的内容。感谢督促的自己。

字符串系列

344. 反转字符串

题目地址

题目描述

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

思路

利用左右指针方式,通过一个临时变量来交换字符组中的字符顺序

代码及注释

class Solution {
    public void reverseString(char[] s) {
        //左右指针,反转字符串
        for (int leftIndex = 0, rightIndex = s.length - 1; leftIndex < rightIndex; leftIndex++, rightIndex--) {
            char temp = s[leftIndex];
            s[leftIndex] = s[rightIndex];
            s[rightIndex] = temp;
        }
        return;
    }
}

541. 反转字符串 II

题目地址

难度:简单

题目描述

给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:

现有矩阵 matrix 如下:

输入: s = "abcdefg", k = 2
输出: "bacdfeg"

提示:

  • 该字符串只包含小写英文字母。
  • 给定字符串的长度和 k 在 [1, 10000] 范围内。

思路

对范围[0+2k, k + 2k]范围内的字符串进行翻转

代码及注释

class Solution {
    public String reverseStr(String s, int k) {
        char[] str = s.toCharArray();

        for (int start = 0; start < str.length; start += 2 * k) {
            int i = start;
            int j = Math.min(str.length - 1, start + k - 1);
            for ( ; i < j; i++, j--) {
                char temp = str[i];
                str[i] = str[j];
                str[j] = temp;
            }
        }
        return new String(str);
    }
}

剑指 Offer 05. 替换空格

题目地址

难度:简单

题目描述

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:

现有矩阵 matrix 如下:

输入:s = "We are happy."
输出:"We%20are%20happy."

提示:

  • 0 <= s 的长度 <= 10000

思路

将空格填充为三个字符位置,新建一个字符串或字符组进行储存

代码及注释

class Solution {
    public String replaceSpace(String s) {
        char[] str1 = s.toCharArray();
        char[] str2 = new char[3 * s.length()];
        String s1 = "";
        int index = 0;

        for (int i = 0; i < s.length(); i++){
            if (str1[i] == ' '){
                str2[index++] = '%';
                str2[index++] = '2';
                str2[index++] = '0';
            } else {
                str2[index++] = str1[i];
            }
        }

        //字符数组 特定位置处的字符转换为字符串
        return s1.copyValueOf(str2, 0, index);
    }
}

151. 翻转字符串里的单词

题目地址

题目描述

给定一个字符串,逐个翻转字符串中的每个单词。

说明:

  • 无空格字符构成一个单词
  • 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
  • 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
示例 1:
输入:"the sky is blue"
输出:"blue is sky the"
示例 2:
输入:"  hello world!  "
输出:"world! hello"
解释:输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入:s = "  Bob    Loves  Alice   "
输出:"Alice Loves Bob"

思路

可以分成三步解决题目:

  • 首先删除字符串中的多余空格,使用函数trim1,多余的空格可能在字符串头部、尾部、中间
  • 先整体翻转整个字符串,swap1
  • 最后根据空格区分单词,将单词再次进行翻转

代码及注释

class Solution {
    public String reverseWords(String s) {
        //去除空格
        StringBuilder str1 = triml(s);

        //字符串反转
        int left = 0;
        int right = str1.length() - 1;
        swapl(left, right, str1);

        //单词再次反转
        int start = 0;
        for (int i = 0; i < right; i++){
            if (str1.charAt(i) == ' '){
                swapl(start, i-1, str1);
                start = i + 1;
            } else if (i == right - 1){
                swapl(start, right, str1);
            }
        }

        //返回反转后的单词
        return str1.toString();
    }

    //去除空格函数
    public StringBuilder triml(String str){
        int left = 0;
        int right = str.length() - 1;
        //去除字符串左端空格
        while (left < right && str.charAt(left) == ' '){
            left++;
        }
        //去除字符串右端空格
        while (left < right && str.charAt(right) == ' '){
            right--;
        }

        StringBuilder str1 = new StringBuilder();
        for (int i = left ; i <= right; i++){
            char c = str.charAt(i);
            if (c != ' '){
                str1.append(c);
            } else if (str.charAt(i - 1) != ' '){
                str1.append(c);
            }
        }
        return str1;
    }

    //字符串反转
    public void swapl(int left, int right, StringBuilder str){
        for ( ; left < right; left++, right--){
            char temp = str.charAt(left);
            // str.charAt(start) = str.charAt(end);
            // str.charAt(end) = temp;
            str.setCharAt(left, str.charAt(right));
            str.setCharAt(right,temp);
            
            // char tmp = sb.charAt(left);
            // sb.setCharAt(left, sb.charAt(right));
            // sb.setCharAt(right, tmp);
        }
    }

}

学习内容一:

String、StringBuilder、StringBuffer的区别和联系:(两篇CSDN中的文章可以借鉴查看)

剑指 Offer 58 - II. 左旋转字符串

题目地址

题目描述

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"

思路

找出原来字符串和旋转后的字符串位置的关系:len = s.length();
0 ~ n - 1, n ~ len - 1;
0 ~ len - n - 1, len - n ~ len - 1;

代码及注释

class Solution {
    public String reverseLeftWords(String s, int n) {
        char[] str = s.toCharArray();
        char[] res = new char[str.length];
        int len = str.length;

        for (int i = 0; i < len; i++) {
            if (i < n) {
                res[len - n + i] = str[i];
            } else {
                res[i - n] = str[i];
            }
        }
        
        return new String(res);
    }
}

28. 实现 strStr()

题目地址

题目描述

实现 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

思路

利用KMP算法进行查找
利用BF算法进行查找

代码及注释

class Solution {
    public int strStr(String haystack, String needle) {
        int hayslen = haystack.length();
        int nelen = needle.length();
    
        //特殊情况排除
        if (nelen > hayslen)
            return -1;
        if (nelen == 0)
            return 0;

        char[] haysarr = haystack.toCharArray();
        char[] nearr = needle.toCharArray();
        
        return kmp(haysarr, hayslen, nearr, nelen);    
    }

    //needle: 模式串
    //haystack:文本串
    public int kmp(char[] haysarr, int hayslen, char[] nearr, int nelen){
        //获取 next 数组
        int[] next = next(nearr, nelen);
        int j = 0;//模式串下标
       
       for (int i = 0; i < hayslen; i++){
            while (j > 0 && haysarr[i] != nearr[j]){
                j = next[j - 1] + 1;

                if (nelen - j + i > hayslen)
                    return -1;
            }

            if (haysarr[i] == nearr[j])
                ++j;
            
            if (j == nelen){
                return i - j + 1;
            }
       }
       return -1;
    }
    

    //求解模式串数组
    public int[] next(char[] needle, int nelen){
        int[] next = new int[nelen];
        next[0] = -1;
        int k = -1;
        
        for (int i = 1; i < nelen; i++){
            while (k != -1 && needle[k + 1] != needle[i]){
                k = next[k];
            }
            if (needle[k + 1] == needle[i])
                ++k;
            next[i] = k;
        }
        return next;
    }
    // public  int[] next (char[] needle,int len) {
    //     //定义 next 数组
    //     int[] next = new int[len];
    //     // 初始化
    //     next[0] = -1;
    //     int k = -1;
    //     for (int i = 1; i < len; ++i) {
    //         //我们此时知道了 [0,i-1]的最长前后缀,但是k+1的指向的值和i不相同时,我们则需要回溯
    //         //因为 next[k]就时用来记录子串的最长公共前后缀的尾坐标(即长度)
    //         //就要找 k+1前一个元素在next数组里的值,即next[k+1]
    //         while (k != -1 && needle[k + 1] != needle[i]) {
    //             k = next[k];
    //         }
    //         // 相同情况,就是 k的下一位,和 i 相同时,此时我们已经知道 [0,i-1]的最长前后缀
    //         //然后 k - 1 又和 i 相同,最长前后缀加1,即可
    //         if (needle[k+1] == needle[i]) {
    //             ++k;
    //         }
    //         next[i] = k;

    //     }
    //     return next;
    // }

}
class Solution {
    //BF算法,若文本串当前位置与模式串位置不对应,则从文本串得下一个位置开始重新比较
    public int strStr(String haystack, String needle) {
        char[] hayarr = haystack.toCharArray();
        int haylen = hayarr.length;
        char[] nearr = needle.toCharArray();
        int nelen = nearr.length;

        if (haylen < nelen)
            return -1;
        if (nelen == 0)
            return 0;

        for (int i = 0; i < haylen; i++) {
            for (int j = 0; j < nelen; j++) {
                if (i + j >= haylen)
                    return -1;
                if (hayarr[i + j] != nearr[j])
                    break;
                if (j == nelen - 1)
                    return i;
            }
        }
        return -1;
    }
}

459. 重复的子字符串

题目地址

题目描述

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1:
输入: "abab"
输出: True
解释: 可由子字符串 "ab" 重复两次构成。
示例 2:
输入: "aba"
输出: False
示例 2:
输入: "abcabcabcabc"
输出: True
解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

思路

利用KMP算法中的模式串、next数组进行比较

代码及注释

class Solution {
    //采用模式串方法进行比较,需要了解模式串的意义
    public boolean repeatedSubstringPattern(String s) {
        char[] nearr = s.toCharArray();
        int nelen = nearr.length;

        int[] next = new int[nelen];
        next[0] = -1;
        int k = -1;

        for (int i = 1; i < nelen; i++) {
            while (k != -1 && nearr[k + 1] != nearr[i]) {
                k = next[k];
            }
            if (nearr[k + 1] == nearr[i])
                k++;
            next[i] = k;
        }

        if (next[nelen - 1] < 0)  
            return false;
        if (nelen % (nelen - next[nelen - 1] - 1) == 0)
            return true;
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值