[Leetcode][String]字符串相关题目汇总/分析/总结

目录

  1. Reverse

  2. SubString

  3. Convert

  4. Palindrome

  5. Parentheses

  6. Remove


基本String知识

  • char[] --> string: new String(c)
  • string --> char[]: s.toCharArray()
  • int --> string: Integer.toString(i)
  • str.split(" ") str.trim()
  • StringBuilder x = new StringBuilder();
    x.append(st + " "); x.toString() x.reverse()

#344 Reverse String
  • Sol 遍历
    public String reverseString(char[] c) {
        for(int i = 0, j = c.length-1; i<=j;i++, j--){
            char tmp = c[i];
            c[i] = c[j];
            c[j] = tmp;
        }
        return new String(c);
    }
#541 Reverse String II

Easy

  • Sol
    每隔k个字符就翻转k个字符,框架
ublic String reverseStr(String s, int k) {
    cha[] c = s.toCharArray();
    for(int i = 0; i < c.length; i += 2*k){
        if(i+k >= length){
            reverse(c, i, c.length-1);
        }else{
            reverse(c, i, i+k-1);
        }
    }
    return new String(c);
}

翻转

public void reverse(char[] s, int start, int end){
    while(start < end){
        char tmp = s[start];
        s[start] = s[end];
        s[end] = tmp;
        start++;
        end--;
    }
}
#557 Reverse Words in a String III

Easy

  • Sol
public String reverseWords(String s) {
        String[] word = s.split(" ");
        StringBuilder res = new StringBuilder();
        for(String si : word){
            res.append(reverse(si) + " ");
        }
        return  res.toString().trim();
}
public String reverse(String s){
    char[] c = s.toCharArray();
    for(int i = 0, j = c.length-1; i < j; i++, j--){
        char tmp = c[i];
        c[i] = c[j];
        c[j] = tmp;
    }
    return new String(c);
}

#345 Reverse Vowels of a String
  • Sol two pointer
public String reverseVowels(String s) {
        char[] c = s.toCharArray();
        for(int i = 0, j = c.length-1; i < j;){
            boolean i_b = (c[j] == 'a' || c[j] == 'e' || c[j] == 'i' || c[j] == 'o' || c[j] == 'u' || c[j] == 'A' || c[j] == 'E' || c[j] == 'I' || c[j] == 'O' || c[j] == 'U');
            boolean i_a = c[i] == 'a' || c[i] == 'e' || c[i] == 'i' || c[i] == 'o' || c[i] == 'u' || c[i] == 'A' || c[i] == 'E' || c[i] == 'I' || c[i] == 'O' || c[i] == 'U';
            if(i_a && i_b){
                char tmp = c[i];
                c[i] = c[j];
                c[j] = tmp;
                i++;
                j--;
            }
            if(!i_a){
                i++;
            }
            if(!i_b){
                j--;
            }
        }
        return new String(c);
}

【SubString】


#1016 Binary String With Substrings Representing 1 To N

int to binary string / substring check

  • Sol built in function
    int数的二进制表示Integer.toBinaryString(i)
    判断一个字符串中是否包含某一 子字符串 str.indexOf("china")!=-1
    public boolean queryString(String S, int N) {
        for(int i = 1; i <= N; i++){
            String tmp = Integer.toBinaryString(i);
            if(S.indexOf(tmp)==-1){return false;}
        }
        return true;
    }

#647 Palindromic Substrings

计算回文子字符串的个数

  • Sol 动态规划|对称性
    【对称轴】回文串都有某个对称轴(奇数个字符的串对称轴为最中间的字符。偶数不同,偶数的对称轴可以看做两个).
    【回文串的规律】当在回文串两端各加入两个相同的字符的时候,形成的新字符仍旧是回文串。
    int count = 0;
public int countSubstrings(String s) {
    for(int i = 0; i < s.length(); i++){
        help(s, i, i); //奇数
        help(s, i, i+1); //偶数
    }
    return count;
}
public void help(String s, int start, int end){
    while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
        count++;
        start--;
        end++;
    }
}

#5 Longest Palindromic Substring
  • Sol 类似647
class Solution {
    int max_length = 0;
    String res = "";
    public String longestPalindrome(String s) {
        for(int i = 0; i < s.length(); i++){
            help(s, i, i);
            help(s, i, i+1);
        }
        return res;
    }
    public void help(String s, int start, int end){
        while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
            int length = end - start + 1;
            if(length > max_length){
                max_length = length;
                if(end+1 < s.length()) res = s.substring(start, end+1);
                else res = s.substring(start);
            }
            start--;
            end++;
        }
    }
}

#3 Longest Substring Without Repeating Characters
  • Sol HashMap
    <字符,最后出现的位置>
    public int lengthOfLongestSubstring(String s) {
        Map<Character, Integer> m = new HashMap<>();
        int length = s.length();
        int i = 0, j = 0, res = 0;
        while(i < length && j < length){
            if(m.containsKey(s.charAt(j))){
                i = Math.max(i, m.get(s.charAt(j))+1);
            }
            res = Math.max(res, j - i+1);
            m.put(s.charAt(j), j);
            j++;
        }
        return res;
    }

#115 Distinct Subsequences
  • Sol DP
    dp[i][j]表示s[0...j]包含的subsequence个数(==T[0...i])
    Base:dp[0][j] = 1, dp[i][0] = 0
    Others:
    if(s[j] == T[i]) dp[i][j] = dp[i-1][j-1] + dp[i][j-1];
    else dp[i][j] = dp[i][j-1];
public int numDistinct(String s, String t) {
        int[][] dp = new int[t.length()+1][s.length()+1];
        for(int i = 0; i <= t.length(); i++){
            dp[i][0] = 0;
        }
        for(int j = 0; j <= s.length(); j++){
            dp[0][j] = 1;
        }
        for(int i = 1; i <= t.length(); i++){
            for(int j = 1; j <= s.length(); j++){
                if(s.charAt(j-1) == t.charAt(i-1)){
                    dp[i][j] = dp[i-1][j-1] + dp[i][j-1];
                }else{
                    dp[i][j] = dp[i][j-1];
                }
            }
        }
        return dp[t.length()][s.length()];
    }

#459 Repeated Substring Pattern
  • Sol One line
class Solution {
    public boolean repeatedSubstringPattern(String s) {
        return (s+s).substring(1, 2 * s.length() - 1).contains(s);
    }
}

【Convert】


#13 Roman to Integer
  • Sol map暂存
class Solution {
    public int romanToInt(String s) {
        Map<Character, Integer> roman = new HashMap<>();
        roman.put('I', 1);
        roman.put('V', 5);
        roman.put('X', 10);
        roman.put('L', 50);
        roman.put('C', 100);
        roman.put('D', 500);
        roman.put('M', 1000);
        if(s.length() == 0) return 0;
        int res = roman.get(s.charAt(0));
        for(int i = 1; i < s.length(); i++){
            if(roman.get(s.charAt(i)) > roman.get(s.charAt(i-1))){
                res = res - 2 * roman.get(s.charAt(i-1)) + roman.get(s.charAt(i));
            }else{
                res += roman.get(s.charAt(i));
            }
        }
        return res;
    }
}
#12 Integer to Roman
  • Sol 分情况考虑
    public String intToRoman(int num) {
        String res = "";
        if(num >= 1000){
            int a = num/1000;
            while(a!=0){
                res = res + "M";
                num = num - 1000;
                a--;
            }
        }
        if(num >= 900){
            res += "CM";
            num = num - 900;
        }
        if(num >= 500){
            res += "D";
            num = num - 500;
        }
        if(num >= 400){
            res += "CD";
            num = num - 400;
        }
        while(num >= 100){
            res += "C";
            num = num-100;
        }
        if(num >= 90){
            res += "XC";
            num = num - 90;
        }
        if(num >= 50){
            res += "L";
            num = num - 50;
        }
        if(num >= 40){
            res += "XL";
            num = num -40;
        }
        while(num >= 10){
            res += "X";
            num = num-10;
        }
        if(num >=9){
            res += "IX";
            num = num - 9;
        }
        if(num >= 5){
            res += "V";
            num = num-5;
        }
        if(num == 4){
            res += "IV";
            num = num-4;
        }
        while(num > 0){
            res += "I";
            num--;
        }
        return res;
    }
#273 Integer to English Words
  • Sol
    private final String[] belowTen = new String[] {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    private final String[] belowTwenty = new String[] {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
    private final String[] belowHundred = new String[] {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
    
    public String numberToWords(int num) {
        if (num == 0) return "Zero";
        return helper(num); 
    }
    
    private String helper(int num) {
        String result = new String();
        if (num < 10) result = belowTen[num];
        else if (num < 20) result = belowTwenty[num -10];
        else if (num < 100) result = belowHundred[num/10] + " " + helper(num % 10);
        else if (num < 1000) result = helper(num/100) + " Hundred " +  helper(num % 100);
        else if (num < 1000000) result = helper(num/1000) + " Thousand " +  helper(num % 1000);
        else if (num < 1000000000) result = helper(num/1000000) + " Million " +  helper(num % 1000000);
        else result = helper(num/1000000000) + " Billion " + helper(num % 1000000000);
        return result.trim();
    }

[Palindrome]

#125 Valid Palindrome
  • Sol
    str = str.replaceAll("[a-zA-Z^0-9]", "");提取字符串中的字母数字
    public boolean isPalindrome(String s) {
        String actual = s.replaceAll("[^A-Za-z0-9]", "").toLowerCase();
        String rev = new StringBuffer(actual).reverse().toString();
        return actual.equals(rev);
    }
#680 Valid Palindrome II
  • Sol Greedy
    收尾依次判断,只允许有一个不同。检测(i++,j)||(i,j--)
public boolean validPalindrome(String s) {
        char[] ch = s.toCharArray();
        int n = s.length();
        for(int i = 0, j = n-1; i < j; i++, j--){
            if(ch[i] != ch[j]){
                if(i + 1 == j) return true;
                return help(s.substring(i, j)) || help(s.substring(i+1, j+1));
                
            }
        }
        return true;
    }
    public boolean help(String s){
        for(int i = 0, j = s.length()-1; i < j; i++, j--){
            if(s.charAt(i) != s.charAt(j)) return false;
        }
        return true;
    }
#131 Palindrome Partitioning
  • Sol DP + DFS
    dp[i][j]表示s[i..j]是否是palindrome
    boolean[][] dp;
    List<List<String>> res;
    public List<List<String>> partition(String s) {
        int l = s.length();
        res = new ArrayList<>();
        dp = new boolean[l][l];
        dpCreate(s);
        dfs(0, s, new ArrayList<>());
        return res;
        
    }
    public void dfs(int index, String s, List<String> cur){
        if(index >= s.length()) {
            res.add(new ArrayList<>(cur));
            return;
        }
        for(int i = index; i < s.length(); i++){
            if(dp[index][i]){
                cur.add(s.substring(index, i+1));
                dfs(i+1, s, cur);
                cur.remove(cur.size()-1);
            }
        }
    }
    public void dpCreate(String s){
        int l = s.length();
        for(int i = 0; i < l; i++){
            for(int j = 0; j < l; j++){
                dp[i][j] = isParlindrome(s, i, j);
            }
        }
    }
    public boolean isParlindrome(String s, int i, int j){
        for(;i<j;i++,j--){
            if(s.charAt(i) != s.charAt(j)) return false;
        }
        return true;
    }
#132 Palindrome Partitioning II
  • Sol dp
    dp[i][j] 表示s[i...j]是都是palindrome
    num[i]最小分割数s[0...i]
class Solution {
    public int minCut(String s) {
        int l = s.length();
        char[] c = s.toCharArray();
        boolean[][] dp = new boolean[l][l];
        int[] num = new int[l];
        for(int j = 0; j < l; j++){
            int min = Integer.MAX_VALUE;
            for(int i = 0; i <= j; i++){
                if(c[i] == c[j] && (i+1>=j || dp[i+1][j-1])){
                    dp[i][j] = true;
                    min = (i == 0 ? 0 : Math.min(min, num[i-1] + 1));
                }
            }
            num[j] = min;
        }
        return num[l-1];
    }
}
#214 Shortest Palindrome
  • Sol1 Two pointer + Recursion
    i从左至右遍历,j右至左遍历
    Time O(n^2):worst case,每次递归,string分为两部分T(n)=T(n−2)+O(n)=
    O(n)+O(n−2)+O(n−4)+...+O(1) = O(n^2)
    Space O(n)存reverse string
class Solution {
    public String shortestPalindrome(String s) {
        int n = s.length();
        int i = 0;
        for(int j = n-1; j >= 0; j--){
            if(s.charAt(i) == s.charAt(j)) i++;
        }
        if(i == n) return s;
        String reverse = rev(s.substring(i));
        return reverse + shortestPalindrome(s.substring(0, i)) + s.substring(i);
    }
    public String rev(String s){
        char[] cc = s.toCharArray();
        int n = s.length();
        for(int i = 0, j = n-1; i < j; i++, j--){
            char c = cc[i];
            cc[i] = cc[j];
            cc[j] = c;
        }
        return new String(cc);
    }
}
  • Sol2 KMP
    Knuth-Morris-Pratt字符串查找算法,reverse(s) + '#' + s组成新string,找出新字符串前缀后缀相等的最大长度
class Solution {
    public String shortestPalindrome(String s) {
        String reverse = rev(s);
        String s_new = s + "#" + reverse;
        int len = s_new.length();
        int[] table = new int[len];
        for(int i = 1; i < len; i++) {
            int t = table[i-1];
            while(t > 0 && s_new.charAt(i) != s_new.charAt(t))
                t = table[t-1];
            if(s_new.charAt(i) == s_new.charAt(t))
                ++t;
            table[i] = t;
        }
        return reverse.substring(0, s.length()-table[len-1]) + s;
    }
    public String rev(String s){
        char[] cc = s.toCharArray();
        int n = s.length();
        for(int i = 0, j = n-1; i < j; i++, j--){
            char c = cc[i];
            cc[i] = cc[j];
            cc[j] = c;
        }
        return new String(cc);
    }
}

[Parentheses]

#20 Valid Parentheses
  • Sol Stack
    public boolean isValid(String s) {
        Stack<Character> st = new Stack<>();
        Map<Character, Character> map = new HashMap<>();
        map.put(')','(');
        map.put(']','[');
        map.put('}','{');
        for(int i = 0; i < s.length(); i++){
            // char c = s.charAt(i);
            if(s.charAt(i) == '(' || s.charAt(i) == '[' || s.charAt(i) == '{'){
                st.push(s.charAt(i));
            }else{
                if(st.isEmpty()) return false;
                char c = st.pop();
                if(c != map.get(s.charAt(i))) return false;
            }
        }
        return st.isEmpty();
    }
#22 Generate Parentheses
  • Sol (left) + right
    public List<String> generateParenthesis(int n) {
        List<String> res = new ArrayList<>();
        if(n==0){
            res.add("");
            return res;
        }
        for(int i = 0; i < n; i++){
            for(String left: generateParenthesis(i)){
                for(String right: generateParenthesis(n-i-1)){
                    res.add("("+left+")" + right);
                }
            }
        }
        return res;
    }
#32 Longest Valid Parentheses
  • Sol
    分别从左从右遍历string,计算left与right的值,一旦相等,更新max。
    public int longestValidParentheses(String s) {
        int left = 0, right = 0;
        int max = 0;
        // int start = 0;
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if(c == '('){
                left++;
            }
            if(c == ')') right++;
            if(left == right) max = Math.max(max, 2 * right);
            else if(right > left){
                right = 0;
                left = 0;
            }
        }
        right = 0;
        left = 0;
        for(int i = s.length()-1; i >= 0 ; i--){
            char c = s.charAt(i);
            if(c == '('){
                left++;
            }
            if(c == ')') right++;
            if(left == right) max = Math.max(max, 2 * right);
            else if(left > right){
                right = 0;
                left = 0;
            }
        }
        return max;
    }

Time complexity : O(n). Two traversals of the string.
Space complexity : O(1). Only two extra variables leftleft and rightright are needed.

#241 Different Ways to Add Parentheses
  • Sol DP
    map<String, list<Integer>>
    Map<String, List<Integer>> map = new HashMap<>();
    public List<Integer> diffWaysToCompute(String input) {
        if(map.containsKey(input)) return map.get(input);
        List<Integer> ans = new ArrayList<>();
        for(int i = 0; i < input.length(); i++){
            if(!Character.isDigit(input.charAt(i))){
                for(int a: diffWaysToCompute(input.substring(0,i))){
                    for(int b: diffWaysToCompute(input.substring(i+1))){
                        ans.add(input.charAt(i) == '+'?a+b:input.charAt(i) == '-'?a-b:a*b);
                    }
                }
            }
        }
        if(ans.isEmpty()) ans.add(Integer.parseInt(input));
        map.put(input, ans);
        return ans;
    }
#301 Remove Invalid Parentheses
  • Sol DFS
    public List<String> removeInvalidParentheses(String s) {
        List<String> res = new ArrayList<>();
        List<String> candidate = new ArrayList();
        Set<String> set = new HashSet<>();
        candidate.add(s);
        while(!candidate.isEmpty()){
            for(String p: candidate){
                if(isValid(p)) res.add(p);
            }
            if(!res.isEmpty()) return res;
            List<String> next = new ArrayList();
            for(String p: candidate){
                for(int i = 0; i < p.length(); i++){
                    if(p.charAt(i)!='(' && p.charAt(i)!=')') continue;
                    String ne = p.substring(0,i)+p.substring(i+1);
                    if(!set.contains(ne)){
                        next.add(ne);
                        set.add(ne);
                    }
                }
            }
            candidate = next;
        }
        return res;
    }
    public boolean isValid(String s){
        char[] c = s.toCharArray();
        int count = 0;
        for(int i = 0; i < c.length; i++){
            if(c[i]=='(') count++;
            if(c[i] == ')') count--;
            if(count < 0) return false;
        }
        return count==0;
    }

[Remove]

#316 Remove Duplicate Letters
  • Sol StringBuilder
    Space O(n)
    Time O(n)
class Solution {
    public String removeDuplicateLetters(String s) {
        StringBuilder sb = new StringBuilder();
        int[] count = new int[26];
        boolean[] visited = new boolean[26];
        for(char c: s.toCharArray()){
            count[c-'a']++;
        }
        for(char c: s.toCharArray()){
            count[c-'a']--;
            if(!visited[c-'a']){
                while(sb.length()>0 && c < sb.charAt(sb.length()-1) && count[sb.charAt(sb.length() - 1) - 'a'] > 0){
                    visited[sb.charAt(sb.length() - 1) - 'a'] = false;
                    sb.setLength(sb.length() - 1);
                }
                sb.append(c);
                visited[c-'a'] = true;
                
            }   
        }
        return sb.toString();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容