Letter Tile Possibilities solution and explanation
9 more videos on this problem
Letter Tile Possibilities - Leetcode 1079 - PythonNeetCodeIO · 13:28 · 14K views
Letter Tile Possibilities | 2 Ways | Using Standard Template | Leetcode 1079 | codestorywithMIKcodestorywithMIK · 29:24 · 12K views
Letter Tile Possibilities | Leetcode 1079Techdose · 19:49 · 6K views
LeetCode 1079. Letter Tile Possibilities Solution Explained - JavaAlgorithms and Data Structures Course · 5:30 · 4K views
LeetCode #1079 - Letter Tile Possibilities: BacktrackingGDSC FIU · 12:28 · 3K views
1079. Letter Tile Possibilities | Backtracking | Math + RecursionAryan Mittal · 26:43 · 3K views
1079. Letter Tile Possibilities | leetcode daily challenge | shashcode | java | dsa | shashwatShashCode · 19:27 · 2K views
LeetCode 1079 - Letter Tile Possibilities | Dynamic Programming & Factorial Precomputation ExplainedRAHUL VIJAYAN · 21:40 · 1K views
LeetCode - 1079. Letter Tile Possibilities | Backtracking | JavaOrkhan Gasanov · 9:55 · 1K views
Letter Tile Possibilities || LeetCode || 1079 || BacktrackingPerceiver · 8:07 · 735 views
The problem
You have n tiles, where each tile has one letter tiles[i] printed on it.
Return the number of possible non-empty sequences of letters you can make using the letters printed on those tiles.
Example 1:
Input: tiles = "AAB" Output: 8 Explanation: The possible sequences are "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA".
Example 2:
Input: tiles = "AAABBC" Output: 188
Example 3:
Input: tiles = "V" Output: 1
Constraints:
1 <= tiles.length <= 7tilesconsists of uppercase English letters.
Approach overview
Problem Overview: You are given a set of letter tiles where each tile has a character printed on it. The task is to count how many distinct non‑empty sequences you can form using those tiles. Each tile can be used at most once per sequence, and sequences with the same letters but different orders count as different results.
Approach 1: Backtracking with Set (O(n! * n) time, O(n! * n) space)
This approach explicitly generates every possible sequence using backtracking. Start with an empty path and recursively append unused characters. At each step, mark a tile as used, append it to the current sequence, and explore deeper. Because duplicate characters may exist (e.g., "AAB"), store generated sequences in a set to avoid counting duplicates. Each recursive call inserts the current string into the set and continues exploring longer permutations. The algorithm essentially enumerates permutations of all possible lengths from 1 to n. Worst‑case time complexity is O(n! * n) because building and storing strings costs O(n), and the number of permutations grows factorially. Space complexity is also O(n! * n) due to storing all unique sequences.
Approach 2: DFS with Frequency Map (O(n! * n) time, O(n) space)
A more efficient strategy avoids generating duplicate sequences by tracking character counts with a frequency map. Build a map using a hash table where each character stores how many tiles remain. Then perform DFS: iterate through each character whose count is greater than zero, place it into the sequence, decrement its count, and recurse. Every time you choose a character, you increment the total number of valid sequences. After recursion, restore the count (classic backtracking step). Because the algorithm works directly on character frequencies, it never generates duplicate permutations even when tiles repeat. This dramatically reduces unnecessary work compared to storing strings in a set. Time complexity remains O(n! * n) in the worst case due to permutation growth, but practical performance is significantly better. Space complexity is O(n) for recursion depth and the frequency structure.
Both methods rely on recursive enumeration of sequences derived from a string. The key difference is whether duplicates are filtered afterward with a set or prevented during generation using frequency counts.
Recommended for interviews: DFS with a frequency map is the approach most interviewers expect. It demonstrates understanding of permutation generation, pruning duplicate work, and efficient counting. Implementing the set‑based backtracking first can help you reason about the search space, but the frequency‑map DFS shows stronger algorithmic optimization and cleaner space usage.
Approach 1: Backtracking with Set
This approach uses backtracking to explore all possible permutations of the tile letters. The permutations are stored in a set to ensure uniqueness, allowing us to retrieve non-duplicate sequences effectively. We recursively select tiles, marking them as used, and backtrack to explore other possibilities.
def numTilePossibilities(tiles):
from itertools import permutations
tile_set = set()
def backtrack(path, used):
if path:
tile_set.add(path)
for i in range(len(tiles)):
if used[i]:
continue
if i > 0 and tiles[i] == tiles[i-1] and not used[i-1]:
continue
used[i] = True
backtrack(path + tiles[i], used)
used[i] = False
tiles = ''.join(sorted(tiles))
backtrack('', [False]*len(tiles))
return len(tile_set)import java.util.*;
public class TilePossibilities {
public int numTilePossibilities(String tiles) {
Set<String> uniqueSequences = new HashSet<>();
boolean[] used = new boolean[tiles.length()];
char[] tileArr = tiles.toCharArray();
Arrays.sort(tileArr);
backtrack("", tileArr, uniqueSequences, used);
return uniqueSequences.size();
}
private void backtrack(String path, char[] tiles, Set<String> results, boolean[] used) {
if (!path.isEmpty()) {
results.add(path);
}
for (int i = 0; i < tiles.length; ++i) {
if (used[i] || (i > 0 && tiles[i] == tiles[i-1] && !used[i-1])) {
continue;
}
used[i] = true;
backtrack(path + tiles[i], tiles, results, used);
used[i] = false;
}
}
}#include <iostream>
#include <unordered_set>
#include <algorithm>
using namespace std;
void backtrack(string path, string& tiles, unordered_set<string>& results, vector<bool>& used){
if (!path.empty()) {
results.insert(path);
}
for (int i = 0; i < tiles.size(); ++i) {
if (used[i] || (i > 0 && tiles[i] == tiles[i-1] && !used[i-1])) {
continue;
}
used[i] = true;
backtrack(path + tiles[i], tiles, results, used);
used[i] = false;
}
}
int numTilePossibilities(string tiles) {
unordered_set<string> results;
vector<bool> used(tiles.size(), false);
sort(tiles.begin(), tiles.end());
backtrack("", tiles, results, used);
return results.size();
}This solution uses backtracking to explore all possible permutations. We maintain an array called used to check if a tile has been included in the current permutation. If so, it's skipped in further permutations unless it's a unique arrangement. The results are collected into a set to ensure every sequence is unique.
Time Complexity: O(n * n!) where n is the number of tiles, considering permutations with duplicates.
Space Complexity: O(n * n!) for storing the permutations in the set.
Approach 2: DFS with Frequency Map
This approach utilizes Depth-First Search (DFS) with a frequency map to track the count of each character used, allowing us to construct sequences by branching through available letters. It eliminates duplicate permutations by managing the count of each character carefully.
def numTilePossibilities(tiles):
from collections import Counter
def dfs(counter):
count = 0
for char in counter:
if counter[char] > 0:
counter[char] -= 1
count += 1 + dfs(counter)
counter[char] += 1
return count
tile_count = Counter(tiles)
return dfs(tile_count)import java.util.HashMap;
import java.util.Map;
public class TilePossibilities {
public int numTilePossibilities(String tiles) {
Map<Character, Integer> counter = new HashMap<>();
for (char tile : tiles.toCharArray()) {
counter.put(tile, counter.getOrDefault(tile, 0) + 1);
}
return dfs(counter);
}
private int dfs(Map<Character, Integer> counter) {
int sum = 0;
for (char c : counter.keySet()) {
if (counter.get(c) > 0) {
counter.put(c, counter.get(c) - 1);
sum += 1 + dfs(counter);
counter.put(c, counter.get(c) + 1);
}
}
return sum;
}
}#include <iostream>
#include <unordered_map>
#include <algorithm>
using namespace std;
int dfs(unordered_map<char, int>& counter) {
int sum = 0;
for (auto& [key, value] : counter) {
if (value > 0) {
counter[key]--;
sum += 1 + dfs(counter);
counter[key]++;
}
}
return sum;
}
int numTilePossibilities(string tiles) {
unordered_map<char, int> counter;
for (char tile : tiles) {
counter[tile]++;
}
return dfs(counter);
}This solution builds all unique sequences using a frequency map (Counter) and explores different possibilities using a depth-first search mechanism. It examines each possible character by decreasing its availability in the counter, counting each new sequence formed uniquely as characters deplete.
Time Complexity: O(k^n), where k is the number of unique tiles and n is the total number of tiles.
Space Complexity: O(k), primarily due to the stored frequency map.
Approach 3: Default Approach
function numTilePossibilities(tiles: string): number {
const cnt: number[] = new Array(26).fill(0);
for (const c of tiles) {
++cnt[c.charCodeAt(0) - 'A'.charCodeAt(0)];
}
const dfs = (cnt: number[]): number => {
let res = 0;
for (let i = 0; i < 26; ++i) {
if (cnt[i] > 0) {
++res;
--cnt[i];
res += dfs(cnt);
++cnt[i];
}
}
return res;
};
return dfs(cnt);
}func numTilePossibilities(tiles string) int {
cnt := [26]int{}
for _, c := range tiles {
cnt[c-'A']++
}
var dfs func(cnt [26]int) int
dfs = func(cnt [26]int) (res int) {
for i, x := range cnt {
if x > 0 {
res++
cnt[i]--
res += dfs(cnt)
cnt[i]++
}
}
return
}
return dfs(cnt)
}Complexity comparison
| Approach | Complexity |
|---|---|
| Backtracking with Set | Time Complexity: O(n * n!) where n is the number of tiles, considering permutations with duplicates. |
| DFS with Frequency Map | Time Complexity: O(k^n), where k is the number of unique tiles and n is the total number of tiles. |
| Default Approach | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Backtracking with Set | O(n! * n) | O(n! * n) | Good for understanding permutation generation and handling duplicates with a set |
| DFS with Frequency Map | O(n! * n) | O(n) | Preferred approach when tiles contain duplicates and you want to avoid storing all sequences |
Frequently asked questions
Is Letter Tile Possibilities easy or hard?
Letter Tile Possibilities is considered a Medium difficulty problem. The recursion itself is straightforward, but handling duplicate characters efficiently and reasoning about permutation counts requires solid understanding of backtracking.
How to solve Letter Tile Possibilities in O(n)?
A true O(n) solution is not possible because the number of possible sequences grows factorially with the number of tiles. The optimal practical solution uses DFS with a frequency map to prune duplicates while exploring permutations, resulting in O(n! * n) complexity.
Letter Tile Possibilities Python or Java solution?
Both Python and Java implementations typically use recursive DFS with a frequency map. The algorithm decrements the character count when choosing a tile, explores deeper sequences, and restores the count during backtracking.
What is the best approach for Letter Tile Possibilities?
The most efficient approach uses DFS with a frequency map. Instead of generating all permutations and removing duplicates, the algorithm tracks how many times each character appears and only explores valid choices. This avoids duplicate work and counts sequences directly during recursion.
What data structure is used in Letter Tile Possibilities?
The optimal solution uses a hash table (frequency map) to store the count of each character and recursion to explore possible sequences. Backtracking manages tile usage, while the frequency structure prevents duplicate permutations.
What is the time complexity of Letter Tile Possibilities?
The worst‑case time complexity is O(n! * n) because the algorithm explores permutations of the tiles and builds sequences of length up to n. The frequency‑map DFS approach still has factorial growth but avoids generating duplicate permutations, making it faster in practice.
Is Letter Tile Possibilities asked at Google, Amazon, or Meta?
Permutation and backtracking problems similar to Letter Tile Possibilities appear in interviews at companies like Google, Amazon, and Meta. The problem tests recursion, counting techniques, and handling duplicates efficiently using frequency maps.
