LeetCode刷题笔记之字符串

一、反转字符串

1. 344【反转字符串】

  • **题目:**编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
  • 代码:
class Solution {
    public void reverseString(char[] s) {
        //交换两个数:a^=b; b^=a; a^=b;
        //双指针法反转数组
        int left = 0;
        int right = s.length-1;
        while (left < right){
            s[left] ^= s[right];
            s[right] ^= s[left];
            s[left] ^= s[right];
            left++;
            right--;
        }
    }
}

2. 541【反转字符串II】

  • 题目: 给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
    • 如果剩余字符少于 k 个,则将剩余字符全部反转。
    • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
  • 代码:
class Solution {
    public String reverseStr(String s, int k) {
        char[] charArr = s.toCharArray();
        //不要用k做除数,因为k可能为0
        for (int i = 0; i < s.length(); i+=2*k) {
            if(i + k > s.length()){
                reverse(charArr,i,s.length()-1);
                break;
            }
            reverse(charArr,i,i+k-1);
        }
        String str = String.valueOf(charArr);
        return str;
    }
    public void reverse(char[] s,int left,int right) {
        while (left < right){
            s[left] ^= s[right];
            s[right] ^= s[left];
            s[left] ^= s[right];
            left++;
            right--;
        }
    }
}

3. 151【翻转字符串里的单词】

  • 题目: 给你一个字符串 s ,请你反转字符串中单词的顺序。单词是由非空格字符组成的字符串。s中使用至少一个空格将字符串中的单词分隔开。返回单词顺序颠倒且单词之间用单个空格连接的结果字符串。
    注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
  • 代码:
class Solution {
    public String reverseWords(String s) {
        //去除多余的空格,先去除首尾空格,使用while
        StringBuilder sb = new StringBuilder();
        int left = 0;
        int right = s.length()-1;
        while (s.charAt(left) == ' '){
            left++;
        }
        while (s.charAt(right) == ' '){
            right--;
        }
        for (int i = left; i < right+1; i++) {
            if(s.charAt(i)==' ' && s.charAt(i-1)==' '){
                continue;
            }
            sb.append(s.charAt(i));
        }
        //反转整个字符串
        int len = sb.length();
        char[] charArr = new char[len];

        for (int i = 0; i < len; i++) {
            charArr[i] = sb.charAt(len-i-1);
        }
        //将每个单词反转回正常顺序
        left = 0;
        for (int i = 0; i < len; i++) {
            if(charArr[i] == ' '){
                reverse(charArr,left,i-1);
                left = i+1;
            }
            if(i == len-1){
                reverse(charArr,left,i);
            }
        }
        String str = String.valueOf(charArr);
        return str;
    }
    public void reverse(char[] s,int left,int right) {
        while (left < right){
            s[left] ^= s[right];
            s[right] ^= s[left];
            s[left] ^= s[right];
            left++;
            right--;
        }
    }
}

4. 卡码网【右旋字符串】

  • 题目: 字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。
    例如,对于输入字符串 “abcdefg” 和整数 2,函数应该将其转换为 “fgabcde”。
    输入:输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。
    输出:输出共一行,为进行了右旋转操作后的字符串。
  • 代码:
import java.util.Scanner;
public void reverse(char[] s,int left,int right) {
  while (left < right){
        s[left] ^= s[right];
        s[right] ^= s[left];
        s[left] ^= s[right];
        left++;
        right--;
    }
}
public void rightReverse(){
    Scanner scan = new Scanner(System.in);
    String s = scan.next();
    int k = scan.nextInt();

    //右旋k,代表字符串最后k个字符会移动到前k个,前n-k个字符会移动到后n-k的位置
    //将该字符串看成两个子串,分别由前n-k个字符,后k个字符组成
    //反转整个字符串,在分别对两个子串进行反转
    char[] charArr = s.toCharArray();
    reverse(charArr,0,s.length()-1);
    reverse(charArr,0,k-1);
    reverse(charArr,k,s.length()-1);

    System.out.println(String.valueOf(charArr));
}

二、替换字符串中某些字符

1. 卡码网【替换数字】

  • 题目: 给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。
    例如,对于输入字符串 “a1b2c3”,函数应该将其转换为 “anumberbnumbercnumber”。
    对于输入字符串 “a5b”,函数应该将其转换为 “anumberb”
    输入:一个字符串 s,s 仅包含小写字母和数字字符。
    输出:打印一个新的字符串,其中每个数字字符都被替换为了number
    样例输入:a1b2c3
    样例输出:anumberbnumbercnumber
    数据范围:1 <= s.length < 10000。
  • 代码:
import java.util.Scanner;
public void replaceDigit(){
	Scanner scan = new Scanner(System.in);
	String s = scan.next();
	StringBuilder sb = new StringBuilder();
	for (int i = 0; i < s.length(); i++) {
	    //判断是否为数字:Character.isDigit(s.charAt(i));
	    if(s.charAt(i)>='0' && s.charAt(i)<='9'){
	        sb.append("number");
	    }else{
	        sb.append(s.charAt(i));
	    }
	}
	scan.close();
	System.out.println(sb);
}

三、KMP算法

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

  • 题目: 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。
    示例 1:
    输入:haystack = “sadbutsad”, needle = “sad”
    输出:0
    解释:“sad” 在下标 0 和 6 处匹配。第一个匹配项的下标是 0 ,所以返回 0 。
  • 代码:
class Solution {
    public int strStr(String haystack, String needle) {
        //如果needle的长度为0,则返回0
        if(needle.length() == 0){
            return 0;
        }
        //使用KMP算法进行匹配字符串,原理是找到最长相等前后缀,使用next数组记录最长相等前缀的下标
        //KMP算法求next数组,初始化next数组,next[0]=0
        int[] next = new int[needle.length()];
        int j = 0;//j表示最长前缀的末尾,初始值为0
        next[j] = 0;
        //i表示后缀的末尾,初始值为1
        for (int i = 1; i < needle.length(); i++) {
            //判断前缀的末尾是否与后缀的末尾相等
            //不相等,则查看当前最长前缀的最长前缀值,即更改j的值,直到j==0或相等为止
            while (j>0 && needle.charAt(i)!=needle.charAt(j)){
                j = next[j-1];
            }
            //相等,则i和j均后移一位,比较下一个位置是否相等
            if(needle.charAt(i) == needle.charAt(j)){
                ++j;
            }
            //为当前位置的next赋值
            next[i] = j;
        }
        j = 0;
        for (int i = 0; i < haystack.length(); i++) {
            while (j>0 && haystack.charAt(i)!=needle.charAt(j)){
                j = next[j-1];
            }
            if(haystack.charAt(i) == needle.charAt(j)){
                j++;
            }
            if(j == needle.length()){
                return i-needle.length()+1;
            }
        }

        return -1;
    }
}

2. 459【重复的子字符串】

  • 题目: 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
  • 代码:
class Solution {
    public boolean repeatedSubstringPattern(String s) {
        //如果s是由某一子串重复组成,则它的最长相等前缀与s的长度相差一个重复子串的长度
        //s的长度一定可以被重复子串的长度整除
        //KMP求最长相等前缀,next数组的最后一项不为0,则有相等前后缀
        //最长相等前后缀的长度为next数组的最后一项值

        //求next数组
        int len = s.length();
        int[] next = new int[len];
        int j = 0;
        next[j] = 0;
        for (int i = 1; i < len; i++) {
            while (j>0 && s.charAt(i)!=s.charAt(j)){
                j = next[j-1];
            }
            if(s.charAt(i) == s.charAt(j)){
                j++;
            }
            next[i] = j;
        }

        //判断是否有相等前后缀
        if(next[len-1]>0 && len%(len-next[len-1])==0){
            return true;
        }
        return false;
    }
}

你可能感兴趣的:(课程复习,leetcode,笔记,算法)