LeetCode 记录-854. 相似度为 K 的字符串
我的解法
思路
看到相似度 k 的最小值,脑子里第一个闪出来的做法是用动态规划。但是不知道该怎么去动态规划。
官方解法 1: 广度优先搜索
思路
这和我所理解的广度优先搜索算法有所不同(我之前一直觉得和树相关的才能用)。在这里,我理解之所以称为 BFS 解法的原因,是用了一个 queue 去遍历所有交换一次、两次、三次...k 次的情况,一直到找到交换 k 次后使得两个字符串相同再停止,这时候的 k 就是最小的交换次数。
代码
var kSimilarity = function (s1, s2) {
const n = s1.length;
const queue = [];
const visit = new Set();
queue.push([s1, 0]);
visit.add(s1);
let step = 0;
while (queue.length) {
const sz = queue.length;
for (let i = 0; i < sz; i++) {
let [cur, pos] = queue.shift();
if (cur === s2) {
return step;
}
while (pos < n && cur[pos] === s2[pos]) {
pos++;
}
for (let j = pos + 1; j < n; j++) {
if (s2[j] === cur[j]) {
continue;
}
if (s2[pos] === cur[j]) {
const next = swap(cur, pos, j);
if (!visit.has(next)) {
visit.add(next);
queue.push([next, pos + 1]);
}
}
}
}
step++;
}
return step;
};
const swap = (cur, i, j) => {
const arr = [...cur];
const c = arr[i];
arr[i] = arr[j];
arr[j] = c;
return arr.join("");
};
复杂度分析
该方法时空复杂度分析较为复杂,暂不讨论。
官方解法 2: 深度优先搜索
思路
这个算法相对于 BFS 的区别就是优先搜索同一个子状态下所有交换次数的可能。能体会到这两种算法在非树形结构上的差异。
同时,它用来剪枝的思路也是非常有意思,但是也是比较难想到的。
代码
var kSimilarity = function (s1, s2) {
let str1 = "";
let str2 = "";
for (let i = 0; i < s1.length; i++) {
if (s1[i] !== s2[i]) {
str1 += s1[i];
str2 += s2[i];
}
}
if (str1.length === 0) {
return 0;
}
let ans = str1.length - 1;
const dfs = (pos, cost, len, str1, str2) => {
if (cost > ans) {
return;
}
while (pos < str1.length && str1[pos] === str2[pos]) {
pos++;
}
if (pos === str1.length) {
ans = Math.min(ans, cost);
return;
}
/* 当前状态的交换次数下限大于等于当前的最小交换次数 */
if (cost + minSwap(str1, str2, pos) >= ans) {
return;
}
for (let i = pos + 1; i < str1.length; i++) {
if (str1[i] === str2[pos]) {
const str1Next = swap(str1, i, pos);
dfs(pos + 1, cost + 1, len, str1Next, str2);
}
}
};
const minSwap = (s1, s2, pos) => {
let tot = 0;
for (let i = pos; i < s1.length; i++) {
tot += s1[i] !== s2[i] ? 1 : 0;
}
return Math.floor((tot + 1) / 2);
};
const swap = (cur, i, j) => {
const arr = [...cur];
const c = arr[i];
arr[i] = arr[j];
arr[j] = c;
return arr.join("");
};
dfs(0, 0, str1.length, str1, str2);
return ans;
};
复杂度分析
该方法时空复杂度分析较为复杂,暂不讨论。
官方解法 3:动态规划
该解法思维难度较大且时间复杂度较高,就先不看了。