题解/算法 {LCP 79. 提取咒文}

题解/算法 {LCP 79. 提取咒文}

LINK: https://leetcode.cn/problems/kjpLFZ/;

首先一定要读懂题目…
. 比赛时, 莫名其妙的以为: 比如字符串为abcd, 那么: 起点-a的最短距离 + a-b的最短距离 + b-c的最短距离 + c-d的最短距离, 就是答案… 这当然是错误的, 题目都没读懂, 人家是要连续移动的, 而你认为所有相同的字符之间 移动是无代价的, 这当然都是错误的…

最重要的是要知道, 他是在移动 即从起点开始 上下左右的移动, 每次移动 都是有代价的; 因此, 答案 一定是一条路径(起点)-> ... -> 终点 (权值为: 移动次数 + 字符串长度), 看到这一点 非常重要;

-{

错误思路; (但可以投机取巧AC);

由于是要取这个字符串, 我们的关注点 很容易把重点去关注这个字符串, 即先去取S[0], 然后去取S[1], … 这当然是正确的, 于是你得到了下面的模型:
.Set( S[i])表示 该二维矩阵里 所有值为S[i]的坐标, 得到一个DAG图: (起点) -> Set( S[0]) -> Set( S[1]) ... (比如Set( S[i]) -> Set( S[i+1])表示: S[i]里的每个元素 向S[i+1]的每个元素 连接一条 abs(x1-x2) + abs(y1-y2)的边, 即连接|S[i]| * |S[i+1]|条边;

每个点是由(x,y,ind)三个维度组成, 表示 S[ind]里有个(x,y)的坐标元素;

答案肯定是: 起点 -> Set( S[0])的某个点 -> Set( S[1])的某个点 -> ...;

也就是, 在这个图上 跑最短路, 由于他是DAG 可以使用DP递推 或 DFS记忆化 (两者一样), 重点是考虑下他是时间复杂度;
时间是: O(N * K) (N是点数, K是每个点的邻接点个数);

想象一个特例, S = "a...a" 且二维网格里全都是a, 此时 点数有1e4 * 1e2个, 每个点 有1e4个临界点, 这一定是超时的; (不管用什么算法, 最短路/DP递推, 都是针对的是这个图, 而这个图本身 就是超时的 因为他有1e10条边);
. 不要想着把这个特例给特判掉, 这就心术不正了, 比如S="abababab..." 二维网格里一半的a 一半的b, 时间也是一样的;

比赛时使用的是DFS记忆化 (其实直接用DP递推即可), 然后用一个counter计数 由于邻接点很多 就枚举counter个即可…
碰巧给AC了, 这是错误的做法 只是后台数据不强, 因为不管你什么算法 都是对这个图跑最短路, 而这个图 本身就是超时的 边数太多了;
. 因为是两个集合间 完全映射 共N*M条边, 如果可以用虚拟节点 则可以优化为N+M, 但由于这里 这N*M条边 权值都不一样, 没办法优化;

-}

如果就专注于这个图 想着如何在这个图上跑最短路, 注定是无解的, 因为这个图 本身就是超时的… 必须要换个思路 (很难做到, 因为你可能已经陷入那个图里去了…);

你忘记了 上下左右移动 这个操作, 上面分析过 答案对应在二维网格里 一定是一条连续的路径 (即通过上下左右 一步一步的移动), 你之前错误的做法 没有用到移动 而是直接跳过去的 (即从(x,y) 直接跳到 (x1,y1));

即, 我们此时 要从一个点 往他4个方向去移动, 对于一个点(x,y) 他可能会多次经过 目的是为了取字符 比如S="abacadae... 假如网格只有一个点为a的话 那么这点 会多次访问, 但虽然多次访问 但每次访问 他对应的S的下标 是不同的;

因此, 使用(x,y,ind)来表示一个节点: 当前在(x,y)位置 且已经拿到了S[0,1,...,ind)这个子串 的最短路;

同样需要建图, 所谓建图 即节点与节点之间的连线 要怎么连;
对于当前(x,y,ind):
. 如果G[x][y] == S[ind], 则拿当前位置上的字符 即转移到(x,y, ind+1), 代价为1;
. 向4个方向移动 即转移到(dx, dy, ind), 代价也是1;
因此, 这是个BFS-1的模型; (注意, 对于第二种情况 即往4个方向移动, 你不要再去判断 如果G[ dx][ dy] == S[ind] 则就更新(dx, dy, ind+1), 不要这样做 因为这样的话 他的代价是2, 就不是BFS-1的模型了;

也就是, 一个状态 有5个临界点; 虽然和之前一样 节点都是1e6个, 但边数不同了;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值