Open In App

Shortest Path using Meet In The Middle

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

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++




// 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




// 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




# 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#




// 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


Javascript




<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


Last Updated : 14 Jan, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads