Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to find how many distinct rotation groups are there for a list of words in Python
Suppose we have a rotation group for a string that holds all of its unique rotations. If the input is like "567" then this can be rotated to "675" and "756" and they are all in the same rotation group. Now if we have a list of strings words, we have to group each word by their rotation group, and find the total number of groups.
So, if the input is like words = ["xyz", "ab", "ba", "c", "yzx"], then the output will be 3, as there are three rotation groups − ["xyz", "yzx"], ["ab", "ba"], ["c"].
Algorithm
To solve this, we will follow these steps −
- Create a set to store all seen rotations
- Initialize counter to 0
- For each word in the input list:
- If the word is not already in our set, increment counter
- Generate all rotations of the current word and add them to the set
- Return the counter
Example
class Solution:
def solve(self, words):
seen_rotations = set()
group_count = 0
for word in words:
if word not in seen_rotations:
group_count += 1
# Generate all rotations of the current word
for j in range(len(word)):
rotation = word[j:] + word[:j]
seen_rotations.add(rotation)
return group_count
# Test the solution
ob = Solution()
words = ["xyz", "ab", "ba", "c", "yzx"]
result = ob.solve(words)
print(f"Number of distinct rotation groups: {result}")
Number of distinct rotation groups: 3
How It Works
Let's trace through the example step by step ?
def trace_rotation_groups(words):
seen_rotations = set()
group_count = 0
for word in words:
print(f"Processing word: '{word}'")
if word not in seen_rotations:
group_count += 1
print(f" New rotation group found! Count: {group_count}")
else:
print(f" '{word}' already seen in a rotation group")
# Generate all rotations
rotations = []
for j in range(len(word)):
rotation = word[j:] + word[:j]
rotations.append(rotation)
seen_rotations.add(rotation)
print(f" All rotations: {rotations}")
print(f" Seen rotations so far: {seen_rotations}")
print()
return group_count
words = ["xyz", "ab", "ba", "c", "yzx"]
result = trace_rotation_groups(words)
print(f"Total rotation groups: {result}")
Processing word: 'xyz' New rotation group found! Count: 1 All rotations: ['xyz', 'yzx', 'zxy'] Processing word: 'ab' New rotation group found! Count: 2 All rotations: ['ab', 'ba'] Processing word: 'ba' 'ba' already seen in a rotation group All rotations: ['ba', 'ab'] Processing word: 'c' New rotation group found! Count: 3 All rotations: ['c'] Processing word: 'yzx' 'yzx' already seen in a rotation group All rotations: ['yzx', 'zxy', 'xyz'] Total rotation groups: 3
Alternative Approach Using Canonical Form
We can also solve this by finding the lexicographically smallest rotation for each word ?
def count_rotation_groups_canonical(words):
def get_canonical_rotation(word):
"""Get the lexicographically smallest rotation"""
rotations = [word[i:] + word[:i] for i in range(len(word))]
return min(rotations)
canonical_forms = set()
for word in words:
canonical = get_canonical_rotation(word)
canonical_forms.add(canonical)
return len(canonical_forms)
# Test with the same example
words = ["xyz", "ab", "ba", "c", "yzx"]
result = count_rotation_groups_canonical(words)
print(f"Number of rotation groups: {result}")
# Show canonical forms
canonical_forms = set()
for word in words:
rotations = [word[i:] + word[:i] for i in range(len(word))]
canonical = min(rotations)
canonical_forms.add(canonical)
print(f"'{word}' -> canonical: '{canonical}'")
print(f"Unique canonical forms: {canonical_forms}")
Number of rotation groups: 3
'xyz' -> canonical: 'xyz'
'ab' -> canonical: 'ab'
'ba' -> canonical: 'ab'
'c' -> canonical: 'c'
'yzx' -> canonical: 'xyz'
Unique canonical forms: {'xyz', 'ab', 'c'}
Conclusion
Both approaches effectively count distinct rotation groups by either tracking all seen rotations or using canonical forms. The first method is more direct, while the canonical form approach provides cleaner grouping logic for complex scenarios.
