graph TD;
A[1]
B[4]
C[3]
D[7]
E[6]
F[8]
G[5]
H[9]
I[10]
A --> B & C
B --> D & E
C --> F & G
F --> H
F ~~~ N1:::hidden
G --> I
G ~~~ N2:::hidden
classDef hidden display: none;
1
2
3
4
5
6
7
8
Input: root = [1,4,3,7,6,8,5,null,null,null,null,9,null,10]
Output: 3Explanation:
- Swap 4and3. The 2nd level becomes [3,4].- Swap 7and5. The 3rd level becomes [5,6,8,7].- Swap 8and7. The 3rd level becomes [5,6,7,8].We used 3 operations so return3.It can be proven that 3is the minimum number of operations needed.
Example 2:
graph TD;
A[1]
B[3]
C[2]
D[7]
E[6]
F[5]
G[4]
A --> B & C
B --> D & E
C --> F & G
1
2
3
4
5
6
7
8
Input: root =[1,3,2,7,6,5,4]Output: 3Explanation:
- Swap 3 and 2. The 2nd level becomes [2,3].- Swap 7 and 4. The 3rd level becomes [4,6,5,7].- Swap 6 and 5. The 3rd level becomes [4,5,6,7].We used 3 operations so return3.It can be proven that 3is the minimum number of operations needed.
Example 3:
graph TD;
A[1]
B[2]
C[3]
D[4]
E[5]
F[6]
A --> B & C
B --> D & E
C --> F
C ~~~ N1:::hidden
classDef hidden display: none;
1
2
3
Input: root =[1,2,3,4,5,6]Output: 0Explanation: Each level is already sorted in increasing order so return0.
Constraints:
The number of nodes in the tree is in the range [1, 10^5].
Sorting with Minimum Swaps: For each level of nodes, determine the minimum number of swaps needed to sort the nodes in strictly increasing order. This can be efficiently determined using the concept of cycle decomposition from graph theory.
Cycle sort is a technique used to address problems requiring a minimum number of swaps or finding missing numbers within a given range. Using cycle sort allows us to efficiently compute the minimum swaps needed to sort the values at each level in strictly increasing order.
classSolution:
defminimumOperations(self, root: Optional[TreeNode]) -> int:
ifnot root:
return0 ans =0 queue = deque([root])
while queue:
level = []
for _ in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
ans += self.minSwaps(level)
return ans
defminSwaps(self, arr: List[int]) -> int:
n = len(arr)
arr_pos = sorted(range(n), key=lambda x: arr[x])
visited = [False] * n
ans =0for i in range(n):
if visited[i] or arr_pos[i] == i:
continue cycle_size =0 x = i
whilenot visited[x]:
visited[x] =True x = arr_pos[x]
cycle_size +=1if cycle_size >0:
ans += (cycle_size -1)
return ans
⏰ Time complexity: O(n log n) where n is the number of nodes in the binary tree. This includes O(n) for level order traversal and O(n log n) for sorting and calculating minimum swaps.
🧺 Space complexity: O(n) to store the nodes at each level during the traversal.
The trick is to count the number of swaps needed by obtaining the array of numbers at a particular level using BFS traversal. To calculate the count in linear complexity, we need extra space. We store the level array in an ordered map with indices as values and copy it to a secondary array “sorted”. We then sort “sorted” to find the correct indices of each element. Next, we traverse the original level array “arr” and check if its values are at the correct indices when sorted. If not, we get the original index from the map and swap the elements, gradually sorting the “arr” array.
Here is the approach:
Level Order Traversal: Traverse the tree level by level using BFS to get the array of node values at each level.
Sorting with Minimum Swaps (Using HashMap):
Use extra space to handle the node values efficiently.
Add the level array to an ordered map with indices as values and also copy it to a secondary array (sorted).
Sort the secondary array to get the correct indices of each element.
Traverse the original level array (arr) and check if its values are at the correct indices as per the sorted array.
If not at the correct position, get the original index from the map and swap the elements to gradually sort the original array.
classSolution:
defminimumOperations(self, root: Optional[TreeNode]) -> int:
ifnot root:
return0 ans =0 queue = deque([root])
while queue:
level = []
for _ in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
ans += self.minSwaps(level)
return ans
defminSwaps(self, arr: List[int]) -> int:
n = len(arr)
numToIdxMap = {}
for i in range(n):
numToIdxMap[arr[i]] = i
sorted_lst = list(arr)
sorted_lst.sort()
swaps =0for i in range(n):
if arr[i] != sorted_lst[i]:
swaps +=1 a = arr[i]
b = sorted_lst[i]
# Swap the values arr[numToIdxMap[b]] = a
numToIdxMap[a] = numToIdxMap[b]
arr[i] = b
numToIdxMap[b] = i
return swaps
⏰ Time complexity: O(n log n) where n is the number of nodes in the binary tree. This includes O(n) for level order traversal and O(n log n) for sorting and calculating minimum swaps.
🧺 Space complexity: O(n) to store the nodes at each level during the traversal.