列表

详情


514. 自由之路

电子游戏“辐射4”中,任务 “通向自由” 要求玩家到达名为 “Freedom Trail Ring” 的金属表盘,并使用表盘拼写特定关键词才能开门。

给定一个字符串 ring ,表示刻在外环上的编码;给定另一个字符串 key ,表示需要拼写的关键词。您需要算出能够拼写关键词中所有字符的最少步数。

最初,ring 的第一个字符与 12:00 方向对齐。您需要顺时针或逆时针旋转 ring 以使 key 的一个字符在 12:00 方向对齐,然后按下中心按钮,以此逐个拼写完 key 中的所有字符。

旋转 ring 拼出 key 字符 key[i] 的阶段中:

  1. 您可以将 ring 顺时针或逆时针旋转 一个位置 ,计为1步。旋转的最终目的是将字符串 ring 的一个字符与 12:00 方向对齐,并且这个字符必须等于字符 key[i]
  2. 如果字符 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

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int findRotateSteps(string ring, string key) { } };

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());
    }
};

上一题