Talentd
FleetCode
Make and follow sheets.Sign in

Number of Ways to Wear Different Hats to Each Other solution and explanation

HardArrayBit ManipulationBitmaskDynamic Programming7 min read47.0% acceptanceUpdated 9 Apr 2026
Number of Ways to Wear Different Hats to Each Other: 1434Tony Teaches · 18:59 · 2K viewsWatch on YouTube
5 more videos on this problem
  1. Number of Ways to Wear Different Hats to Each Other: 1434Tony Teaches · 18:59 · 2K views
  2. LeetCode 1434. Number of Ways to Wear Different Hats to Each OtherHappy Coding · 42:49 · 1K views
  3. 1434. Number of Ways to Wear Different Hats to Each Other (Leetcode Hard)Programming Live with Larry · 16:51 · 1K views
  4. 1434. Number of Ways to Wear Different Hats to Each Other | LeetCode | DP with BitmaskingCoding Gist · 16:33 · 916 views
  5. 【每日一题】1434. Number of Ways to Wear Different Hats to Each Other, 5/4/2020Huifeng Guan · 28:15 · 640 views
  6. Leetcode 1434. Number of Ways to Wear Different Hats to Each OtherFearless Learner · 10:25 · 94 views

The problem

There are n people and 40 types of hats labeled from 1 to 40.

Given a 2D integer array hats, where hats[i] is a list of all hats preferred by the ith person.

Return the number of ways that the n people wear different hats to each other.

Since the answer may be too large, return it modulo 109 + 7.

Example 1:

Input: hats = [[3,4],[4,5],[5]]
Output: 1
Explanation: There is only one way to choose hats given the conditions. 
First person choose hat 3, Second person choose hat 4 and last one hat 5.

Example 2:

Input: hats = [[3,5,1],[3,5]]
Output: 4
Explanation: There are 4 ways to choose hats:
(3,5), (5,3), (1,3) and (1,5)

Example 3:

Input: hats = [[1,2,3,4],[1,2,3,4],[1,2,3,4],[1,2,3,4]]
Output: 24
Explanation: Each person can choose hats labeled from 1 to 4.
Number of Permutations of (1,2,3,4) = 24.

Constraints:

  • n == hats.length
  • 1 <= n <= 10
  • 1 <= hats[i].length <= 40
  • 1 <= hats[i][j] <= 40
  • hats[i] contains a list of unique integers.

Approach overview

Problem Overview: Each person has a list of hats they are willing to wear. Every person must wear exactly one hat and no two people can wear the same hat. The task is to count how many valid assignments exist. The constraints are small for people (≤10) but large for hat IDs (≤40), which pushes you toward bitmask-based state compression.

Approach 1: Backtracking with Memoization (O(40 * 2^n) time, O(2^n) space)

Backtracking tries every valid assignment of hats to people. Instead of iterating people first, iterate hats from 1..40 and decide whether to assign the current hat to any eligible person who is still unassigned. Track assigned people using a bitmask where bit i indicates whether person i already has a hat. The recursion state becomes (hatIndex, mask). Memoization avoids recomputing the same state when the same combination of processed hats and assigned people appears again. This drastically reduces the search space because there are at most 40 * 2^n states.

The key insight is flipping the mapping: build a list of people for each hat rather than hats for each person. That lets you process hats sequentially and maintain the assignment mask efficiently using bitmask operations.

Approach 2: Dynamic Programming with Bitmasking (O(40 * 2^n) time, O(2^n) space)

The optimal solution models the problem as DP over subsets. Define dp[mask] as the number of ways to assign hats such that the set of people represented by mask already have hats. Iterate hats from 1..40, and for each hat update states where that hat is given to a compatible person. If person p likes the current hat and the bit for p is not set in mask, transition to mask | (1 << p). This builds assignments incrementally while guaranteeing that each hat is used at most once.

This works because the number of people is small. A mask of size n ≤ 10 produces at most 2^10 states, making the DP manageable. Each hat only transitions from existing masks, producing a total complexity of roughly 40 * 2^n. This technique is a classic combination of dynamic programming and bitmask state compression.

Recommended for interviews: The dynamic programming with bitmasking approach is the expected solution. Interviewers want to see that you recognize the small number of people and encode assignment states using a bitmask. Implementing the recursive backtracking version with memoization still demonstrates the same insight and is often easier to reason about during discussion. Showing both approaches signals strong understanding of subset DP and state compression techniques commonly used in array and combinatorial problems.

Approach 1: Backtracking with Memoization

This approach involves using backtracking to try all possible assignments of hats by recursively assigning hats to people.

We use memoization to store already computed results to avoid redundant calculations, improving efficiency.

MOD = 10**9 + 7

def number_ways(hats):
    n = len(hats)
    all_mask = (1 << n) - 1
    dp = {}
    hat_to_people = [[] for _ in range(41)]
    for person, hat_list in enumerate(hats):
        for hat in hat_list:
            hat_to_people[hat].append(person)
    
    def ways(hat, mask):
        if mask == all_mask:
            return 1
        if hat > 40:
            return 0
        if (hat, mask) in dp:
            return dp[(hat, mask)]
        ans = ways(hat + 1, mask)
        for person in hat_to_people[hat]:
            if mask & (1 << person) == 0:
                ans += ways(hat + 1, mask | (1 << person))
                ans %= MOD
        dp[(hat, mask)] = ans
        return ans
    
    return ways(1,0)
const MOD = 10**9 + 7;

function numberOfWays(hats) {
    const n = hats.length;
    const allMask = (1 << n) - 1;
    const dp = new Map();
    const hatToPeople = Array.from({ length: 41 }, () => []);

    hats.forEach((hatList, person) => {
        hatList.forEach(hat => {
            hatToPeople[hat].push(person);
        });
    });

    function ways(hat, mask) {
        if (mask === allMask) return 1;
        if (hat > 40) return 0;
        const key = `${hat},${mask}`;
        if (dp.has(key)) return dp.get(key);
        let ans = ways(hat + 1, mask);
        hatToPeople[hat].forEach(person => {
            if ((mask & (1 << person)) === 0) {
                ans += ways(hat + 1, mask | (1 << person));
                ans %= MOD;
            }
        });
        dp.set(key, ans);
        return ans;
    }

    return ways(1, 0);
}

We implemented a `ways` function that checks each hat number iteratively and recursively assigns it to available people.

Using a bit mask helps track which people have already been assigned hats.

Memoization is employed to cache results of previously computed states.

Complexity

Time Complexity: O(2^n * 40) where `n` is the number of people.

Space Complexity: O(2^n * 40) due to memoization storage.

Try this approach in the editor

Approach 2: Dynamic Programming with Bitmasking

We use dynamic programming and bitmasking to efficiently calculate the number of distinct hat placements.

Each state is represented by a bitmask indicating which people have been assigned hats.

Transition between states occurs by considering each hat for each person who prefers it.

import java.util.*;

class Solution {
    private static final int MOD = 1000000007;
    
    public int numberOfWays(List<List<Integer>> hats) {
        int n = hats.size();
        List<Integer>[] peopleWithHat = new ArrayList[41];
        for (int i = 0; i <= 40; i++) {
            peopleWithHat[i] = new ArrayList<>();
        }
        for (int i = 0; i < n; i++) {
            for (int hat : hats.get(i)) {
                peopleWithHat[hat].add(i);
            }
        }
        Map<Integer, Integer> dp = new HashMap<>();
        return dfs(0, 0, peopleWithHat, dp, n);
    }
    
    private int dfs(int hat, int mask, List<Integer>[] peopleWithHat, Map<Integer, Integer> dp, int n) {
        if (mask == (1 << n) - 1) return 1;
        if (hat > 40) return 0;
        int key = (hat << 10) | mask;
        if (dp.containsKey(key)) return dp.get(key);
        int ans = dfs(hat + 1, mask, peopleWithHat, dp, n);
        for (int person : peopleWithHat[hat]) {
            if ((mask & (1 << person)) == 0) {
                ans = (ans + dfs(hat + 1, mask | (1 << person), peopleWithHat, dp, n)) % MOD;
            }
        }
        dp.put(key, ans);
        return ans;
    }
}
#include <vector>
#include <unordered_map>

using namespace std;
#define MOD 1000000007

int numberOfWays(vector<vector<int>>& hats) {
    int n = hats.size();
    vector<vector<int>> people_with_hat(41);
    for (int i = 0; i < n; ++i) {
        for (int hat : hats[i]) {
            people_with_hat[hat].push_back(i);
        }
    }
    unordered_map<int, int> dp;
    return dfs(0, 0, people_with_hat, dp, n);
}

int dfs(int hat, int mask, vector<vector<int>>& people_with_hat, unordered_map<int, int>& dp, int n) {
    if (mask == (1 << n) - 1) return 1;
    if (hat > 40) return 0;
    if (dp.count((hat << 10) | mask)) return dp[(hat << 10) | mask];
    int ans = dfs(hat + 1, mask, people_with_hat, dp, n);
    for (int person : people_with_hat[hat]) {
        if (!(mask & (1 << person))) {
            ans = (ans + dfs(hat + 1, mask | (1 << person), people_with_hat, dp, n)) % MOD;
        }
    }
    dp[(hat << 10) | mask] = ans;
    return ans;
}

This Java solution uses bitmasking and memoization, implementing a depth-first search while protecting against over-counting by storing results in a map.

Complexity

Time Complexity: O(2^n * 40)

Space Complexity: O(2^n * 40)

Try this approach in the editor

Approach 3: Dynamic Programming

We notice that n is not greater than 10, so we consider using DP with state compression to solve this problem.

We define f[i][j] as the number of ways to assign the first i hats to the people whose state is j. Here j is a binary number, which represents a set of people. We have f[0][0]=1 at the beginning, and the answer is f[m][2^n - 1], where m is the maximum number of hats and n is the number of people.

Consider f[i][j]. If we don't assign the i-th hat to anyone, then f[i][j]=f[i-1][j]; if we assign the i-th hat to the person k who likes it, then f[i][j]=f[i-1][j \oplus 2^k]. Here \oplus denotes the XOR operation. Therefore, we can get the state transition equation:

$ f[i][j]=f[i-1][j]+ sum_{k \in like[i]} f[i-1][j \oplus 2^k]

where like[i] denotes the set of people who like the i-th hat.

The final answer is f[m][2^n - 1], and the answer may be very large, so we need to take it modulo 10^9 + 7.

Time complexity O(m times 2^n times n), space complexity O(m times 2^n). Here m is the maximum number of hats, which is no more than 40 in this problem; and n is the number of people, which is no more than 10$ in this problem.

function numberWays(hats: number[][]): number {
    const n = hats.length;
    const m = Math.max(...hats.flat());
    const g: number[][] = Array.from({ length: m + 1 }, () => []);
    for (let i = 0; i < n; ++i) {
        for (const v of hats[i]) {
            g[v].push(i);
        }
    }
    const f: number[][] = Array.from({ length: m + 1 }, () =>
        Array.from({ length: 1 << n }, () => 0),
    );
    f[0][0] = 1;
    const mod = 1e9 + 7;
    for (let i = 1; i <= m; ++i) {
        for (let j = 0; j < 1 << n; ++j) {
            f[i][j] = f[i - 1][j];
            for (const k of g[i]) {
                if (((j >> k) & 1) === 1) {
                    f[i][j] = (f[i][j] + f[i - 1][j ^ (1 << k)]) % mod;
                }
            }
        }
    }
    return f[m][(1 << n) - 1];
}
func numberWays(hats [][]int) int {
	n := len(hats)
	m := 0
	for _, h := range hats {
		m = max(m, slices.Max(h))
	}
	g := make([][]int, m+1)
	for i, h := range hats {
		for _, v := range h {
			g[v] = append(g[v], i)
		}
	}
	const mod = 1e9 + 7
	f := make([][]int, m+1)
	for i := range f {
		f[i] = make([]int, 1<<n)
	}
	f[0][0] = 1
	for i := 1; i <= m; i++ {
		for j := 0; j < 1<<n; j++ {
			f[i][j] = f[i-1][j]
			for _, k := range g[i] {
				if j>>k&1 == 1 {
					f[i][j] = (f[i][j] + f[i-1][j^(1<<k)]) % mod
				}
			}
		}
	}
	return f[m][(1<<n)-1]
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Backtracking with Memoization

Time Complexity: O(2^n * 40) where `n` is the number of people.

Space Complexity: O(2^n * 40) due to memoization storage.

Dynamic Programming with Bitmasking

Time Complexity: O(2^n * 40)

Space Complexity: O(2^n * 40)

Dynamic Programming–

Complexity analysis

ApproachTimeSpaceWhen to Use
Backtracking with MemoizationO(40 * 2^n)O(2^n)Good for understanding the assignment search space and building intuition for subset states
Dynamic Programming with BitmaskingO(40 * 2^n)O(2^n)Best approach when the number of people is small and each state can be represented using a bitmask

Frequently asked questions

Is Number of Ways to Wear Different Hats to Each Other easy or hard?

The problem is classified as Hard on LeetCode. The difficulty comes from recognizing the need for subset DP and using bitmask state compression to represent assignments efficiently.

Number of Ways to Wear Different Hats to Each Other Python/Java solution

Python solutions commonly implement recursion with memoization using a bitmask to track assigned people. Java and C++ solutions often use iterative DP arrays indexed by mask. Both implementations rely on the same O(40 * 2^n) state transitions.

How to solve Number of Ways to Wear Different Hats to Each Other in O(n)?

An O(n) solution is not possible because the problem requires exploring combinations of assignments. The best known approach runs in O(40 * 2^n) using bitmask dynamic programming. Since the number of people is at most 10, the subset space (2^n) remains small enough to compute efficiently.

What is the best approach for Number of Ways to Wear Different Hats to Each Other?

Dynamic programming with bitmasking is the most efficient approach. Represent the set of people who already received hats using a bitmask and iterate through hats from 1 to 40. For each hat, update DP states by assigning it to compatible people. This yields O(40 * 2^n) time and O(2^n) space, which works because n ≤ 10.

Is Number of Ways to Wear Different Hats to Each Other asked at Google/Amazon/Meta?

Subset dynamic programming and bitmask assignment problems frequently appear in interviews at companies like Google, Amazon, and Meta. While this exact question may vary, the underlying technique—DP over subsets with bitmasks—is a common interview pattern.

What data structure is used in Number of Ways to Wear Different Hats to Each Other?

The main data structure is a bitmask representing which people already have hats. Along with the bitmask, a dynamic programming array or memoization map stores the number of valid assignments for each state. A reversed mapping from hat to people who like it is also used for efficient iteration.

What is the time complexity of Number of Ways to Wear Different Hats to Each Other?

The optimal complexity is O(40 * 2^n), where n is the number of people. There are at most 40 hats and 2^n possible assignment states represented by a bitmask. Each hat processes transitions across these states, keeping the runtime manageable.

Comments

Now write it yourselfClose this page and solve Number of Ways to Wear Different Hats to Each Other in the editor, without looking.
Practise Number of Ways to Wear Different Hats to Each Other