From 702a13417e5765b797b14d9527fd3f86c9efd7d6 Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Sun, 14 May 2023 01:25:09 +0800 Subject: [PATCH] modify code --- .../class03/Code07_FreedomTrail.java | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/大厂刷题班/class03/Code07_FreedomTrail.java b/大厂刷题班/class03/Code07_FreedomTrail.java index a3ef36d..a329870 100644 --- a/大厂刷题班/class03/Code07_FreedomTrail.java +++ b/大厂刷题班/class03/Code07_FreedomTrail.java @@ -2,11 +2,13 @@ package class03; import java.util.ArrayList; import java.util.HashMap; +import java.util.TreeSet; // 本题测试链接 : https://leetcode.com/problems/freedom-trail/ public class Code07_FreedomTrail { - public static int findRotateSteps(String r, String k) { + // 提交时把findRotateSteps1方法名字改成findRotateSteps可以直接通过 + public static int findRotateSteps1(String r, String k) { char[] ring = r.toCharArray(); int N = ring.length; HashMap> map = new HashMap<>(); @@ -59,4 +61,80 @@ public class Code07_FreedomTrail { 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> ringSet; + private final HashMap 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 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; + } + }