LeetCode每日一题--514. 自由之路(动态规划)

题目:跳转至 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 的下一个字符(下一阶段),直至完成所有拼写。

示例:
输入: ring = “godding”, key = “gd”
输出: 4
解释:
对于 key 的第一个字符 ‘g’,已经在正确的位置, 我们只需要1步来拼写这个字符。
对于 key 的第二个字符 ‘d’,我们需要逆时针旋转 ring “godding” 2步使它变成 “ddinggo”。
当然, 我们还需要1步进行拼写。
因此最终的输出是 4。
提示:

  1. ring 和 key 的字符串长度取值范围均为 1 至 100;
  2. 两个字符串中都只有小写字符,并且均可能存在重复字符;
  3. 字符串 key 一定可以由字符串 ring 旋转拼出。
class Solution {
public:
    int findRotateSteps(string ring, string key) {

    }
};

思路:
礼拜三看到困难又是两眼一黑,题目挺有意思的,刚开始还是挺自信满满的。首先定义一个下标i指向ring的第一个字母。然后可以定义l,r两个指针分别往左往右走,直到找到此时对应的key值,取其中较小的步数改变i(注意i大于等于0小于ring.length()),直到key全部找出。每次找到一个相等的值就增加操作步数。感觉还挺简单,结果依旧骨感,解答错误,解答错误,解答错误。
因为后面把错误用例记下来直接测试,做了改动也没存就不贴了。具体点就是循环key中每一个字母,与ring中i对应的字母比较,循环分别获取l和r的值(也可以每一步都向左向右移一格直到l或者r某一个找到最近的值就返回)
!!!现在发现了华点!如果找到的字母同时相等,那只会保存一个结果继续循环,所以值就可能偏大。
要维护每一个位置上的次数来算最优解,动态规划!

又是爱题解的一天。

class Solution {
public:
    int findRotateSteps(string ring, string key) {
        int n = ring.size(), m = key.size();
        vector<int> pos[26];  //位置数组,存储ring各字符的位置
        for (int i = 0; i < n; ++i) {
            pos[ring[i] - 'a'].push_back(i);
        }
        vector<vector<int>> dp(m, vector<int>(n, 0x3f3f3f3f)); //初始化为最大值,表示key[i]->ring[j]的最小步数
        for (auto& i: pos[key[0] - 'a']) {  //首先存ring各字符到key[0]的最短距离路径+确认操作步数1
            dp[0][i] = min(i, n - i) + 1;
        }
        for (int i = 1; i < m; ++i) {  //循环找key中其余的字符
            for (auto& j: pos[key[i] - 'a']) {  //循环每个key当前值在ring中的位置索引
                for (auto& k: pos[key[i - 1] - 'a']) {  //循环key前一个值的位置索引,因为必须从前一个位置转移到当前位置,记录最短次数
                    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());
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值