diff --git a/solution/0500-0599/0514.Freedom Trail/README.md b/solution/0500-0599/0514.Freedom Trail/README.md index cc54a49071f7b..999ec737b21b3 100644 --- a/solution/0500-0599/0514.Freedom Trail/README.md +++ b/solution/0500-0599/0514.Freedom Trail/README.md @@ -194,6 +194,40 @@ func abs(x int) int { } ``` +```ts +function findRotateSteps(ring: string, key: string): number { + const m: number = key.length; + const n: number = ring.length; + const pos: number[][] = Array.from({ length: 26 }, () => []); + for (let i = 0; i < n; ++i) { + const j: number = ring.charCodeAt(i) - 'a'.charCodeAt(0); + pos[j].push(i); + } + + const f: number[][] = Array.from({ length: m }, () => Array(n).fill(1 << 30)); + for (const j of pos[key.charCodeAt(0) - 'a'.charCodeAt(0)]) { + f[0][j] = Math.min(j, n - j) + 1; + } + + for (let i = 1; i < m; ++i) { + for (const j of pos[key.charCodeAt(i) - 'a'.charCodeAt(0)]) { + for (const k of pos[key.charCodeAt(i - 1) - 'a'.charCodeAt(0)]) { + f[i][j] = Math.min( + f[i][j], + f[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)) + 1, + ); + } + } + } + + let ans: number = 1 << 30; + for (const j of pos[key.charCodeAt(m - 1) - 'a'.charCodeAt(0)]) { + ans = Math.min(ans, f[m - 1][j]); + } + return ans; +} +``` + diff --git a/solution/0500-0599/0514.Freedom Trail/README_EN.md b/solution/0500-0599/0514.Freedom Trail/README_EN.md index 6ebe1713659ee..be510ac6102d7 100644 --- a/solution/0500-0599/0514.Freedom Trail/README_EN.md +++ b/solution/0500-0599/0514.Freedom Trail/README_EN.md @@ -48,7 +48,19 @@ So the final output is 4. ## Solutions -### Solution 1 +### Solution 1: Dynamic Programming + +First, we preprocess the positions of each character $c$ in the string $ring$, and record them in the array $pos[c]$. Suppose the lengths of the strings $key$ and $ring$ are $m$ and $n$, respectively. + +Then we define $f[i][j]$ as the minimum number of steps to spell the first $i+1$ characters of the string $key$, and the $j$-th character of $ring$ is aligned with the $12:00$ direction. Initially, $f[i][j]=+\infty$. The answer is $\min_{0 \leq j < n} f[m - 1][j]$. + +We can first initialize $f[0][j]$, where $j$ is the position where the character $key[0]$ appears in $ring$. Since the $j$-th character of $ring$ is aligned with the $12:00$ direction, we only need $1$ step to spell $key[0]$. In addition, we need $min(j, n - j)$ steps to rotate $ring$ to the $12:00$ direction. Therefore, $f[0][j]=min(j, n - j) + 1$. + +Next, we consider how the state transitions when $i \geq 1$. We can enumerate the position list $pos[key[i]]$ where $key[i]$ appears in $ring$, and enumerate the position list $pos[key[i-1]]$ where $key[i-1]$ appears in $ring$, and then update $f[i][j]$, i.e., $f[i][j]=\min_{k \in pos[key[i-1]]} f[i-1][k] + \min(\text{abs}(j - k), n - \text{abs}(j - k)) + 1$. + +Finally, we return $\min_{0 \leq j \lt n} f[m - 1][j]$. + +The time complexity is $O(m \times n^2)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the lengths of the strings $key$ and $ring$, respectively. @@ -174,6 +186,40 @@ func abs(x int) int { } ``` +```ts +function findRotateSteps(ring: string, key: string): number { + const m: number = key.length; + const n: number = ring.length; + const pos: number[][] = Array.from({ length: 26 }, () => []); + for (let i = 0; i < n; ++i) { + const j: number = ring.charCodeAt(i) - 'a'.charCodeAt(0); + pos[j].push(i); + } + + const f: number[][] = Array.from({ length: m }, () => Array(n).fill(1 << 30)); + for (const j of pos[key.charCodeAt(0) - 'a'.charCodeAt(0)]) { + f[0][j] = Math.min(j, n - j) + 1; + } + + for (let i = 1; i < m; ++i) { + for (const j of pos[key.charCodeAt(i) - 'a'.charCodeAt(0)]) { + for (const k of pos[key.charCodeAt(i - 1) - 'a'.charCodeAt(0)]) { + f[i][j] = Math.min( + f[i][j], + f[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)) + 1, + ); + } + } + } + + let ans: number = 1 << 30; + for (const j of pos[key.charCodeAt(m - 1) - 'a'.charCodeAt(0)]) { + ans = Math.min(ans, f[m - 1][j]); + } + return ans; +} +``` + diff --git a/solution/0500-0599/0514.Freedom Trail/Solution.ts b/solution/0500-0599/0514.Freedom Trail/Solution.ts new file mode 100644 index 0000000000000..e5ea34cce7612 --- /dev/null +++ b/solution/0500-0599/0514.Freedom Trail/Solution.ts @@ -0,0 +1,31 @@ +function findRotateSteps(ring: string, key: string): number { + const m: number = key.length; + const n: number = ring.length; + const pos: number[][] = Array.from({ length: 26 }, () => []); + for (let i = 0; i < n; ++i) { + const j: number = ring.charCodeAt(i) - 'a'.charCodeAt(0); + pos[j].push(i); + } + + const f: number[][] = Array.from({ length: m }, () => Array(n).fill(1 << 30)); + for (const j of pos[key.charCodeAt(0) - 'a'.charCodeAt(0)]) { + f[0][j] = Math.min(j, n - j) + 1; + } + + for (let i = 1; i < m; ++i) { + for (const j of pos[key.charCodeAt(i) - 'a'.charCodeAt(0)]) { + for (const k of pos[key.charCodeAt(i - 1) - 'a'.charCodeAt(0)]) { + f[i][j] = Math.min( + f[i][j], + f[i - 1][k] + Math.min(Math.abs(j - k), n - Math.abs(j - k)) + 1, + ); + } + } + } + + let ans: number = 1 << 30; + for (const j of pos[key.charCodeAt(m - 1) - 'a'.charCodeAt(0)]) { + ans = Math.min(ans, f[m - 1][j]); + } + return ans; +}