Welcome to Subscribe On Youtube
854. K-Similar Strings
Description
Strings s1 and s2 are k-similar (for some non-negative integer k) if we can swap the positions of two letters in s1 exactly k times so that the resulting string equals s2.
Given two anagrams s1 and s2, return the smallest k for which s1 and s2 are k-similar.
Example 1:
Input: s1 = "ab", s2 = "ba" Output: 1 Explanation: The two string are 1-similar because we can use one swap to change s1 to s2: "ab" --> "ba".
Example 2:
Input: s1 = "abc", s2 = "bca" Output: 2 Explanation: The two strings are 2-similar because we can use two swaps to change s1 to s2: "abc" --> "bac" --> "bca".
Constraints:
1 <= s1.length <= 20s2.length == s1.lengths1ands2contain only lowercase letters from the set{'a', 'b', 'c', 'd', 'e', 'f'}.s2is an anagram ofs1.
Solutions
Solution 1
BFS.
Solution 2
A* search algorithm (A* pronounced as A-star), referred to as A* algorithm, is an algorithm that finds the lowest pass cost for a path with multiple nodes on the graphics plane. It belongs to graph traversal and best-first search algorithms (English: Best-first search), and is also an improvement of BFS.
The main steps of the A* algorithm are as follows:
- Convert the BFS queue in method 1 to a priority queue (small root heap);
- Each element in the queue is
(dist[s] + f(s), s),dist[s]represents the distance from the initial state $s_1$ to the current state $s$, andf(s)represents the estimated distance from the current state $s$ to the target state $s_2$. The sum of these two distances is used as the basis for heap sorting; - When the end point is dequeued for the first time, it means that the shortest path from the starting point $s_1$ to the end point $s_2$ has been found, and the corresponding distance is returned directly;
f(s)is the valuation function, and the valuation function must satisfyf(s) <= g(s), whereg(s)represents the real distance from $s$ to the end point $s_2$;
It should be noted that the A* algorithm can only guarantee that when the end point is dequeued for the first time, it will find a minimum path from the starting point to the end point. It cannot guarantee that when other points are dequeued, it will also be the shortest path from the starting point to the current point.
Complexity analysis: Heuristic search does not discuss time and space complexity.
-
class Solution { public int kSimilarity(String s1, String s2) { Deque<String> q = new ArrayDeque<>(); Set<String> vis = new HashSet<>(); q.offer(s1); vis.add(s1); int ans = 0; while (true) { for (int i = q.size(); i > 0; --i) { String s = q.pollFirst(); if (s.equals(s2)) { return ans; } for (String nxt : next(s, s2)) { if (!vis.contains(nxt)) { vis.add(nxt); q.offer(nxt); } } } ++ans; } } private List<String> next(String s, String s2) { int i = 0, n = s.length(); char[] cs = s.toCharArray(); for (; cs[i] == s2.charAt(i); ++i) { } List<String> res = new ArrayList<>(); for (int j = i + 1; j < n; ++j) { if (cs[j] == s2.charAt(i) && cs[j] != s2.charAt(j)) { swap(cs, i, j); res.add(new String(cs)); swap(cs, i, j); } } return res; } private void swap(char[] cs, int i, int j) { char t = cs[i]; cs[i] = cs[j]; cs[j] = t; } } // Solution 2 class Solution { public int kSimilarity(String s1, String s2) { PriorityQueue<Pair<Integer, String>> q = new PriorityQueue<>(Comparator.comparingInt(Pair::getKey)); q.offer(new Pair<>(f(s1, s2), s1)); Map<String, Integer> dist = new HashMap<>(); dist.put(s1, 0); while (true) { String s = q.poll().getValue(); if (s.equals(s2)) { return dist.get(s); } for (String nxt : next(s, s2)) { if (!dist.containsKey(nxt) || dist.get(nxt) > dist.get(s) + 1) { dist.put(nxt, dist.get(s) + 1); q.offer(new Pair<>(dist.get(nxt) + f(nxt, s2), nxt)); } } } } private int f(String s, String s2) { int cnt = 0; for (int i = 0; i < s.length(); ++i) { if (s.charAt(i) != s2.charAt(i)) { ++cnt; } } return (cnt + 1) >> 1; } private List<String> next(String s, String s2) { int i = 0, n = s.length(); char[] cs = s.toCharArray(); for (; cs[i] == s2.charAt(i); ++i) { } List<String> res = new ArrayList<>(); for (int j = i + 1; j < n; ++j) { if (cs[j] == s2.charAt(i) && cs[j] != s2.charAt(j)) { swap(cs, i, j); res.add(new String(cs)); swap(cs, i, j); } } return res; } private void swap(char[] cs, int i, int j) { char t = cs[i]; cs[i] = cs[j]; cs[j] = t; } } -
class Solution { public: int kSimilarity(string s1, string s2) { queue<string> q{ {s1} }; unordered_set<string> vis{ {s1} }; int ans = 0; while (1) { for (int i = q.size(); i; --i) { auto s = q.front(); q.pop(); if (s == s2) { return ans; } for (auto& nxt : next(s, s2)) { if (!vis.count(nxt)) { vis.insert(nxt); q.push(nxt); } } } ++ans; } } vector<string> next(string& s, string& s2) { int i = 0, n = s.size(); for (; s[i] == s2[i]; ++i) {} vector<string> res; for (int j = i + 1; j < n; ++j) { if (s[j] == s2[i] && s[j] != s2[j]) { swap(s[i], s[j]); res.push_back(s); swap(s[i], s[j]); } } return res; } }; // Solution 2 using pis = pair<int, string>; class Solution { public: int kSimilarity(string s1, string s2) { priority_queue<pis, vector<pis>, greater<pis>> q; q.push({f(s1, s2), s1}); unordered_map<string, int> dist; dist[s1] = 0; while (1) { auto [_, s] = q.top(); q.pop(); if (s == s2) { return dist[s]; } for (auto& nxt : next(s, s2)) { if (!dist.count(nxt) || dist[nxt] > dist[s] + 1) { dist[nxt] = dist[s] + 1; q.push({dist[nxt] + f(nxt, s2), nxt}); } } } } int f(string& s, string& s2) { int cnt = 0; for (int i = 0; i < s.size(); ++i) { cnt += s[i] != s2[i]; } return (cnt + 1) >> 1; } vector<string> next(string& s, string& s2) { int i = 0, n = s.size(); for (; s[i] == s2[i]; ++i) {} vector<string> res; for (int j = i + 1; j < n; ++j) { if (s[j] == s2[i] && s[j] != s2[j]) { swap(s[i], s[j]); res.push_back(s); swap(s[i], s[j]); } } return res; } }; -
class Solution: def kSimilarity(self, s1: str, s2: str) -> int: def next(s): i = 0 while s[i] == s2[i]: i += 1 res = [] for j in range(i + 1, n): if s[j] == s2[i] and s[j] != s2[j]: res.append(s2[: i + 1] + s[i + 1 : j] + s[i] + s[j + 1 :]) return res q = deque([s1]) vis = {s1} ans, n = 0, len(s1) while 1: for _ in range(len(q)): s = q.popleft() if s == s2: return ans for nxt in next(s): if nxt not in vis: vis.add(nxt) q.append(nxt) ans += 1 # Solution 2 class Solution: def kSimilarity(self, s1: str, s2: str) -> int: def f(s): cnt = sum(c != s2[i] for i, c in enumerate(s)) return (cnt + 1) >> 1 def next(s): i = 0 while s[i] == s2[i]: i += 1 res = [] for j in range(i + 1, n): if s[j] == s2[i] and s[j] != s2[j]: res.append(s2[: i + 1] + s[i + 1 : j] + s[i] + s[j + 1 :]) return res q = [(f(s1), s1)] dist = {s1: 0} n = len(s1) while 1: _, s = heappop(q) if s == s2: return dist[s] for nxt in next(s): if nxt not in dist or dist[nxt] > dist[s] + 1: dist[nxt] = dist[s] + 1 heappush(q, (dist[nxt] + f(nxt), nxt)) -
func kSimilarity(s1 string, s2 string) int { next := func(s string) []string { i := 0 res := []string{} for ; s[i] == s2[i]; i++ { } for j := i + 1; j < len(s1); j++ { if s[j] == s2[i] && s[j] != s2[j] { res = append(res, s[:i]+string(s[j])+s[i+1:j]+string(s[i])+s[j+1:]) } } return res } q := []string{s1} vis := map[string]bool{s1: true} ans := 0 for { for i := len(q); i > 0; i-- { s := q[0] q = q[1:] if s == s2 { return ans } for _, nxt := range next(s) { if !vis[nxt] { vis[nxt] = true q = append(q, nxt) } } } ans++ } } // Solution 2 func kSimilarity(s1 string, s2 string) int { next := func(s string) []string { i := 0 res := []string{} for ; s[i] == s2[i]; i++ { } for j := i + 1; j < len(s1); j++ { if s[j] == s2[i] && s[j] != s2[j] { res = append(res, s[:i]+string(s[j])+s[i+1:j]+string(s[i])+s[j+1:]) } } return res } f := func(s string) int { cnt := 0 for i := range s { if s[i] != s2[i] { cnt++ } } return (cnt + 1) >> 1 } q := hp{pair{f(s1), s1}} dist := map[string]int{s1: 0} for { s := heap.Pop(&q).(pair).s if s == s2 { return dist[s] } for _, nxt := range next(s) { if v, ok := dist[nxt]; !ok || v > dist[s]+1 { dist[nxt] = dist[s] + 1 heap.Push(&q, pair{dist[nxt] + f(nxt), nxt}) } } } } type pair struct { v int s string } type hp []pair func (h hp) Len() int { return len(h) } func (h hp) Less(i, j int) bool { a, b := h[i], h[j] return a.v < b.v } func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *hp) Push(v any) { *h = append(*h, v.(pair)) } func (h *hp) Pop() any { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }