This problem is tricky conceptually. Ultimately it is a permutation graph problem. We define the nodes of the graph as two adjacent seats, so the first node is the two people sitting at 0 and 1, the second node is the two people sitting at 2 and 3, etc. We draw a edge between two nodes if one part of a couple is one node and the other partner is in the other node. This way a couple already sitting next to each other form a node whose only edge points to itself. A couple that has been split apart will be in two separate nodes, with the nodes connected by an edge. At this point we'll have a bunch of isolated nodes, and a bunch of cycles. The isolated nodes are couples that are already sitting next to each other. The cycles are couples that need to be swapped into place, so each cycle of k nodes will require k - 1 swaps.
This gives us the overall algorithm: create a graph out of the couples, and then use union-find to find the connected components of the graph. Once we have the components, we can count the number of swaps by sum(size of each component - 1). Alternatively, we can keep track of the number of union operations, since each union represents a swap that needs to be made.
O(n) time (Union-find is linear time for all practical purposes)
O(n) space
class Solution:
def minSwapsCouples(self, row: List[int]) -> int:
couches = {}
self.swaps = len(row) / 2
parents = {}
sizes = {}
def find(A):
if parents[A] != A:
parents[A] = find(parents[A])
return parents[A]
def union(A, B):
parent1 = find(A)
parent2 = find(B)
if parent1 == parent2:
return
if sizes[parent1] < sizes[parent2]:
parent1, parent2 = parent2, parent1
parents[parent2] = parent1
if sizes[parent1] == sizes[parent2]:
sizes[parent1] += 1
self.swaps -= 1
for couch in range(len(row) // 2):
parents[couch] = couch
sizes[couch] = 1
for couch in range(len(row) // 2):
a = row[couch * 2]
b = row[couch * 2 + 1]
union(a // 2, b // 2)
return int(len(row) / 2 - self.swaps)