0
点赞
收藏
分享

微信扫一扫

854. 相似度为 K 的字符串 : 常规搜索运用题


题目描述

这是 LeetCode 上的 ​​854. 相似度为 K 的字符串​​ ,难度为 困难

Tag : 「启发式搜索」、「AStar 算法」

对于某些非负整数 ​​k​​​ ,如果交换 中两个字母的位置恰好 ​​​k​​​ 次,能够使结果字符串等于 ,则认为字符串 的 相似度为 ​​​k​​ 。

给你两个字母异位词 ,返回 的相似度 ​​​k​​ 的最小值。

示例 1:

输入:s1 = "ab", s2 = "ba"

示例 2:

输入:s1 = "abc", s2 = "bca"

提示:

  • ​s1​​​ 和​​s2​​​  只包含集合​​{'a', 'b', 'c', 'd', 'e', 'f'}​​ 中的小写字母
  • ​s2​​​ 是​​s1​​ 的一个字母异位词

AStar 算法

问题本质为将 ​​s1​​​ 转换为 ​​s2​​​ 的最小操作次数,由于题目确保了 ​​s1​​​ 和 ​​s2​​ 互为字母异位词(必然有解),因此最好的求解方式是使用 AStar 算法。

可直接根据本题规则来设计 AStar 的启发式函数: 对于两个状态 ​​a​​​ 和 ​​b​​ 直接计算出「理论最小转换次数」: 不同字符串的转换成本之和,由于每一次交换最多可减少两个不同的字符,我们可计算 a​b​ 的不同字符数量 ,对应的理论最小转换次数为

需要注意的是:由于我们衡量某个字符 str 的估值是以目标字符串 ​target​ 为基准,因此我们只能确保 ​target​ 出队时为「距离最短」,而不能确保中间节点出队时「距离最短」,因此我们不能单纯根据某个节点是否「曾经入队」而决定是否入队,还要结合当前节点的「最小距离」是否被更新而决定是否入队。

一些细节:在使用当前状态(字符串)​​poll​​​ 拓展新状态(字符串)​​nstr​​ 时,只拓展能够减少不同字符数量的方案,从而收窄搜索空间。

Java 代码:

class Solution {
int n;
String t;
int f(String s) {
int ans = 0;
for (int i = 0; i < n; i++) ans += s.charAt(i) != t.charAt(i) ? 1 : 0;
return ans + 1 >> 1;
}
public int kSimilarity(String s1, String s2) {
if (s1.equals(s2)) return 0;
t = s2;
n = s1.length();
Map<String, Integer> map = new HashMap<>();
PriorityQueue<String> pq = new PriorityQueue<>((a,b)->{
int v1 = f(a), v2 = f(b), d1 = map.get(a), d2 = map.get(b);
return (v1 + d1) - (v2 + d2);
});
map.put(s1, 0);
pq.add(s1);
while (!pq.isEmpty()) {
String poll = pq.poll();
int step = map.get(poll);
char[] cs = poll.toCharArray();
int idx = 0;
while (idx < n && cs[idx] == t.charAt(idx)) idx++;
for (int i = idx + 1; i < n; i++) {
if (cs[i] == t.charAt(idx) && cs[i] != t.charAt(i)) {
swap(cs, idx, i);
String nstr = String.valueOf(cs);
if (map.containsKey(nstr) && map.get(nstr) <= step + 1) continue;
if (nstr.equals(t)) return step + 1;
map.put(nstr, step + 1);
pq.add(nstr);
swap(cs, idx, i);
}
}
}
return -1; // never
}
void swap(char[] cs, int i, int {
char c =

  • 时间复杂度:启发式搜索不分析时空复杂度
  • 空间复杂度:启发式搜索不分析时空复杂度

最后

这是我们「刷穿 LeetCode」系列文章的第 ​​No.854​​ 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:​​github.com/SharingSour…​​ 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。


举报

相关推荐

0 条评论