514. 自由之路
电子游戏“辐射4”中,任务 “通向自由” 要求玩家到达名为 “Freedom Trail Ring” 的金属表盘,并使用表盘拼写特定关键词才能开门。
给定一个字符串 ring
,表示刻在外环上的编码;给定另一个字符串 key
,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。
最初,ring 的第一个字符与 12:00
方向对齐。您需要顺时针或逆时针旋转 ring
以使 key 的一个字符在 12:00
方向对齐,然后按下中心按钮,以此逐个拼写完 key
中的所有字符。
旋转 ring
拼出 key 字符 key[i]
的阶段中:
ring
的一个字符与 12:00
方向对齐,并且这个字符必须等于字符 key[i]
。key[i]
已经对齐到12:00方向,您需要按下中心按钮进行拼写,这也将算作 1 步。按完之后,您可以开始拼写 key 的下一个字符(下一阶段), 直至完成所有拼写。
示例 1:
输入: ring = "godding", key = "gd" 输出: 4 解释: 对于 key 的第一个字符 'g',已经在正确的位置, 我们只需要1步来拼写这个字符。 对于 key 的第二个字符 'd',我们需要逆时针旋转 ring "godding" 2步使它变成 "ddinggo"。 当然, 我们还需要1步进行拼写。 因此最终的输出是 4。
示例 2:
输入: ring = "godding", key = "godding" 输出: 13
提示:
1 <= ring.length, key.length <= 100
ring
和 key
只包含小写英文字母key
一定可以由字符串 ring
旋转拼出原站题解
golang 解法, 执行用时: 0 ms, 内存消耗: 6.6 MB, 提交时间: 2024-01-29 09:22:09
func findRotateSteps(s, t string) int { n, m := len(s), len(t) // 先算出每个字母的最后一次出现的下标 // 由于 s 是环形的,循环结束后的 pos 就刚好是 left[0] pos := [26]int{} // 初始值不重要 for i, b := range s { pos[b-'a'] = i } // 计算每个 s[i] 左边 a-z 的最近下标(左边没有就从 n-1 往左找) left := make([][26]int, n) for i, b := range s { left[i] = pos pos[b-'a'] = i // 更新下标 } // 先算出每个字母的首次出现的下标 // 由于 s 是环形的,循环结束后的 pos 就刚好是 right[n-1] for i := n - 1; i >= 0; i-- { pos[s[i]-'a'] = i } // 计算每个 s[i] 右边 a-z 的最近下标(左边没有就从 0 往右找) right := make([][26]int, n) for i := n - 1; i >= 0; i-- { right[i] = pos pos[s[i]-'a'] = i // 更新下标 } f := make([][]int, m+1) for i := range f { f[i] = make([]int, n) } for j := m - 1; j >= 0; j-- { for i := 0; i < n; i++ { if s[i] == t[j] { // 无需旋转 f[j][i] = f[j+1][i] continue } // 左边最近 or 右边最近,取最小值 l := left[i][t[j]-'a'] res1 := f[j+1][l] if l > i { res1 += n - l + i } else { res1 += i - l } r := right[i][t[j]-'a'] res2 := f[j+1][r] if r < i { res2 += n - i + r } else { res2 += r - i } f[j][i] = min(res1, res2) } } return f[0][0] + m }
python3 解法, 执行用时: 214 ms, 内存消耗: 16.8 MB, 提交时间: 2024-01-29 09:21:27
class Solution: def findRotateSteps(self, s: str, t: str) -> int: s = [ord(c) - ord('a') for c in s] t = [ord(c) - ord('a') for c in t] n, m = len(s), len(t) # 先算出每个字母的最后一次出现的下标 # 由于 s 是环形的,循环结束后的 pos 就刚好是 left[0] pos = [0] * 26 # 初始值不重要 for i, c in enumerate(s): pos[c] = i # 计算每个 s[i] 左边 a-z 的最近下标(左边没有就从 n-1 往左找) left = [None] * n for i, c in enumerate(s): left[i] = pos[:] pos[c] = i # 更新下标 # 先算出每个字母的首次出现的下标 # 由于 s 是环形的,循环结束后的 pos 就刚好是 right[n-1] for i in range(n - 1, -1, -1): pos[s[i]] = i # 计算每个 s[i] 右边 a-z 的最近下标(左边没有就从 0 往右找) right = [None] * n for i in range(n - 1, -1, -1): right[i] = pos[:] pos[s[i]] = i # 更新下标 f = [[0] * n for _ in range(m + 1)] for j in range(m - 1, -1, -1): c = t[j] for i, x in enumerate(s): if x == c: # 无需旋转 f[j][i] = f[j + 1][i] else: # 左边最近 or 右边最近,取最小值 l, r = left[i][c], right[i][c] f[j][i] = min(f[j + 1][l] + (n - l + i if l > i else i - l), f[j + 1][r] + (n - i + r if r < i else r - i)) return f[0][0] + m
python3 解法, 执行用时: 140 ms, 内存消耗: 16.1 MB, 提交时间: 2023-10-09 10:05:31
''' 定义 dp[i][j] 表示从前往后拼写出 key 的第 i 个字符, ring 的第 j 个字符与 12:00 方向对齐的最少步数(下标均从 0 开始)。 ''' class Solution: def findRotateSteps(self, ring: str, key: str) -> int: n, m = len(ring), len(key) pos = [[] for _ in range(26)] for i, c in enumerate(ring): pos[ord(c)-ord('a')].append(i) dp = [[inf for i in range(n)] for _ in range(m)] for p in pos[ord(key[0])-ord('a')]: dp[0][p] = min(p, n-p) + 1 for i in range(1, m): for j in pos[ord(key[i])-ord('a')]: for k in pos[ord(key[i-1])-ord('a')]: dp[i][j] = min(dp[i][j], dp[i-1][k]+min(abs(j-k), n-abs(j-k))+1) return min(dp[m-1])
python3 解法, 执行用时: 148 ms, 内存消耗: 16.9 MB, 提交时间: 2023-10-09 09:56:30
class Solution: def findRotateSteps(self, ring: str, key: str) -> int: import collections, functools lookup = collections.defaultdict(list) for i in range(len(ring)): lookup[ring[i]].append(i) @functools.lru_cache(None) def dfs(cur, k): if k == len(key): return 0 res = float("inf") for j in lookup[key[k]]: res = min(res, min(tmp := abs(cur - j), len(ring) - tmp) + 1 + dfs(j, k + 1)) return res return dfs(0, 0)
python3 解法, 执行用时: 132 ms, 内存消耗: 17.2 MB, 提交时间: 2023-10-09 09:56:10
class Solution: def findRotateSteps(self, ring: str, key: str) -> int: import collections, functools lookup = collections.defaultdict(list) steps = collections.defaultdict(int) # 把所有可以旋转的字符串找出来 for i in range(len(ring)): tmp = ring[i:] + ring[:i] # 加入以开头字母为键的数组中 lookup[ring[i]].append(tmp) # 距离原始ring顺时针旋转需要几步 steps[tmp] = i # 从一个字符串到另一字符串最少旋转的步数 def cal_steps(cur, nxt): return min(tmp := abs(steps[cur] - steps[nxt]), len(ring) - tmp) @functools.lru_cache(None) def dfs(cur, k): if k == len(key): return 0 res = float("inf") for word in lookup[key[k]]: res = min(res, cal_steps(cur, word) + 1 + dfs(word, k + 1)) return res return dfs(ring, 0)
python3 解法, 执行用时: 180 ms, 内存消耗: 16.3 MB, 提交时间: 2023-10-09 09:54:32
from collections import defaultdict as d class Solution: def findRotateSteps(self, ring: str, key: str) -> int: Choices = d() # 把每个key对应的可选的ring的字母的index做成字典。 for k in key: if k in Choices: continue else: Choices[k] = [] for ri, r in enumerate(ring): if r == k: Choices[k].append(ri) counter = [{0 : 0}] Path = d() for keyi in range(len(key)): # 一共len(key)个格子。 counter.append({}) for choice in Choices[key[keyi]]: # choice是个index,是表示对于在key上第keyi个字母来说,ring里有哪几个位置的字母可以选择。 temp = [] for start in counter[keyi].keys(): # start表示上一个格子里,有几种情况可以到达当前的choice。 previous_distance = counter[keyi][start] s = str(start) + "-" + str(choice) if s not in Path: d1 = abs(choice - start) d2 = abs(len(ring) - d1) newc = min(d1, d2) Path[s] = newc temp.append(previous_distance + Path[s]) counter[keyi + 1][choice] = min(temp) + 1 # 只需要保留最小值 再加1表示按下按钮。 # print(Choices) final = min(counter[-1].values()) return final
golang 解法, 执行用时: 0 ms, 内存消耗: 6.5 MB, 提交时间: 2023-10-09 09:52:18
func findRotateSteps(ring string, key string) int { const inf = math.MaxInt64 / 2 n, m := len(ring), len(key) pos := [26][]int{} for i, c := range ring { pos[c-'a'] = append(pos[c-'a'], i) } dp := make([][]int, m) for i := range dp { dp[i] = make([]int, n) for j := range dp[i] { dp[i][j] = inf } } for _, p := range pos[key[0]-'a'] { dp[0][p] = min(p, n-p) + 1 } for i := 1; i < m; i++ { for _, j := range pos[key[i]-'a'] { for _, k := range pos[key[i-1]-'a'] { dp[i][j] = min(dp[i][j], dp[i-1][k]+min(abs(j-k), n-abs(j-k))+1) } } } return min(dp[m-1]...) } func min(a ...int) int { res := a[0] for _, v := range a[1:] { if v < res { res = v } } return res } func abs(x int) int { if x < 0 { return -x } return x }
javascript 解法, 执行用时: 104 ms, 内存消耗: 51 MB, 提交时间: 2023-10-09 09:51:55
/** * @param {string} ring * @param {string} key * @return {number} */ const getIdx = (str, v) => str.codePointAt(v) - 'a'.codePointAt(0); var findRotateSteps = function(ring, key) { const n = ring.length, m = key.length; const pos = new Array(26).fill(0).map(v => []); for (let i = 0; i < n; ++i) { pos[getIdx(ring, i)].push(i); } const dp = new Array(m).fill(0).map(v => new Array(n).fill(Number.MAX_SAFE_INTEGER)); for (const i of pos[getIdx(key, 0)]) { dp[0][i] = Math.min(i, n - i) + 1; } for (let i = 1; i < m; ++i) { for (const j of pos[getIdx(key, i)]) { for (const k of pos[getIdx(key, i - 1)]) { dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)) + 1); } } } return dp[m - 1].reduce((pre, cur) => Math.min(pre, cur), Number.MAX_SAFE_INTEGER); };
java 解法, 执行用时: 14 ms, 内存消耗: 43.2 MB, 提交时间: 2023-10-09 09:51:39
class Solution { public int findRotateSteps(String ring, String key) { int n = ring.length(), m = key.length(); List<Integer>[] pos = new List[26]; for (int i = 0; i < 26; ++i) { pos[i] = new ArrayList<Integer>(); } for (int i = 0; i < n; ++i) { pos[ring.charAt(i) - 'a'].add(i); } int[][] dp = new int[m][n]; for (int i = 0; i < m; ++i) { Arrays.fill(dp[i], 0x3f3f3f); } for (int i : pos[key.charAt(0) - 'a']) { dp[0][i] = Math.min(i, n - i) + 1; } for (int i = 1; i < m; ++i) { for (int j : pos[key.charAt(i) - 'a']) { for (int k : pos[key.charAt(i - 1) - 'a']) { dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)) + 1); } } } return Arrays.stream(dp[m - 1]).min().getAsInt(); } }
cpp 解法, 执行用时: 8 ms, 内存消耗: 13.6 MB, 提交时间: 2023-10-09 09:51:24
class Solution { public: int findRotateSteps(string ring, string key) { int n = ring.size(), m = key.size(); vector<int> pos[26]; for (int i = 0; i < n; ++i) { pos[ring[i] - 'a'].push_back(i); } vector<vector<int>> dp(m, vector<int>(n, 0x3f3f3f3f)); for (auto& i: pos[key[0] - 'a']) { dp[0][i] = min(i, n - i) + 1; } for (int i = 1; i < m; ++i) { for (auto& j: pos[key[i] - 'a']) { for (auto& k: pos[key[i - 1] - 'a']) { dp[i][j] = min(dp[i][j], dp[i - 1][k] + min(abs(j - k), n - abs(j - k)) + 1); } } } return *min_element(dp[m - 1].begin(), dp[m - 1].end()); } };