LeetCode字符串

面试01.03 URL化(空格替换)

题目

分析

1. string.substring(x,y).replaceAll("x","y"):
2. StringBuilder.append("X")
3. 字符数组char[]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class URLhua {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
int length=input.nextInt();
System.out.println(replaceSpaces(s,length));
}

public static char[] replaceSpaces(String s, int length) {
char[] a=new char[length*3];
int i=0;
char c;
for(int j=0;j<length;j++) { //控制长度length
c=s.charAt(j); //获取字符串的当前字符
if (c == ' '){ //如果当前位置为空
a[i++] = '%'; //空替换为 %20
a[i++] = '2';
a[i++] = '0';
}else{
a[i++] =c; //不为空就它填进去
}
}
return a;
}

}

结果


面试01.04 回文排列(字符出现次数)

题目

分析

每个字符出现的次数为偶数 / 有且只有一个字符出现的次数为奇数

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class HuiWenPaiLie {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.next();
System.out.println(canPermutePalindrome(s));
}

public static boolean canPermutePalindrome(String s) {
Set<Character> set = new HashSet<>();
for(char c:s.toCharArray()) {
if (!set.add(c)) { //如果c字符不能添加就说明是重复出现
set.remove(c); //移除第一次添加的c字符
}
}
return set.size()<=1; //看最后是不是只有那个奇数的一个/全是偶数的被移除了
}

}

结果


面试01.05 一次编辑(统计变换次数)

题目

分析

1. |a.length-b.length|>1 说明不可能通过一次编译完成
2. 两层循环如果到了不相等的位置
3. 判断是前面的多一个还是后面的多一个
    3.1 前面多 后面的字符串需要多添一个(j--)
    3.2 后面多 前面的字符串需要多添一个(i--)
    3.3 最后一次执行count--
4. 最后我们通过判断count变化几次来判断

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class YiCiBianYi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String first=input.nextLine();
String second=input.nextLine();
System.out.println(oneEditAway(first,second));
}

public static boolean oneEditAway(String first, String second) {
int len=first.length()-second.length();
if(len>1||len<-1){
return false; //长度差大于1 肯定不可能
}
int count=1;
for(int i=0,j=0;i<first.length()&&j< second.length();i++,j++){
if(first.charAt(i)!=second.charAt(j)){
if(len==1){ //前面的多一个
j--; //second要不要添加一个字符
}else if(len==-1){ //后面的多一个
i--; //first要不要添加一个字符
}
count--; //反正不相等肯定要操作一次 count--变成0
}
if(count<0){ //最多能改一次(最大也是0)
return false;
}
}
return true;
}

}

结果


面试01.06 字符串压缩(StringBuilder添加)

题目

分析

1. 使用StringBuilder字符串对象sb
2. 步骤:
    2.1 当前字符添加进去
    2.2 计算出现次数
        2.2.1 相邻相等计数器++
        2.2.2 相邻不相等直接break
    2.3 将重复次数添加进去
    2.4 返回长度最小的结果(s/sb)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class StringYaSuo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
System.out.println(compressString(s));

}

public static String compressString(String s) {
StringBuilder sb=new StringBuilder(); //新建sb对象
for(int i=0;i<s.length();i++){
int count=1; //记录重复出现次数
char c=s.charAt(i); //获取当前字符串的字符
sb.append(c); //将其加入到sb对象
for(int j=i+1;j<s.length();j++){ //找后面的用于判断是否相同count++?
char c2=s.charAt(j); //获取当前字符串的字符(c之后一位)
if(c==c2){ //如果前后一样 就count++
count++;
i++; //成功了就一定要记得往后推!!!!!!!!
}else{
break; //如果不相等 说明重复结束了
}
}
sb.append(count); //循环之后我们将重复次数加进去
}
return s.length()>sb.length()?sb.toString():s;
}

}

结果


面试01.09 字符串轮转(contains判断是否包含子串)

题目

分析

1. 原来的s1重复添加(S1+=S1;)
2. 使用String.contains(s2); //判断现在的s1里面有没有s2

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class StringLunZhuan {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s1=input.nextLine();
String s2=input.nextLine();
System.out.println(isFlipedString(s1,s2));
}

public static boolean isFlipedString(String s1, String s2) {
if(s1.length()!=s2.length()){ //如果不一样长肯定有问题
return false;
}
if(s1.equals(s2)){ //如果是aaa这种肯定是正确
return true;
}
s1+=s1; //将s1重复添加一次(abc+abc=abcabc)
return s1.contains(s2); //查找s1里面有没有s2
}

}

结果


面试05.02 二进制转字符串(StringBuilder添加)

题目

分析

1. 只需要考虑小数点后的乘2问题
2. 思路:每次乘2将整数部分按需存进去直到乘2为0

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ErjinzhizhuanString {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Double num=input.nextDouble();
System.out.println(printBin(num));
}

public static String printBin(double num) {
if(num <= 0 || num >= 1){
return "ERROR";
}
StringBuilder sb = new StringBuilder(); //用于粘贴结果
sb.append("0."); //因为介于0-1之间
while(num != 0){
num *= 2;
sb.append(num - 1 >= 0 ? 1 : 0);
if(num >= 1){
num --;
}
if(sb.length() > 32){
return "ERROR";
}
}
return sb.toString();
}

}

结果


面试08.09 括号(深度优先遍历(回溯))

题目

分析

https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/

深度优先遍历(回溯):

  • 以n=2为例:

画图以后,可以分析出的结论:

1. 当前左右括号都有大于 00 个可以使用的时候,才产生分支;

2. 产生左分支的时候,只看当前是否还有左括号可以使用;

3. 产生右分支的时候,还受到左分支的限制,右边剩余可以使用的括号数量一定得在严格大于左边剩余的数量的时候,才可以产生分支;

4. 在左边和右边剩余的括号数都等于 00 的时候结算。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class KuoHao {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(generateParenthesis(n)); //调用方法
}

public static List<String> generateParenthesis(int n) {
List<String> res=new ArrayList();
//特定判断
if (n == 0) {
return res;
}
//执行深度优先遍历
dfs("",n,n,res);

return res;
}

/**
* @param curStr 当前递归得到的结果
* @param left 左括号还有几个可以使用
* @param right 右括号还有几个可以使用
* @param res 结果集
*/
private static void dfs(String curStr, int left, int right, List<String> res) {
//因为每一次尝试,都使用新的字符串变量,所以无需回溯
if(left==0&&right==0){
res.add(curStr); // 在递归终止的时候,直接把它添加到结果集即可
return ; //void不需要返回
}

// 剪枝(左<右就符合左边用的多这样不需要剪枝)
if (left > right) {
return; //void不需要返回
}

//左分支(左边用了一个“(”)
if(left>0){
dfs(curStr+"(", left-1, right, res);
}

//右分支(右边用了一个“)”)
if(right>0){
dfs(curStr+")", left, right-1, res);
}

}

}

结果


面试16.18 模式匹配(KMP)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Solution {
private char[] global_pattern, global_value;
private int value_len;

public boolean patternMatching(String pattern, String value) {
value_len = value.length();
if (value_len == 0) return pattern.length() < 2;
global_pattern = pattern.toCharArray();
global_value = value.toCharArray();
int pattern_len = pattern.length();
if (pattern_len == 0) return false;
int count_a = 0, count_b = 0;
for (char ch : global_pattern) {
if (ch == 'a') ++count_a;
else ++count_b;
}
if (count_a == 0) return single_count(count_b);
if (count_b == 0) return single_count(count_a);
return count_a < count_b ? muti_count(count_a, count_b, 'a') : muti_count(count_b, count_a, 'b');
}

private boolean single_count(int count) {
if (value_len % count != 0) return false;
String base = new String(global_value, 0, value_len / count);
int base_len = base.length(), idx = base_len;
while (idx < value_len) {
if (!check(base, idx)) return false;
idx += base_len;
}
return true;
}

private boolean muti_count(int small_count, int big_count, char small_ch) {
int small_sum = 0;
search:
while ((small_sum += small_count) < value_len) {
int remain = value_len - small_sum;
if (remain % big_count != 0) continue;
int big_len = remain / big_count, small_len = small_sum / small_count;
String small_str = null, big_str = null;
int value_idx = 0;
for (char cur_ch : global_pattern) {
if (cur_ch == small_ch) {
if (small_str == null)
small_str = new String(global_value, value_idx, small_len);
else if (!check(small_str, value_idx)) continue search;
value_idx += small_len;
} else {
if (big_str == null)
big_str = new String(global_value, value_idx, big_len);
else if (!check(big_str, value_idx)) continue search;
value_idx += big_len;
}
}
return true;
}
return single_count(small_count) || single_count(big_count);
}

private boolean check(String str, int value_idx) {
int idx = 0;
for (char ch : str.toCharArray())
if (ch != global_value[value_idx + idx++])
return false;
return true;
}
}

结果


面试16.26 计算器(Stack栈)

题目

分析

1. 使用字符数组arr接住字符串s的每一位字符,str接住每一次的数字,num用于将每一次的数字转为int,prev用于接住+-*/,用stack栈进行结果的存放。
2. 对于+-运算直接将数字放入stack栈
3. 对于*/运算需要将结果计算好放入stack栈

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class JiSuanQi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.next();
System.out.println(calculate(s));
}

public static int calculate(String s) {
char[] arr=s.replaceAll(" ","").toCharArray(); //将要判断的字符串转字符数组arr
Stack<Integer> stack=new Stack<>(); //新建stack栈
int res=0; //最终结果
char prev=' '; //每一位字符
for(int i=0;i<arr.length;i++){
StringBuilder str=new StringBuilder();
//1. 每一轮将所对应的数字放到str内!!!!!!!!!!!!
while(i<arr.length&&arr[i]>='0'&&arr[i]<='9'){ //在0-9之内
str.append(arr[i]); //将符合的添加到str
i++; //添加往后挪
}
System.out.println("str的值:"+str.toString());
int num=Integer.parseInt(str.toString()); //假如是3-6-8*5+6/8: num每一次将str中的数字转为int数字
System.out.print("num的值:"+num+" ");
//2. 判断四则运算!!!!!!!!!!!!!!!!!!
if(prev == '+'){
stack.push(num); //将数值放入栈内
}else if(prev == '-'){
stack.push(-num); //将数值相反数放入栈内
}else if(prev == '*'){
stack.push(stack.pop() * num); //乘法算出结果放入栈
}else if(prev == '/'){
stack.push(stack.pop() / num); //除法算出结果放入栈
}else{
stack.push(num);
}
if(i < arr.length) {
prev = arr[i]; //将数组的每一个字符都放入prev内用于判断是不是+-*/中一个
}
}
while (!stack.isEmpty()) { //只要栈不为空
res += stack.pop(); //依次将数组结果弹出后加入到res中
}

return res;
}

}

结果


面试17.13 恢复空格(动态递归+contains包含方法)

题目

分析

1. 使用set集合存储字典内所有单词
2. 定义dp数组每一个位置存放当前最优的答案
3. 定义两层循环:如果set.contains包含方法内有句子中的单词我们就去考虑i当前位置的答案和j位置的答案取最小值

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class HuiFuKongGe {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String[] dictionary={"looked","just","like","her","brother"};
String sentence=input.next();
System.out.println(respace(dictionary,sentence));
}

public static int respace(String[] dictionary, String sentence) {
Set<String> set = new HashSet<>();
for(String str: dictionary) {
set.add(str); //将字典里面的所有单词放入set集合
}
int n = sentence.length(); //获取长度
//dp[i]表示sentence前i个字符所得结果
int[] dp = new int[n+1];
for(int i=1; i<=n; i++){
dp[i] = dp[i-1]+1; //先假设当前字符不在字典
for(int j=0; j<i; j++){
if(set.contains(sentence.substring(j,i))){
dp[i] = Math.min(dp[i], dp[j]); //如果set里面有要判断的单词 就只要最小的长度
}
}
}
return dp[n]; //返回最后一个位置的长度即可
}

}

结果


面试58-I 翻转单词顺序(split()分割/trim()去除首尾空格)

题目

分析

1. 先删除首尾空格然后分割字符串生成一个单词表strs
2. 然后倒序遍历单词表strs存储到StringBuilder对象内

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ZuiChangDanCi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
System.out.println(reverseWords(s));
}

public static String reverseWords(String s) {
String[] strs = s.trim().split(" "); // 删除首尾空格,分割字符串
StringBuilder res = new StringBuilder();
for(int i = strs.length - 1; i >= 0; i--) { // 倒序遍历单词列表
if(strs[i].equals("")){
continue; // 遇到空单词则跳过
}
res.append(strs[i]+" "); // 将单词拼接至 StringBuilder
}
return res.toString().trim(); // 转化为字符串,删除尾部空格,并返回
}

}

结果


面试58-II 左旋转字符串(substring取特定位置字符串)

题目

分析

1. 使用substring获取n之前的和n之后两部分字符串
2. 然后stringbuilder对象去append链接两个部分

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ZuoXuanZhuanString {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
int n=input.nextInt();
System.out.println(reverseLeftWords(s,n));
}

public static String reverseLeftWords(String s, int n) {
String s1=s.substring(0,n); //前n个长度的字符串
String s2=s.substring(n,s.length()); //后面的正常字符串
StringBuilder sb=new StringBuilder();
sb.append(s2).append(s1); //sb去接s2然后s1
return sb.toString();
}

}

结果


Z字形变换(StringBuilder对象)

题目

分析

参考思路

https://leetcode-cn.com/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/

1. 怎么存: 每层都是一个sb对象 最后每一层都append在最终的一个sb对象
2. 怎么上下走: 定义i控制i上下走,上下走就是通过flag的变化(这个操作绝了)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

public class Main {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.next();
int n=input.nextInt();
System.out.println(convert(s,n));
}

public static String convert(String s, int numRows) {
if(numRows<2){ //如果是0行或者1行 就直接输出s即可
return s;
}
//存储每一行的字符(要拼接所以要用StringBuilder类)
List<StringBuilder> rows = new ArrayList<StringBuilder>();
//根据行数每行添加一个StringBuilder
for(int i=0;i<numRows;i++){
rows.add(new StringBuilder()); //每一行都有一个
}
int i=0;
int flag=-1;
for(char c:s.toCharArray()){
rows.get(i).append(c); //对应行添加进去字符
if(i==0||i==numRows-1){
flag=-flag; //到了拐角要变换flag
}
i=i+flag; //1的话就是往下加 -1的话就是往上加
}
StringBuilder res = new StringBuilder(); //新建接住结果
for(StringBuilder row:rows) {
res.append(row); //添加每一行的结果集合
}
return res.toString();//最后记得转字符串
}

}

结果


最常见的单词(map集合去重)

题目

分析

1. 使用正则表达式[^a-z]可以筛选单词
2. 使用map存储出现单词和单词次数
3. 使用remove删除禁用词
4. 使用entrySet()方法取出出现次数最多的单词

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class Solution {
//返回次数最多的单词
public static String mostCommonWord(String s, String[] str) {
s=s.toLowerCase();
String[] temp=s.split("[^a-z]"); //根据空格转字符串

Map<String,Integer> map=new HashMap<>();
for(int i=0;i< temp.length;i++){
String ts=temp[i]; //获取每一个单词的
if(map.containsKey(ts)){
map.put(ts,map.get(ts).intValue()+1); //出现次数+1
}else{
map.put(ts,1); //没出现过就设置出现为1
}
}
for(int i=0;i<str.length;i++){
str[i]=str[i].toLowerCase();
map.remove(str[i]); //依次移除所有的禁用词
}
map.remove("");
Integer max=0;
String res=""; //一定要设置成-1 /0 可能会出错!!!!!!!!!!!
for (Map.Entry<String, Integer> entry : map.entrySet()) {
int count = entry.getValue();
if (count > max) {
max = count;
res = entry.getKey();
}
}
return res;
}
}

结果


字符的最短距离(左右两边最短)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println(Arrays.toString(shortestToChar("loveleetcode",'e')));
}

public static int[] shortestToChar(String S, char C) {
int N = S.length(); //获取字符串长度
int[] ans = new int[N]; //返回结果的ans数组

int prev=Integer.MIN_VALUE/2; //先取负数
//从左往右取结果
for (int i = 0; i < N; ++i) { //正序
if (S.charAt(i) == C) prev = i;
ans[i] = i - prev; //找到相近的字符的距离
}
//从右往左取结果
prev = Integer.MAX_VALUE / 2; //先取正数
for (int i = N-1; i >= 0; --i) { //倒序
if (S.charAt(i) == C) prev = i;
ans[i] = Math.min(ans[i], prev - i); //找到相近的字符的距离
}
return ans; //返回ans数组
}

}

结果


删除回文子序列(因为只有a和b字符)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10

public int removePalindromeSub(String s) {
if ("".equals(s)) {
return 0; //空字符串
}
if (s.equals(new StringBuilder(s).reverse().toString())){
return 1; //本身就是回文串
}
return 2; //其他情况就是一次性删除所有a 然后删除b
}

结果


字符串的最大公因子(辗转相除法)

题目

分析

使用辗转相除法得到最大公因子!!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public String gcdOfStrings(String str1, String str2) {
// 假设str1是N个x,str2是M个x,那么str1+str2肯定是等于str2+str1的。
if (!(str1 + str2).equals(str2 + str1)) {
return "";
}
int l1=str1.length();
int l2=str2.length();
// 辗转相除法求gcd。
return str1.substring(0, gcd(l1, l2)); //截取str1的部分字符串
}

public static int gcd(int a, int b) {
return b == 0? a: gcd(b, a % b); //b是0就返回a b不是0就返回a%b
}

结果


仅仅反转字母(字母压栈)

题目

分析

1. 个人感觉倒序输入/反向的都需要栈顶
2. 第一次遍历将所有字符倒序压栈到栈stack  其实就反序放进去
3. 第二次遍历只要是特殊符号就放到遍历的位置  其他位置就反序出栈即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public String reverseOnlyLetters(String S) {
Stack<Character> letters = new Stack();
for (char c: S.toCharArray())
if (Character.isLetter(c))
letters.push(c); //所有数字反序压栈

StringBuilder ans = new StringBuilder();

//第二次再次遍历
for (char c: S.toCharArray()) {
if (Character.isLetter(c))
ans.append(letters.pop()); //如果当前位是字母 就出栈 刚好是反序
else
ans.append(c); //特殊位置继续放入当前位置
}

return ans.toString();
}

结果


翻转数位(只能把1个0改成1)

题目

分析

1. 使用方法将n转成二进制字符串形式s
2. 使用方法将字符串通过0隔开成字符串数组 每个子数组的长度就是1的长度
3. 最后通过for循环遍历找到第哪两个之间+1最大即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public static int reverseBits(int n) {
if(n==-1){
return 32; //负数就是32个
}
String s = Integer.toBinaryString(n);
String[] arr = s.split("0");
if(arr.length<1) {
return arr.length+1; //如果没有1就返回+1
}
int res=arr[0].length()+1; //暂定最终结果
for (int i = 1; i < arr.length; i++) { //从第二位开始
int temp=arr[i-1].length()+arr[i].length()+1; //获取当前值和上一位值+1 就相当于连起来试
res=Math.max(res,temp); //每次找最大的res
}
return res;
}

结果


×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 面试01.03 URL化(空格替换)
    1. 1.1. 题目
    2. 1.2. 分析
    3. 1.3. 代码
    4. 1.4. 结果
  2. 2. 面试01.04 回文排列(字符出现次数)
    1. 2.1. 题目
    2. 2.2. 分析
    3. 2.3. 代码
    4. 2.4. 结果
  3. 3. 面试01.05 一次编辑(统计变换次数)
    1. 3.1. 题目
    2. 3.2. 分析
    3. 3.3. 代码
    4. 3.4. 结果
  4. 4. 面试01.06 字符串压缩(StringBuilder添加)
    1. 4.1. 题目
    2. 4.2. 分析
    3. 4.3. 代码
    4. 4.4. 结果
  5. 5. 面试01.09 字符串轮转(contains判断是否包含子串)
    1. 5.1. 题目
    2. 5.2. 分析
    3. 5.3. 代码
    4. 5.4. 结果
  6. 6. 面试05.02 二进制转字符串(StringBuilder添加)
    1. 6.1. 题目
    2. 6.2. 分析
    3. 6.3. 代码
    4. 6.4. 结果
  7. 7. 面试08.09 括号(深度优先遍历(回溯))
    1. 7.1. 题目
    2. 7.2. 分析
    3. 7.3. 代码
    4. 7.4. 结果
  8. 8. 面试16.18 模式匹配(KMP)
    1. 8.1. 题目
    2. 8.2. 分析
    3. 8.3. 代码
    4. 8.4. 结果
  9. 9. 面试16.26 计算器(Stack栈)
    1. 9.1. 题目
    2. 9.2. 分析
    3. 9.3. 代码
    4. 9.4. 结果
  10. 10. 面试17.13 恢复空格(动态递归+contains包含方法)
    1. 10.1. 题目
    2. 10.2. 分析
    3. 10.3. 代码
    4. 10.4. 结果
  11. 11. 面试58-I 翻转单词顺序(split()分割/trim()去除首尾空格)
    1. 11.1. 题目
    2. 11.2. 分析
    3. 11.3. 代码
    4. 11.4. 结果
  12. 12. 面试58-II 左旋转字符串(substring取特定位置字符串)
    1. 12.1. 题目
    2. 12.2. 分析
    3. 12.3. 代码
    4. 12.4. 结果
  13. 13. Z字形变换(StringBuilder对象)
    1. 13.1. 题目
    2. 13.2. 分析
    3. 13.3. 代码
    4. 13.4. 结果
  14. 14. 最常见的单词(map集合去重)
    1. 14.1. 题目
    2. 14.2. 分析
    3. 14.3. 代码
    4. 14.4. 结果
  15. 15. 字符的最短距离(左右两边最短)
    1. 15.1. 题目
    2. 15.2. 分析
    3. 15.3. 代码
    4. 15.4. 结果
  16. 16. 删除回文子序列(因为只有a和b字符)
    1. 16.1. 题目
    2. 16.2. 分析
    3. 16.3. 代码
    4. 16.4. 结果
  17. 17. 字符串的最大公因子(辗转相除法)
    1. 17.1. 题目
    2. 17.2. 分析
    3. 17.3. 代码
    4. 17.4. 结果
  18. 18. 仅仅反转字母(字母压栈)
    1. 18.1. 题目
    2. 18.2. 分析
    3. 18.3. 代码
    4. 18.4. 结果
  19. 19. 翻转数位(只能把1个0改成1)
    1. 19.1. 题目
    2. 19.2. 分析
    3. 19.3. 代码
    4. 19.4. 结果
,