Problem Statement

My Solution
class Solution:
def numTilePossibilities(self, tiles: str) -> int:
n = len(tiles)
counter = Counter(tiles)
seen = set()
def dfs(start, arr, curr):
if start == n:
return
for i in range(n):
arr[i], arr[0] = arr[0], arr[i]
curr.append(arr[0])
curr_str = ''.join(curr)
freq = Counter(curr_str)
if curr_str not in seen and freq <= counter:
seen.add(curr_str)
dfs(start + 1, arr, curr)
curr.pop()
arr[i], arr[0] = arr[0], arr[i]
dfs(0, list(tiles), [])
return len(seen)
Editorial
Approach 1: Recursion
class Solution:
def numTilePossibilities(self, tiles: str) -> int:
sequences = set()
used = [False] * len(tiles)
# Generate all possible sequences including empty string
self._generate_sequences(tiles, "", used, sequences)
# Subtract 1 to exclude empty string from count
return len(sequences) - 1
def _generate_sequences(
self, tiles: str, current: str, used: list, sequences: set
) -> None:
sequences.add(current)
# Try adding each unused character to current sequence
for pos, char in enumerate(tiles):
if not used[pos]:
used[pos] = True
self._generate_sequences(tiles, current + char, used, sequences)
used[pos] = False
Approach 2: Optimized Recursion
class Solution:
def numTilePossibilities(self, tiles: str) -> int:
# Track frequency of each uppercase letter (A-Z)
char_count = [0] * 26
for char in tiles:
char_count[ord(char) - ord("A")] += 1
# Find all possible sequences using character frequencies
return self._find_sequences(char_count)
def _find_sequences(self, char_count: list) -> int:
total = 0
# Try using each available character
for pos in range(26):
if char_count[pos] == 0:
continue
# Add current character and recurse
total += 1
char_count[pos] -= 1
total += self._find_sequences(char_count)
char_count[pos] += 1
return total
Approach 3: Permutations and Combinations
class Solution:
def numTilePossibilities(self, tiles: str) -> int:
seen = set()
# Sort characters to handle duplicates efficiently
sorted_tiles = "".join(sorted(tiles))
# Find all unique sequences and their permutations
return self._generate_sequences(sorted_tiles, "", 0, seen) - 1
def _factorial(self, n: int) -> int:
if n <= 1:
return 1
result = 1
for num in range(2, n + 1):
result *= num
return result
def _count_permutations(self, seq: str) -> int:
# Calculate permutations using factorial formula
total = self._factorial(len(seq))
# Divide by factorial of each character's frequency
for count in Counter(seq).values():
total //= self._factorial(count)
return total
def _generate_sequences(
self, tiles: str, current: str, pos: int, seen: set
) -> int:
if pos >= len(tiles):
# If new sequence found, count its unique permutations
if current not in seen:
seen.add(current)
return self._count_permutations(current)
return 0
# Try including and excluding current character
return self._generate_sequences(
tiles, current, pos + 1, seen
) + self._generate_sequences(tiles, current + tiles[pos], pos + 1, seen)