Given a permutation P = p1, p2, ...., pn of first n natural numbers (1 ? n ? 10). One can swap any two consecutive elements pi and pi + 1 (1 ? i < n). The task is to find the minimum number of swaps to change P to another permutation P' = p'1, p'2, ...., p'n.
Examples:
Input: P = "213", P' = "321"
Output: 2
213 <-> 231 <-> 321

Input: P = "1234", P' = "4123"
Output: 3
Approach: This problem can be solved using Dijkstra's Shortest Path Algorithm. Seem like there is nothing related to a graph in the statement. But assume one permutation is one vertex, then every swap of a permutation's elements is an edge which connects this vertex with another vertex. So finding the minimum number of swaps now becomes a simple BFS/shortest path problem.
Now let's analyze time complexity. We have n! vertices, each vertex has n - 1 adjacent vertices. We also have to store vertices visited state by map because their representations are hard to be stored by normal arrays. So total time complexity is O(N log(N!) * N!). Meet In The Middle technique can be used to make the solution faster.
Meet In The Middle solution is similar to Dijkstra's solution with some modifications.
- Let P be the start vertex and P' be the finish Vertex.
- Let both start and finish be roots. We start BFS from both the roots, start and finish at the same time but using only one queue.
- Push start and finish into queue's back, visitedstart = visitedfinish = true.
- Let srcu be the root of vertex u in BFS progression. So, srcstart = start and srcfinish = finish.
- Let Du be the shortest distance from vertex u to it's tree's root. So Dstart = Dfinish = 0.
- While queue is not empty, pop queue's front which is vertex u then push all vertices v which are adjacent with u and haven't been visited yet (visitedv = false) into queue's back, then let Dv = Du + 1, srcv = srcu and visitedv = true. Especially, if v was visited and srcv != srcu then we can immediately return Du + Dv + 1.
Below is the implementation of the above approach:
// C++ implementation of the approach
#include <bits/stdc++.h>
using namespace std;
// Function to find minimum number of
// swaps to make another permutation
int ShortestPath(int n, string start, string finish)
{
unordered_map<string, bool> visited;
unordered_map<string, int> D;
unordered_map<string, string> src;
visited[start] = visited[finish] = true;
D[start] = D[finish] = 0;
src[start] = start;
src[finish] = finish;
queue<string> q;
q.push(start);
q.push(finish);
while (!q.empty()) {
// Take top vertex of the queue
string u = q.front();
q.pop();
// Generate n - 1 of it's permutations
for (int i = 1; i < n; i++) {
// Generate next permutation
string v = u;
swap(v[i], v[i - 1]);
// If v is not visited
if (!visited[v]) {
// Set it visited
visited[v] = true;
// Make root of u and root of v equal
src[v] = src[u];
// Increment it's distance by 1
D[v] = D[u] + 1;
// Push this vertex into queue
q.push(v);
}
// If it is already visited
// and roots are different
// then answer is found
else if (src[u] != src[v])
return D[u] + D[v] + 1;
}
}
}
// Driver code
int main()
{
string p1 = "1234", p2 = "4123";
int n = p1.length();
cout << ShortestPath(n, p1, p2);
return 0;
}
// Java implementation of the approach
import java.util.*;
class GFG{
// Function to find minimum number of
// swaps to make another permutation
static int ShortestPath(int n, String start,
String finish)
{
HashMap<String,
Boolean> visited = new HashMap<String,
Boolean>();
HashMap<String,
Integer> D = new HashMap<String,
Integer>();
HashMap<String,
String> src = new HashMap<String,
String>();
visited.put(start, true);
visited.put(finish, true);
D.put(start, 0);
D.put(finish, 0);
src.put(start, start);
src.put(finish, finish);
Queue<String> q = new LinkedList<>();
q.add(start);
q.add(finish);
while (q.size() != 0)
{
// Take top vertex of the queue
String u = (String)q.peek();
q.remove();
// Generate n - 1 of it's permutations
for(int i = 1; i < n; i++)
{
// Generate next permutation
StringBuilder tmp = new StringBuilder(u);
char t = tmp.charAt(i);
tmp.setCharAt(i, tmp.charAt(i - 1));
tmp.setCharAt(i - 1, t);
String v = tmp.toString();
// If v is not visited
if (!visited.getOrDefault(v, false))
{
// Set it visited
visited.put(v, true);
// Make root of u and root of v equal
src.put(v, src.get(u));
// Increment it's distance by 1
D.put(v, D.get(u) + 1);
// Push this vertex into queue
q.add(v);
}
// If it is already visited
// and roots are different
// then answer is found
else if (src.get(u) != src.get(v))
return D.get(u) + D.get(v) + 1;
}
}
return 0;
}
// Driver Code
public static void main(String[] args)
{
String p1 = "1234", p2 = "4123";
int n = p1.length();
System.out.println(ShortestPath(n, p1, p2));
}
}
// This code is contributed by pratham76
# Python3 implementation of the approach
from collections import deque, defaultdict
# Function to find minimum number of
# swaps to make another permutation
def shortestPath(n: int, start: str, finish: str) -> int:
visited, D, src = defaultdict(lambda: False), defaultdict(
lambda: 0), defaultdict(lambda: '')
visited[start] = visited[finish] = True
D[start] = D[finish] = 0
src[start], src[finish] = start, finish
q = deque()
q.append(start)
q.append(finish)
while q:
# Take top vertex of the queue
u = q[0]
q.popleft()
# Generate n - 1 of it's permutations
for i in range(n):
v = list(u)
v[i], v[i - 1] = v[i - 1], v[i]
v = ''.join(v)
if not visited[v]:
# Set it visited
visited[v] = True
# Make root of u and root of v equal
src[v] = src[u]
# Increment it's distance by 1
D[v] = D[u] + 1
# Push this vertex into queue
q.append(v)
# If it is already visited
# and roots are different
# then answer is found
elif u in src and src[u] != src[v]:
return D[u] + D[v] + 1
# Driver Code
if __name__ == "__main__":
p1 = "1234"
p2 = "4123"
n = len(p1)
print(shortestPath(n, p1, p2))
# This code is contributed by
# sanjeev2552
// C# implementation of the approach
using System;
using System.Collections;
using System.Text;
using System.Collections.Generic;
class GFG{
// Function to find minimum number of
// swaps to make another permutation
static int ShortestPath(int n, string start,
string finish)
{
Dictionary<string,
bool> visited = new Dictionary<string,
bool>();
Dictionary<string,
int> D = new Dictionary<string,
int>();
Dictionary<string,
string> src = new Dictionary<string,
string>();
visited[start] = true;
visited[finish] = true;
D[start] = 0;
D[finish] = 0;
src[start] = start;
src[finish] = finish;
Queue q = new Queue();
q.Enqueue(start);
q.Enqueue(finish);
while (q.Count != 0)
{
// Take top vertex of the queue
string u = (string)q.Peek();
q.Dequeue();
// Generate n - 1 of it's permutations
for(int i = 1; i < n; i++)
{
// Generate next permutation
StringBuilder tmp = new StringBuilder(u);
char t = tmp[i];
tmp[i] = tmp[i - 1];
tmp[i - 1] = t;
string v = tmp.ToString();
// If v is not visited
if (!visited.GetValueOrDefault(v, false))
{
// Set it visited
visited[v] = true;
// Make root of u and root of v equal
src[v] = src[u];
// Increment it's distance by 1
D[v] = D[u] + 1;
// Push this vertex into queue
q.Enqueue(v);
}
// If it is already visited
// and roots are different
// then answer is found
else if (src[u] != src[v])
return D[u] + D[v] + 1;
}
}
return 0;
}
// Driver Code
public static void Main(string[] args)
{
string p1 = "1234", p2 = "4123";
int n = p1.Length;
Console.Write(ShortestPath(n, p1, p2));
}
}
// This code is contributed by rutvik_56
<script>
// Function to find minimum number of
// swaps to make another permutation
function ShortestPath(n, start, finish) {
let visited = new Map();
let D = new Map();
let src = new Map();
visited.set(start, true);
visited.set(finish, true);
D.set(start, 0);
D.set(finish, 0);
src.set(start, start);
src.set(finish, finish);
let q = [];
q.push(start);
q.push(finish);
while (q.length > 0) {
// Take top vertex of the queue
let u = q.shift();
// Generate n - 1 of it's permutations
for (let i = 1; i < n; i++) {
// Generate next permutation
let v = u;
let temp = v[i];
v = v.substring(0, i) + v[i - 1] + v.substring(i + 1);
v = v.substring(0, i - 1) + temp + v.substring(i);
// If v is not visited
if (!visited.has(v)) {
// Set it visited
visited.set(v, true);
// Make root of u and root of v equal
src.set(v, src.get(u));
// Increment it's distance by 1
D.set(v, D.get(u) + 1);
// Push this vertex into queue
q.push(v);
}
// If it is already visited
// and roots are different
// then answer is found
else if (src.get(u) !== src.get(v))
return D.get(u) + D.get(v) + 1;
}
}
}
// Driver code
function main() {
let p1 = "1234", p2 = "4123";
let n = p1.length;
console.log(ShortestPath(n, p1, p2));
}
main();
</script>
Output
3