Open In App

Shortest Path using Meet In The Middle

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.

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

Article Tags :