LeetCode---String

Count and Say
思路:递归求出n - 1时的字符串,然后双指针算出每个字符的次数,拼接在结果后面

public String countAndSay(int n) {
    if(n == 1) return "1";
    String front = countAndSay(n - 1);
    
    int i = 0;
    int j = 0;
    String res = "";
    int count = 0;
    
    while(j < front.length()){
        while(j < front.length() && front.charAt(i) == front.charAt(j)){
            count++;
            j++;
        }
        res = res.concat(String.valueOf(count));
        res += (front.charAt(i));
        count = 0;
        i = j;
    }
    return res;
}
Add Binary
思路:当string有值时,就将数值加起来,该位置的结果为sum % 2,利用carry = sum / 2作为下一次的结果初值,拼接起来,最后翻转string

public String addBinary(String a, String b) {
    StringBuilder sb = new StringBuilder();
    int i = a.length() - 1, j = b.length() -1, carry = 0;
    while (i >= 0 || j >= 0) {
        int sum = carry;
        if (j >= 0) sum += b.charAt(j--) - '0';
        if (i >= 0) sum += a.charAt(i--) - '0';
        sb.append(sum % 2);
        carry = sum / 2;
    }
    if (carry != 0) sb.append(carry);
    return sb.reverse().toString();
}
Mini Parser
思路:
If encounters '[', push current NestedInteger to stack and start a new one.
If encounters ']', end current NestedInteger and pop a NestedInteger from stack to continue.
If encounters ',', append a new number to curr NestedInteger, if this comma is not right after a brackets.
Update index l and r, where l shall point to the start of a integer substring, while r shall points to the end+1 of substring.

public NestedInteger deserialize(String s) {
    if(s == null || s.isEmpty()) return null;
    if(s.charAt(0) != '[') return new NestedInteger(Integer.parseInt(s));
    
    int l = 0;
    NestedInteger cur = null;
    Stack<NestedInteger> stack = new Stack<NestedInteger>();
    for(int r = 0; r < s.length(); r++){
        if(s.charAt(r) == '['){
            if(cur != null) stack.push(cur);
            cur = new NestedInteger();
            l = r + 1;
        }
        else if(s.charAt(r) == ','){
            if(s.charAt(r - 1) != ']'){
                String num = s.substring(l,r);
                cur.add(new NestedInteger(Integer.parseInt(num)));   
            }
            l = r + 1;
        }
        else if(s.charAt(r) == ']'){
            String num = s.substring(l,r);
            if(!num.isEmpty()){
                cur.add(new NestedInteger(Integer.parseInt(num)));
            }
            if(!stack.isEmpty()){
                NestedInteger p = stack.pop();
                p.add(cur);
                cur = p;
            }
            l = r + 1;
        }
    }
    return cur;
}
Group Anagrams
思路:将每个字符串变成字符数组以后排序,将排序后相同的字符串放在一个list,形成最终结果
主要学习toCharArray Arrays.sort String.valueOf map.values()

public List<List<String>> groupAnagrams(String[] strs) {
    List<List<String>> res = new ArrayList<List<String>>();
    if(strs.length == 0 || strs == null) return res;
    
    HashMap<String,ArrayList<String>> map = new HashMap<String,ArrayList<String>>();
    for(int i = 0; i < strs.length; i++){
        char[] c = strs[i].toCharArray();
        Arrays.sort(c);
        if(map.containsKey(String.valueOf(c))){
            ArrayList<String> list = map.get(String.valueOf(c));
            list.add(strs[i]);
        }
        else{
            ArrayList<String> list = new ArrayList<String>();
            list.add(strs[i]);
            map.put(String.valueOf(c),list);
        }
    }
    return new ArrayList<List<String>>(map.values());
}
17. Letter Combinations of a Phone Number
思路:建立数字和字符串的对应关系,回溯  

public List<String> letterCombinations(String digits) {
    HashMap<Integer,String> map = new HashMap<Integer,String>();
    map.put(2,"abc");
    map.put(3,"def");
    map.put(4,"ghi");
    map.put(5,"jkl");
    map.put(6,"mno");
    map.put(7,"pqrs");
    map.put(8,"tuv");
    map.put(9,"wxyz");
    
    ArrayList<String> list = new ArrayList<String>();
    for(int i = 0; i < digits.length(); i++){
        list.add(map.get(digits.charAt(i) - '0'));
    }
    
    List<String> res = new ArrayList<String>();
    if(digits.equals("")) return res;
    dfs(res,"",list,0);
    return res;
}

public void dfs(List<String> res,String ans,ArrayList<String> list,int start){
    if(start == list.size()){
        res.add(ans);
        return;
    }
    
    for(int i = start; i < list.size(); i++){
        String s = list.get(i);
        for(int j = 0; j < s.length(); j++){
            ans += s.charAt(j);
            dfs(res,ans,list,i + 1);
            ans = ans.substring(0,ans.length() - 1);
        }
        //强制返回第一层,否则在最后一次回溯结束以后会继续循环i++
        return;
    }
}
Basic Calculator II
思路:先判断第一个数的符号和开始下标,然后依次往后循环,若是数字则算出num,若是+-则入栈,是*/则直接计算后入栈,别忘了将最后一个num入栈,最后将栈中数字相加  

public int calculate(String s) {
    if(s == null || s.isEmpty()) return 0;
    Stack<Integer> stack = new Stack<Integer>();
    int num = 0;
    //判断第一个数是正数还是负数
    char sign = (s.charAt(0) == '-') ? '-' : '+';
    int i = (sign == '-') ? 1 : 0;
    while(i < s.length()){
        if(Character.isDigit(s.charAt(i))){
            num = num * 10 + (s.charAt(i) - '0');
        }
        //只有一个数的情况
        if((!Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ') || i == s.length() - 1){
            if(sign == '+'){
                stack.push(num);
            }
            else if(sign == '-'){
                stack.push(-num);
            }
            else if(sign == '*'){
                stack.push(stack.pop() * num);
            }
            else if(sign == '/'){
                stack.push(stack.pop() / num);
            }
            sign = s.charAt(i);
            num = 0;
        }
        i++;
    }
    int res = 0;
    for(int j : stack){
        res += j;
    }
    return res;
}
**91. Decode Ways
思路:用数组dp[n + 1]表示第几位的不同解码数,判断当前位数字范围和前两位数字范围,动态规划

public int numDecodings(String s) {
    if(s == null || s.isEmpty()) return 0;
    int[] dp = new int[s.length() + 1];
    dp[0] = 1;
    dp[1] = (s.charAt(0) == '0') ? 0 : 1;
    
    for(int i = 2; i < s.length() + 1; i++){
        int first = Integer.parseInt(s.substring(i - 1,i));
        int second = Integer.parseInt(s.substring(i - 2,i));
        if(first >= 1 && first <= 9) dp[i] += dp[i - 1];
        if(second >= 10 && second <= 26) dp[i] += dp[i - 2];
    }
    return dp[s.length()];
}
**93. Restore IP Addresses
思路:回溯

public List<String> restoreIpAddresses(String s) {
    List<String> res = new ArrayList<String>();
    if(s == null || s.isEmpty()) return res;
    dfs(res,s,"",0,0);
    return res;
}

//ans表示每个符合要求的solution,idx用来截取每段地址,i表示每段地址的长度,count表示第几段
public void dfs(List<String> res,String s,String ans,int idx,int count){
    if(count > 4) return;
    if(count == 4 && idx == s.length()){
        res.add(ans);
        return;
    }
    
    for(int i = 1; i < 4; i++){
        if(idx + i > s.length()) break;
        String str = s.substring(idx,idx + i);
        if((str.charAt(0) == '0' && str.length() != 1) || (str.length() == 3 && Integer.parseInt(str) > 255)) continue;
        dfs(res,s,ans + str + ((count == 3) ? "" : "."),idx + i,count + 1);
    }
}
**214. Shortest Palindrome
public String shortestPalindrome(String s) {
    int j = 0;
    for(int i = s.length() - 1; i >= 0; i--){
        if(s.charAt(i) == s.charAt(j)) j++;
    }
    if(j == s.length()) return s;
    String str = s.substring(j);
    return new StringBuffer(str).reverse().toString() + shortestPalindrome(s.substring(0,j)) + str;
}
**76. Minimum Window Substring
思路:用map存储字符和个数,利用count来控制已经出现的字符个数,然后滑动窗口计算长度

public String minWindow(String s, String t) {
    HashMap<Character,Integer> map = new HashMap<Character,Integer>();
    for(int i = 0; i < t.length(); i++){
        if(map.containsKey(t.charAt(i))){
            map.put(t.charAt(i),map.get(t.charAt(i)) + 1);
        }
        else{
            map.put(t.charAt(i),1);
        }
    }
    
    int left = 0;
    int minLeft = 0;
    int minLen = Integer.MAX_VALUE;
    int count = 0;
    //map中的value值大于0说明还有字符没找到,小于等于0说明窗口已经包含
    for(int right = 0; right < s.length(); right++){
        if(map.containsKey(s.charAt(right))){
            map.put(s.charAt(right),map.get(s.charAt(right)) - 1);
            if(map.get(s.charAt(right)) >= 0) count++;
        }
        
        while(count == t.length()){
            if(minLen > right - left + 1){
                minLen = right - left + 1;
                minLeft = left;
            }
            if(map.containsKey(s.charAt(left))){
                map.put(s.charAt(left),map.get(s.charAt(left)) + 1);
                if(map.get(s.charAt(left)) > 0) count--;
            }
            left++;
        }
    }
    return (minLen == Integer.MAX_VALUE) ? "" : s.substring(minLeft,minLeft + minLen);
}
总结
344:reverse string
8. String to Integer (atoi):1.判空;2.除空格;3.定符号;4.算数值,判越界
383. Ransom Note:抽屉法,先将字母一个个放入,然后一个个拿出,若全都能拿出,则返回true
14. Longest Common Prefix:找出所有字符串中长度最短的,然后判断是否为所有串公共前缀,循环--
345. Reverse Vowels of a String:双指针,分别从前后找到元音字母(大小写),然后交换
20. Valid Parentheses:利用栈,若是左括号则入栈,是右括号则判断栈是否为空,然后判断栈顶元素是否为左括号,是则出栈,最后看栈是否为空
434. Number of Segments in a String:先除首尾空格后按空格分隔,结果为分隔后数组长度
28. Implement strStr():indexOf
58. Length of Last Word:利用trim()和lastIndexOf()或者trim()和split()
468. Validate IP Address:分隔以后判断,考虑全面就行
151. Reverse Words in a String:分隔以后翻转列表
22. Generate Parentheses:利用left和right记录左括号数和右括号数,当都为0时即一个solution
273. Integer to English Words:利用三个字符串数组,递归拼接最终结果
训练
459. Repeated Substring Pattern:Repeated Substring的长度最多为原串的一半,则循环查找符合长度要求的串,看是不是Repeated Substring
**6. ZigZag Conversion:一行一行连接,找到每行下标的规律
13. Roman to Integer:用两个指针分别表示当前指向和前一个指向,注意I V X L C D M,VX前只能是I,LC前只能是X,DM前只能是C
12. Integer to Roman:利用数组列出所有组合,然后依次减,连接所有字符串
165. Compare Version Numbers:先按.分隔,然后使用巧妙的方法使两个数组长度对齐,最后利用Integer的compareTo方法得到结果
125. Valid Palindrome:使用正则表达式先将非字母数字的字符替换成“”,然后利用reverse判断
**43. Multiply Strings:s1[i] * s2[j]的结果在最终结果的res[i + j]和res[i + j + 1]位,最后去除首位的0即可
71. Simplify Path:利用栈,通过/分隔,注意用法ArrayList<String> list = new ArrayList<String>(stack);   "/" + String.join("/",list)
3. Longest Substring Without Repeating Characters:利用map存储字符以及下标,利用双指针控制字符串首尾位置
**5. Longest Palindromic Substring:分两种情况,考虑结果位数是奇数和偶数,分别求解
**32. Longest Valid Parentheses:利用栈,将合理的括号都提取出来,只留下分隔的字符,然后依次计算间隔取最大,注意应该入栈字符下标,要不然不好计算间隔长度
**87. Scramble String:先判断长度和字符是否完全一致,若符合条件则要么左右子树完全一致,要么左右子树完全翻转,递归求解
**72. Edit Distance:构造int[m + 1][n + 1]表示长度为i的字符串到长度为j的字符串需要多少步,初始化以后,若字符相等则f(i,j) = f(i - 1,j - 1),不相等则在插入、删除和替换三者大的那个加一即可
提示
String常用函数:
	charAt compareTo contains concat endsWith equals indexOf(int/string) lastIndexOf(int/string) length() matches(regex) replace(char old, char new) split startsWith substring(begin, end) toCharArray toLowerCase/toUpperCase trim()
StringBuffer常用函数:
	charAt indexOf lastIndexOf length() substring
	append delete reverse setCharAt toString
	因此需要删除、翻转、set操作应该先将string转化为StringBuffer
Arrays常用函数:
	sort copyOfRange(origin[],from,to)包前不包后 asList:list.add(new ArrayList<Integer>(Arrays.asList(1,2,3)));

int string char char[] Array之间的常用用法:
int->string:String.valueOf(int)    int->char:(char)(int + 48)
string->int:Integer.parseInt(string)   string->char[]:string.toCharArray()
char->int:char - '0'/Character.getNumericValue(char)   char->string:String.valueOf(char)
char[]->string:String.valueOf(char[])
Arrays.sort(char[])
原文地址:https://www.cnblogs.com/LeonNew/p/6202685.html