算法必刷系列之字符串

字符串

字符串虽然不是一种数据结构,在确是被经常使用的,与之相关的算法诸如字符串转换,计数、反转、压缩等问题是非常常见的

转换成小写字母

leetcode709
利用大小写字母Ascii码相差32对底层字符数组进行加减实现字符串转换

public String toLowerCase(String s) {
    int n = s.length();
    char[] chars = s.toCharArray();
    for (int i = 0; i < n; i++) {
        if (chars[i]>='A'&&chars[i]<='Z'){
            chars[i] += 32;
        }
    }
    String str = new String(chars);
    return str;
}

字符串转数字

leetcode8
按照题目要求,去掉空白字符,设置符号位,转换时,取数字,对原结果✖️10➕当前数字,注意溢出判断

public int myAtoi(String s) {
    int n = s.length();
    char[] chars = s.toCharArray();
    int sign = 1;
    int res = 0;
    int index = 0;
    while (index < n && chars[index] == ' ') {
        index++;
    }
    if (index == n) {
        return res;
    }
    if (chars[index] == '+') {
        index++;
    }else if (chars[index] == '-') {
        sign = -1;
        index++;
    }
    while (index < n) {
        if (chars[index] >= '0' && chars[index] <= '9') {
            if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && (chars[index]-'0') > Integer.MAX_VALUE % 10)) {
                return Integer.MAX_VALUE;
            }
            if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && (chars[index]-'0') > -(Integer.MIN_VALUE % 10))) {
                return Integer.MIN_VALUE;
            }
            res = res * 10 + sign * (chars[index] - '0');
            index++;
        } else {
            return res;
        }
    }
    return res;
}

原地反转字符串

leetcode344
使用双指针,对底层字符数组反转实现字符串的反转

public void reverseString(char[] s) {
    int left = 0;
    int right = s.length - 1;
    while (left < right){
        char c = s[left];
        s[left] = s[right];
        s[right] = c;
        left++;
        right--;
    }
}

K个一组反转字符串

leetcode541
与原地反转字符串基本相同,差别在于每次对2*k长度的子串进行操作,反转前K个,注意下标

public String reverseStr(String s, int k) {
    char[] chars = s.toCharArray();
    int length = s.length();
    for (int i = 0; i <= length; i+=2*k) {
        int left = i;
        int right = left + k-1;
        right = Math.min(right,length-1);
        swap(chars,left,right);
    }
    return new String(chars);
}

public void swap(char[] chars,int left,int right){
    while (left < right) {
        char c = chars[left];
        chars[left] = chars[right];
        chars[right] = c;
        left++;
        right--;
    }
}

仅反转英文字母

leetcode917
使用双指针,分别从左到右和从右到左寻找英文字母,找到后进行交换,直至两指针重合

public String reverseOnlyLetters(String s) {
    int left = 0;
    int right = s.length()-1;
    char[] chars = s.toCharArray();
    while (left < right) {
        while (left < right&&!isEnglishChar(chars[left])){
            left++;
        }
        while (left < right&&!isEnglishChar(chars[right])){
            right--;
        }
        if (left < right){
            char c = chars[left];
            chars[left] = chars[right];
            chars[right] = c;
            left++;
            right--;
        }
    }
    return new String(chars);
}

public boolean isEnglishChar(char c){
    if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){
        return true;
    }else {
        return false;
    }
}

反转字符串中的单词

leetcode151
首先对字符串进行反转,然后去掉字符串首尾多余空格,最后去掉单词之间的空格并反转单词

public String reverseWords(String s) {
    char[] chars = s.toCharArray();
    int len = s.length();
    reverse(chars, 0, len - 1);
    StringBuilder sb = new StringBuilder();
    int start = 0;
    while (start < len && chars[start] == ' ') {
        start++;
    }
    int end = len - 1;
    while (end > 0 && chars[end] == ' ') {
        end--;
    }
    int index = start;
    while (index <= end) {
        if (chars[index] != ' ') {
            sb.append(chars[index]);
        } else if (chars[index] == ' ' && chars[index - 1] != ' ') {
            sb.append(chars[index]);
        }
        index++;
    }
    s = sb.toString();
    chars = s.toCharArray();
    start = 0;
    index = 0;
    while (index < chars.length) {
    	if (chars[index] != ' ') {
            index++;
        } else {
            reverse(chars, start, index - 1);
            index++;
            start = index;
        }
    }
    reverse(chars,start,index-1);
    return new String(chars);
}

public void reverse(char[] chars, int left, int right) {
    while (left < right) {
        char c = chars[left];
        chars[left] = chars[right];
        chars[right] = c;
        left++;
        right--;
    }
}

判断回文串

leetcode125
首先将大写字符转换为小写字符,然后使用双指针进行判断

public boolean isPalindrome(String s) {
    StringBuilder sb = new StringBuilder();
    char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        if (chars[i] >= 'A' && chars[i] <= 'Z') {
            chars[i] += 32;
            sb.append(chars[i]);
        } else if (chars[i] >= 'a' && chars[i] <= 'z') {
            sb.append(chars[i]);
        } else if (chars[i] >= '0' && chars[i] <= '9') {
            sb.append(chars[i]);
        }
    }
    s = sb.toString();
    chars = s.toCharArray();
    int left = 0;
    int right = chars.length - 1;
    while (left < right) {
        if (chars[left]!=chars[right]){
            return false;
        }
        left++;
        right--;
    }
    return true;
}

字符串中的第一个唯一字符

leetcode387
使用HashMap存储每个字符出现的次数,之后遍历字符数组,寻找第一个唯一字符

public int firstUniqChar(String s) {
    Map<Character,Integer> map = new HashMap<>();
    char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length;i++){
        if (!map.containsKey(chars[i])){
            map.put(chars[i],1);
        }else {
            map.put(chars[i],map.get(chars[i])+1);
        }
    }
    for (int i = 0; i < chars.length;i++){
        if (map.get(chars[i])==1){
            return i;
        }
    }
    return -1;
}

判断两个字符串是否互为字符重排

leetcode242
设置一个长度为26的数组用来计数字符串中26个字符出现的次数,遍历第一个字符串时,对遍历到的每一字符对应的下标加一,遍历第二个字符串时,对遍历到的每一字符对应的下标减一,最后判断整个数组是否全为0

public boolean isAnagram(String s, String t) {
    if(s.length()!=t.length()){
        return false;
    }
    int[] res = new int[26];
    char[] chars = s.toCharArray();
    for (char c : chars){
        res[c-'a']++;
    }
    chars = t.toCharArray();
    for (char c : chars){
        res[c-'a']--;
    }
    for (int i=0;i<res.length;i++){
        if(res[i]!=0){
            return false;
        }
    }
    return true;
}

最长公共前缀

leetcode14
直观上来看,有竖直和水平两种方式,竖直方式是指我们依次比较所有字符串的第一个字符,如果相同,继续比较所有字符串的下一个字符,直至不相同或者有一个字符串遍历结束。水平方式是指可以先比较前两个字符的最长公共前缀,然后在比较前两个字符的最长公共前缀,与第三个字符的公共前缀,以此类推。同时,采用水平方式时,我们可以使用归并的方式,两两一组找最长公共前缀,然后再进行归并。

public String longestCommonPrefix(String[] strs) {
    StringBuilder sb = new StringBuilder();
    int len = strs.length;
    int n = strs[0].length();
    for (int i = 0; i < n; i++) {
        char c = strs[0].charAt(i);
        for (int j = 1; j < len; j++) {
            if (i >= strs[j].length() || strs[j].charAt(i) != c){
                return sb.toString();
            }
        }
        sb.append(c);
    }
    return sb.toString();
}
public String longestCommonPrefix(String[] strs) {
     int len = strs.length;
     if (len == 1) {
         return strs[0];
     }
     String prefix = longestCommonPrefix(strs[0], strs[1]);
     for (int i = 2; i < len; i++) {
         prefix = longestCommonPrefix(prefix, strs[i]);
     }
     return prefix;
 }

 public String longestCommonPrefix(String str1, String str2) {
     StringBuilder sb = new StringBuilder();
     int i = 0;
     int j = 0;
     while (i < str1.length() && j < str2.length()) {
         if(str1.charAt(i) == str2.charAt(j)){
             sb.append(str1.charAt(i));
             i++;
             j++;
         }else {
             return sb.toString();
         }
     }
     return sb.toString();
 }

压缩字符串

leetcode443
可以设置两个指针,用于寻找重复字符的起始和结束位置,同时在设置一个指针,用于设置写入位置,遍历字符数组,但个字符直接追加,重复字符,写入当前字符和出现次数,对于两位以上的出现次数,可以先逆序写入,然后再反转

public int compress(char[] chars) {
    int left = 0;
    int right = 0;
    int write = 0;
    while (right < chars.length) {
        while (right < chars.length && chars[right] == chars[left]) {
            right++;
        }
        if (right - left == 1) {
            chars[write++] = chars[left];
            left = right;
        } else {
            int count = right - left;
            chars[write++] = chars[left];
            int start = write;
            while (count != 0) {
                int num = count % 10;
                chars[write++] = (char) ('0' + num);
                count/=10;
            }
            reverse(chars, start, write - 1);
            left = right;
        }
    }
    return write;
}

public void reverse(char[] chars, int left, int right) {
    while (left < right) {
        char temp = chars[left];
        chars[left] = chars[right];
        chars[right] = temp;
        left++;
        right--;
    }
}

你可能感兴趣的:(算法)