In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a metal dial called the "Freedom Trail Ring", and use the dial to spell a specific keyword in order to open the door.

Given a string ring, which represents the code engraved on the outer ring and another string key, which represents the keyword needs to be spelled. You need to find the minimum number of steps in order to spell all the characters in the keyword.

Initially, the first character of the ring is aligned at 12:00 direction. You need to spell all the characters in the string key one by one by rotating the ring clockwise or anticlockwise to make each character of the string key aligned at 12:00 direction and then by pressing the center button. 
At the stage of rotating the ring to spell the key character key[i]:

  1. You can rotate the ring clockwise or anticlockwise one place, which counts as 1 step. The final purpose of the rotation is to align one of the string ring's characters at the 12:00 direction, where this character must equal to the character key[i].
  2. If the character key[i] has been aligned at the 12:00 direction, you need to press the center button to spell, which also counts as 1 step. After the pressing, you could begin to spell the next character in the key (next stage), otherwise, you've finished all the spelling.

Example:

Input: ring = "godding", key = "gd"
Output: 4
Explanation:
For the first key character 'g', since it is already in place, we just need 1 step to spell this character.
For the second key character 'd', we need to rotate the ring "godding" anticlockwise by two steps to make it become "ddinggo".
Also, we need 1 more step for spelling.
So the final output is 4.

Note:

  1. Length of both ring and key will be in range 1 to 100.
  2. There are only lowercase letters in both strings and might be some duplcate characters in both strings.
  3. It's guaranteed that string key could always be spelled by rotating the string ring.

这道题是关于辐射4这款游戏出的,博主虽然没有玩过这款游戏,但是知道确实有些游戏中需要破解一些谜题才能继续通关,像博主很早以前玩过的恐龙危机啊,生化危机啊啥的,都有一些机关需要破解,博主大部分都要靠看攻略来通关哈哈。这道题讲的是一种叫做自由之路的机关,我们需要将密码字符串都转出来,让我们求最短的转动步数。博主最先尝试的用贪婪算法来做,就是每一步都选最短的转法,但是OJ中总有些test case会引诱贪婪算法得出错误的结果,因为全局最优解不一定都是局部最优解,而贪婪算法一直都是在累加局部最优解,这也是为啥DP解法这么叼的原因。贪婪算法好想好实现,但是不一定能得到正确的结果。DP解法难想不好写,但往往才是正确的解法,这也算一个trade off吧。这道题可以用DP来解,难点还是写递推公式,博主在充分研究网上大神们的帖子后尝试着自己理理思路,如果有不正确或者不足的地方,也请各位不吝赐教。此题需要使用一个二维数组dp,其中dp[i][j]表示转动从i位置开始的key串所需要的最少步数(这里不包括spell的步数,因为spell可以在最后统一加上),此时表盘的12点位置是ring中的第j个字符。不得不佩服这样的设计的确很巧妙,我们可以从key的末尾往前推,这样dp[0][0]就是我们所需要的结果,因为此时是从key的开头开始转动,而且表盘此时的12点位置也是ring的第一个字符。现在我们来看如何找出递推公式,对于dp[i][j],我们知道此时要将key[i]转动到12点的位置,而此时表盘的12点位置是ring[j],我们有两种旋转的方式,顺时针和逆时针,我们的目标肯定是要求最小的转动步数,而顺时针和逆时针的转动次数之和刚好为ring的长度n,这样我们求出来一个方向的次数,就可以迅速得到反方向的转动次数。为了将此时表盘上12点位置上的ring[j]转动到key[i],我们要将表盘转动一整圈,当转到key[i]的位置时,我们计算出转动步数diff,然后计算出反向转动步数,并取二者较小值为整个转动步数step,此时我们更新dp[i][j],更新对比值为step + dp[i+1][k],这个也不难理解,因为key的前一个字符key[i+1]的转动情况suppose已经计算好了,那么dp[i+1][k]就是当时表盘12点位置上ring[k]的情况的最短步数,step就是从ring[k]转到ring[j]的步数,也就是key[i]转到ring[j]的步数,用语言来描述就是,从key的i位置开始转动并且此时表盘12点位置为ring[j]的最小步数(dp[i][j])就等价于将ring[k]转动到12点位置的步数(step)加上从key的i+1位置开始转动并且ring[k]已经在表盘12点位置上的最小步数(dp[i+1][k])之和。突然发现这不就是之前那道Reverse Pairs中解法一中归纳的顺序重现关系的思路吗,都做了总结,可换个马甲就又不认识了,泪目中。。。

解法一:

class Solution {
public:
int findRotateSteps(string ring, string key) {
int n = ring.size(), m = key.size();
vector<vector<int>> dp(m + , vector<int>(n));
for (int i = m - ; i >= ; --i) {
for (int j = ; j < n; ++j) {
dp[i][j] = INT_MAX;
for (int k = ; k < n; ++k) {
if (ring[k] == key[i]) {
int diff = abs(j - k);
int step = min(diff, n - diff);
dp[i][j] = min(dp[i][j], step + dp[i + ][k]);
}
}
}
}
return dp[][] + m;
}
};

下面这种解法是用DFS来解的,我们需要做优化,也就是用memo数组来保存已经计算过的结果,否则大量的重复运算是无法通过OJ的。其实这里的memo数组也起到了跟上面解法中的dp数组相类似的作用,还有就是要注意数组v的作用,记录了每个字母在ring中的出现位置,由于ring中可能有重复字符,而且麻烦的情况是当前位置向两个方向分别转动相同的步数会分别到达两个相同的字符,这也是贪婪算法会失效的一个重要原因,而且也是上面的解法在找到ring[k] == key[i]并处理完之后不break的原因,因为后面还有可能找到。上面的迭代解法中使用到的变量i和j可以直接访问到,而在递归的写法中必须要把位置变量x和y当作参数导入进去,这样才能更新正确的地方,参见代码如下:

解法二:

class Solution {
public:
int findRotateSteps(string ring, string key) {
int n = ring.size(), m = key.size();
vector<vector<int>> v();
vector<vector<int>> memo(n, vector<int>(m));
for (int i = ; i < n; ++i) v[ring[i] - 'a'].push_back(i);
return helper(ring, key, , , v, memo);
}
int helper(string ring, string key, int x, int y, vector<vector<int>>&v, vector<vector<int>>& memo) {
if (y == key.size()) return ;
if (memo[x][y]) return memo[x][y];
int res = INT_MAX, n = ring.size();
for (int k : v[key[y] - 'a']) {
int diff = abs(x - k);
int step = min(diff, n - diff);
res = min(res, step + helper(ring, key, k, y + , v, memo));
}
return memo[x][y] = res + ;
}
};

参考资料:

https://discuss.leetcode.com/topic/81684/concise-java-dp-solution

https://discuss.leetcode.com/topic/82720/evolve-from-brute-force-to-dp

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Freedom Trail 自由之路的更多相关文章

  1. 514 Freedom Trail 自由之路

    详见:https://leetcode.com/problems/freedom-trail/description/ C++: class Solution { public: int findRo ...

  2. [Swift]LeetCode514. 自由之路 | Freedom Trail

    In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a metal ...

  3. Leetcode 514.自由之路

    自由之路 视频游戏"辐射4"中,任务"通向自由"要求玩家到达名为"Freedom Trail Ring"的金属表盘,并使用表盘拼写特定关键词 ...

  4. Java实现 LeetCode 514 自由之路

    514. 自由之路 视频游戏"辐射4"中,任务"通向自由"要求玩家到达名为"Freedom Trail Ring"的金属表盘,并使用表盘拼写 ...

  5. 514. Freedom Trail

    In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a metal ...

  6. LeetCode 514----Freedom Trail

    问题描述 In the video game Fallout 4, the quest "Road to Freedom" requires players to reach a ...

  7. 【美】范·K·萨普曼 - 通向财务自由之路(2013年11月26日)

    <通向财务自由之路> 作 者:[美]范·K·萨普曼  译 者:董梅 系 列: 出 版:机械工业出版社 字 数:约40千字 阅读完成:2013年11月26日

  8. [LeetCode] Judge Route Circle 判断路线绕圈

    Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot m ...

  9. 动态规划——Freedom Trail

    题目:https://leetcode.com/problems/freedom-trail/ 额...不解释大意了,题目我也不想写过程了有点繁琐,直接给出代码: public int findRot ...

随机推荐

  1. 详细说明手工创建oracle数据库实例

    手工建库比起使用DBCA建库来说,是比较麻烦的,但是如果我们学好了手工建库的话,就可以使我们更好地理解Oracle数据库的体系结构.手工建库须要经过几个步骤,每一个步骤都非常关键.它包括:1. 创建必 ...

  2. Beta冲刺第七天

    一.昨天的困难 没有困难. 二.今天进度 1.林洋洋:MD图片上传,修复权限问题,修复本地存储判空问题,修复协作申请没有过滤问题. 2.黄腾达:添加文件链接和邀请链接复制功能,协作树界面优化. 3.张 ...

  3. Android属性动画 nineoldandroids

    各种资源链接 nineoldandroids 任玉刚的五个图片滑动,点击menu http://blog.csdn.net/singwhatiwanna/article/details/1763998 ...

  4. IQKeyboardManager使用方法

    使用方法: 将IQKeyboardManager 和 IQSegmentedNextPrevious类文件加进项目中.在AppDelegate文件中写下以下一行代码: [IQKeyBoardManag ...

  5. C#系统服务安装

    转载 http://blog.csdn.net/vvhesj/article/details/8349615 1.1创建WindowsService项目 导入需要的引用比如System.configu ...

  6. python之路--day6--字符编码

    一.知识储备 cpu--控制和运算 内存--暂时存储cpu需要的数据 硬盘--永久保存数据2.文本编辑器的原理存储原理 1,启动文本编辑器 2,在编辑器上输入内容---此时输入内容还在内存上 3,保存 ...

  7. 更优雅的方式: JavaScript 中顺序执行异步函数

    火于异步 1995年,当时最流行的浏览器--网景中开始运行 JavaScript (最初称为 LiveScript). 1996年,微软发布了 JScript 兼容 JavaScript.随着网景.微 ...

  8. 点开GitHub之后,瑟瑟发抖...的我

    我说句实在话啊,GitHub这个网址真的很能勾起人学习的欲望,一进入GitHub的注册页面真的让我这个英语学渣瑟瑟发抖,瞬间立下个flag:好好学习英语..... 我对python的求知欲怎么能被英语 ...

  9. JAVA版exe可执行加密软件

    1.现在eclipse(myeclipse)中插入以下代码 1.1 MainForm package cee.hui.myfile; import javax.swing.*; import java ...

  10. SpringMvc返回报文形式的控制-验证方法: JSON or HTML or XML

    首先,请求通过accept请求头声明了支持的返回格式 然后,框架根据该请求头和代码实现(注解)选择了对应的MessageConverter处理返回! 一.验证过程 1.返回html 1.1.请求组装 ...