【数据结构与算法】字符串经典题

翻转移位相关方法

右移

s = "abcd123" k = 3
Return "123abcd"

先分别将“abcd”和“123”翻转,再将整个字符串翻转,即可得到结果。

单词翻转

s = "I am a student"
Return "student a am I"

先分别将每个单词翻转,最后将整个句子进行翻转即得到结果

有效的字母异位词

LeetCode:有效的字母异位词

题目描述:

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例:

输入: s = "anagram", t = "nagaram"
输出: true

思想:

1.使用26位计数器
因为本题仅限于小写英文字母,所以使用26位数组来进行标记即可
2.map.getOrDefault(ch, 0)
若不存在则返回0。使用这个函数可稍微优化代码,不会太臃肿。
3.遍历String的优化写法

//方法一
for(int i=0;i<s.length();++i){
      char c = s.charAt(i);
}
//方法二
for(char ch : s.toCharArray()){
}

方法二比方法一性能好不少

代码:

我自己的蠢方法,使用hashmap但是特别不优雅

class Solution {
    public boolean isAnagram(String s, String t) {
        HashMap<Character,Integer> map = new HashMap<>();
        Integer v;
        for(int i=0;i<s.length();++i){
            char c = s.charAt(i);
            if((v = map.get(c))!=null){
                map.put(c,v+1);
            }else{
                map.put(c,1);
            }
        }
        for(int i=0;i<t.length();++i){
            char c = t.charAt(i);
            if((v = map.get(c))!=null){
                if(v==1) 
                    map.remove(c);
                else
                    map.put(c,v-1);
            }else{
                return false;
            }
        }
        return map.isEmpty();
    }
}

更加优化的hashmap写法:

public boolean isAnagram_2(String s, String t) {
    Map<Character, Integer> map = new HashMap<>();
    for (char ch : s.toCharArray()) {
        map.put(ch, map.getOrDefault(ch, 0) + 1);
    }
    for (char ch : t.toCharArray()) {
        Integer count = map.get(ch);
        if (count == null) {
            return false;
        } else if (count > 1) {
            map.put(ch, count - 1);
        } else {
            map.remove(ch);
        }
    }
    return map.isEmpty();
}

本题的标准做法:

class Solution {
    public boolean isAnagram(String s, String t) {
        int[] arr = new int[26];
        for(char c:s.toCharArray()){
            arr[c-'a'] +=1;
        }
        for(char c:t.toCharArray()){
            arr[c-'a'] -=1;
        }
        for(int item : arr){
            if(item!=0) return false;
        }
        return true;
    }
}

最长回文串

LeetCode:最长回文串

题目描述:

给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。

在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

注意:
假设字符串的长度不会超过 1010。

示例:

输入:
"abccccdd"

输出:
7

解释:
我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

思想:

这题主要切入点容易想到:先用数组存储每个字母的出现次数。然后判断这个数组,仅满足多个偶数+一个奇数,才能组成回文数。

注意:

  • 存在大写字母,范围应该是65-122;
  • 最后判断是否存在奇数,可以用如下方法判断
if(res < s.length()) res++;

这样很巧妙。我一开始做法是在循环内部判断,那样会徒增复杂性

代码:

class Solution {
    public int longestPalindrome(String s) {
        int[] arr = new int[58];
        for(char c : s.toCharArray()){
            arr[c - 'A']++;
        }
        int res=0;
        //boolean b=false;
        for(int k : arr){
            //if(k%2 == 1) b = true;
            res += (k/2)*2;
        }
        if(res < s.length()) res++;
        return res;
    }
}

同构字符串

/五星/
LeetCode:同构字符串

题目描述:

给定两个字符串 s 和 t,判断它们是否是同构的。

如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。

所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。

示例:

输入: s = "paper", t = "title"
输出: true

思想:

这题我根本没想到切入点。看了答案才明白。
遍历到某个元素时,上一次出现该元素的位置,如果不相等就不同构,相等则继续遍历
想到这一点就好做了

代码:

class Solution {
    public boolean isIsomorphic(String s, String t) {
        int[] arr_s = new int[128];
        int[] arr_t = new int[128];
        for(int i=0;i<s.length();++i){
            char ch1=s.charAt(i),ch2=t.charAt(i);
            if(arr_s[ch1]!=arr_t[ch2]){
                return false;
            }
            arr_s[ch1]=arr_t[ch2]=i+1;
        }
        return true;
    }
}

回文子串

LeetCode:回文子串

题目描述:

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。

示例:

输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".

思想:

  • 回文串中心位置进行扩展,累计可以扩展的次数,遍历完所有中心位置之后,即得到结果;
  • 回文串有两种,奇数串和偶数串。可以通过low和high来控制;

代码:

class Solution {
    public int countSubstrings(String s) {
        int res = 0;
        char[] arr = s.toCharArray();
        for(int i=0;i<s.length();++i){
            res +=expandCount(arr,i,i);
            res +=expandCount(arr,i,i+1);
        }
        return res;
    }
    private int expandCount(char[] arr, int low, int high){
        int count = 0 ;
        while(low>-1&&high<arr.length){
            if(arr[low]!=arr[high])
                break;
            ++count;
            --low;
            ++high;

        }
        return count;
    }
}

替换空格

牛客:替换空格

题目描述:

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

思想:

如果按照正常思路,遍历字符串,碰到空格就插入“%20”,这样时间复杂度是O(n*n)。

正确思路:先遍历一遍字符串,长度扩展为最终长度,然后使用双指针从后向前遍历,逐个字符赋值,碰到空格特殊处理,直到遍历完整个字符串。时间复杂度为O(n)。

代码:

public class Solution {
    public String replaceSpace(StringBuffer str) {
        int lenRaw = str.length();
        for(int i=0;i<lenRaw;++i){
            if(str.charAt(i)==' '){
                str.append("  ");
            }
        }
        int pos=lenRaw-1;
        for(int i=str.length()-1;i>=0;--i){
            char ch = str.charAt(pos--);
            if(ch!=' '){
                str.setCharAt(i,ch);
                continue;
            }
            str.setCharAt(i--,'0');
            str.setCharAt(i--,'2');
            str.setCharAt(i,'%');
        }
        return str.toString();
    }
}
posted @ 2020-05-30 10:04  数小钱钱的种花兔  阅读(298)  评论(0编辑  收藏  举报