-
Notifications
You must be signed in to change notification settings - Fork 299
/
Code07_FreedomTrail.java
140 lines (131 loc) · 4.98 KB
/
Code07_FreedomTrail.java
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package class03;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TreeSet;
// 本题测试链接 : https://leetcode.com/problems/freedom-trail/
public class Code07_FreedomTrail {
// 提交时把findRotateSteps1方法名字改成findRotateSteps可以直接通过
public static int findRotateSteps1(String r, String k) {
char[] ring = r.toCharArray();
int N = ring.length;
HashMap<Character, ArrayList<Integer>> map = new HashMap<>();
for (int i = 0; i < N; i++) {
if (!map.containsKey(ring[i])) {
map.put(ring[i], new ArrayList<>());
}
map.get(ring[i]).add(i);
}
char[] str = k.toCharArray();
int M = str.length;
int[][] dp = new int[N][M + 1];
// hashmap
// dp[][] == -1 : 表示没算过!
for (int i = 0; i < N; i++) {
for (int j = 0; j <= M; j++) {
dp[i][j] = -1;
}
}
return process(0, 0, str, map, N, dp);
}
// 电话里:指针指着的上一个按键preButton
// 目标里:此时要搞定哪个字符?keyIndex
// map : key 一种字符 value: 哪些位置拥有这个字符
// N: 电话大小
// f(0, 0, aim, map, N)
public static int process(int preButton, int index, char[] str, HashMap<Character, ArrayList<Integer>> map, int N,
int[][] dp) {
if (dp[preButton][index] != -1) {
return dp[preButton][index];
}
int ans = Integer.MAX_VALUE;
if (index == str.length) {
ans = 0;
} else {
// 还有字符需要搞定呢!
char cur = str[index];
ArrayList<Integer> nextPositions = map.get(cur);
for (int next : nextPositions) {
int cost = dial(preButton, next, N) + 1 + process(next, index + 1, str, map, N, dp);
ans = Math.min(ans, cost);
}
}
dp[preButton][index] = ans;
return ans;
}
public static int dial(int i1, int i2, int size) {
return Math.min(Math.abs(i1 - i2), Math.min(i1, i2) + size - Math.max(i1, i2));
}
// 以下方法来自陆振星同学
// 可以省掉枚举行为
// 提交时把findRotateSteps2方法名字改成findRotateSteps可以直接通过
// 来龙去脉 : https://www.mashibing.com/question/detail/67299
// 例 :
// ring = aaca
// key = ca
// 首先来到 2 位置的 c, 下一步有 0 1 3 三个位置的 a 可以选择
// 只需要在 1 3 里面选择最优的即可, 因为 0 位置的 a 在任何情况下都不会比 1 位置的 a 更优
// 这是对的
// 应该是可以的,课上讲述的方法根据数据量能过,就没有继续优化了。
// 如下的贪心方式不对:
// 当前来到的位置,然后要去下一个字符,左边离下一个字符近就选左边,左边离下一个字符近就选右边。
// 两条路只选1条,彻底的每一步都选当前步最优。
// 但陆振星同学的贪心方式是:
// 1)当前来到的位置,然后要去下一个字符,左边离下一个字符最近的位置,去往左边,然后可能性展开,选最好的解;
// 2)当前来到的位置,然后要去下一个字符,右边离下一个字符最近的位置,去往右边,然后可能性展开,选最好的解;
// 1)和2)中最好的解,选出来,返回。
// 这是对的,因为如果去往离左右两边都更远的位置,那么为什么不在走的过程中,顺带就满足了下一个字符呢?
// 这样还能省掉枚举行为
// 如下所有代码都提交,再次注意:提交时把findRotateSteps2方法名字改成findRotateSteps可以直接通过
private int ringLength;
private char[] key;
private ArrayList<TreeSet<Integer>> ringSet;
private final HashMap<Integer, Integer> dp = new HashMap<>();
public int findRotateSteps2(String ring, String key) {
char[] chars = ring.toCharArray();
this.key = key.toCharArray();
ringLength = chars.length;
ringSet = new ArrayList<>();
for (int i = 0; i < 26; i++) {
ringSet.add(new TreeSet<>());
}
for (int i = 0; i < chars.length; i++) {
ringSet.get(chars[i] - 'a').add(i);
}
return findRotateSteps(0, 0);
}
// kIndex : 当前要搞定的字符
// cur : 当前所在的位置
private int findRotateSteps(int kIndex, int cur) {
if (kIndex == key.length) {
return 0;
}
// kIndex 和 cur 的最大值为 100, 所以用 十进制的低两位 表示 cur, 用高两位表示 kIndex
int k = kIndex * 100 + cur - 1;
Integer v = dp.get(k);
if (v != null) {
return v;
} else {
v = Integer.MAX_VALUE;
}
// key[kIndex] 的所有位置
TreeSet<Integer> treeSet = ringSet.get(key[kIndex] - 'a');
// 从 cur 向左走, 最近的符合 key[kIndex] 的位置
Integer floor = treeSet.floor(cur);
if (floor == null) {
floor = treeSet.last();
}
int len = Math.abs(cur - floor);
len = Math.min(len, ringLength - len);
v = Math.min(v, len + 1 + findRotateSteps(kIndex + 1, floor));
// 从 cur 向右走, 最近的符合 key[kIndex] 的位置
Integer ceiling = treeSet.ceiling(cur);
if (ceiling == null) {
ceiling = treeSet.first();
}
len = Math.abs(cur - ceiling);
len = Math.min(len, ringLength - len);
v = Math.min(v, len + 1 + findRotateSteps(kIndex + 1, ceiling));
dp.put(k, v);
return v;
}
}