算法练习(26):Freedom Trail

来源:互联网 发布:程序员2016精华本 pdf 编辑:程序博客网 时间:2024/06/05 15:22

题意:像是老式电话机那种转盘,有两个字符串key,ring,key的每个字符都出现在ring中,按下key[i]这个字符意思是把ring中对应字符转到12点方向,可以顺时针或者逆时针都可以,转一位就算一步,转到之后按中间键,按一次也算一步。

分析与思路:先把问题简单化,最后的按中间键对于key每个字符都要按一次,所以直接放到最后再整体加上key.length()就好。而且发现一个规律:把ring的第k个字符转到12点方向且这个字符等于key[i]后,则转要key[i+1]的ring起始位置就是k,所以可以把问题一步步化小,从key[0]开始找到key[key.length()-1]的最小步数可以转成从key[1]找到key[key.length()-1]的最小步数,很容易可以想到动态规划的解法,dp[i][j]代表ring[j]在12点方向,且正在找key[i]的状态到最终解决问题的最小步数,由于dp[keylength()-1][n]都可以提前算好的,因此可以从这里开始慢慢往前递推得出dp[0][0],这个就是解了。至于dp[i][j]怎么求,就是一个ring这个圈,找出两个方向离key[i]相等字符的较小距离即可,用dis表示。因此,动态方程可以表示为dp[i][j]=min{dp[i][j],dp[i+1][k]+dis}(对于key[i]在ring可能有多个相同字符)

代码:

class Solution {public:int findRotateSteps(string ring, string key) {vector<vector<int>> dp(key.length(),vector<int>(ring.length()));for (int i = key.length() - 1; i >= 0; i--) {for (int j = 0; j < ring.length(); j++) {dp[i][j] = 9999;for (int k = 0; k < ring.length(); k++) {if (ring[k] == key[i]) {int dis = abs(k - j);if (ring.length() - dis < dis) dis = ring.length() - dis;if (i == key.length() - 1) {if (dis < dp[i][j]) dp[i][j] = dis;}else if (dis + dp[i + 1][k] < dp[i][j]) dp[i][j] = dis + dp[i + 1][k];}}}}return dp[0][0] + key.length();}};