[H线性dp] lc514. 自由之路(经典线性dp+字符串)

1. 题目来源

链接:lc514. 自由之路

2. 题目说明

在这里插入图片描述

3. 题目解析

其实这个是很经典的线性 dp 变种题。状态定义、状态转移都是很自然的。

思路:

  • 状态定义:
    • f[i][j] 已经输出了 key 的前 i 个字符,且输出第 key[i] 时,指针位于 ring[j] 的所有方案步骤的最小值
  • 状态转移:
    • 集合划分一般找最后一步不同点。即,考虑 j-1 步指针是位于什么位置转移到 j 的。显然转盘的 n 中可能位置都是备选位置,都会发生状态转移。假设,输出 key[i-1],时指针位于 k 位置,此时意义为已经输出了 key 的前 i-1 个字符,且输出第 key[i-1] 时指针位于 ring[j-1] 的所有方案步骤的最小值,其等价于 f[i-1][k]k 可取 1~n,最后从 k 位置统一转到 key[i] 所在位置。在此考虑下顺、逆时针即可
  • 状态转移方程:
    • n 为环形字符串长度,mkey 的长度
    • 如果 key[i] == ring[j] 则从上一个状态进行转移 f[i][j]=min(f[i][j],f[i-1][k]+min(abs(k-j), abs(n-k+j)) + 1)
  • 边界情况及初始化:
    • minf 数组置为正无穷
    • 初始状态输出 key 的第一个字符之前,假定指针位于 key 的第 0 个字符。这相当于指针输出了 key 的第 0 个字符,且指针位于 ring 的第一个字母,该点由题目说明,初始时指针即位于 ring 的第一个字母。即 f[0][1] = 0,不做任何操作
    • 答案即为:min(f[m][i]) i 为转盘各个位置

代码:

class Solution {
public:
    int findRotateSteps(string ring, string key) {
        int n = ring.size(), m = key.size();
        ring = ' ' + ring, key = ' ' + key;
        vector<vector<int>> f(m + 1, vector<int>(n + 1, 1e8));
        f[0][1] = 0;
        for (int i = 1; i <= m; ++i)                // 枚举key大小
            for (int j = 1; j <= n; ++j)            // 枚举输出i时j指针的位置
                if (key[i] == ring[j]) {            // 当前key字符和指针指向字符相等才可进行状态转移
                    for (int k = 1; k <= n; ++k) {  // 枚举i-1个字符输出时,指针的所有位置,所有状态取min
                        int t = abs(k - j);         // 由于是环形,求距离加上abs,另外一个方向长度就是n-t
                        f[i][j] = min(f[i][j], f[i - 1][k] + min(t, n - t) + 1);  // 走到j位置还要按下去
                    }
                }
        
        int res = 1e8;
        for (int i = 1; i <= n; ++i) res = min(res, f[m][i]); // 在各个位置下输出所有的k的最小值
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值