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

翻转移位相关方法

右移

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;
    }
}
原文地址:https://www.cnblogs.com/buptleida/p/12991090.html