Facebook Pixel

3718. Smallest Missing Multiple of K

EasyArrayHash Table
LeetCode ↗

Problem Description

You are given an integer array nums and an integer k. Your task is to find the smallest positive multiple of k that does not appear in nums.

A multiple of k is any positive integer that is divisible by k. In other words, the multiples of k are k * 1, k * 2, k * 3, and so on.

For example, if nums = [2, 4, 8] and k = 2:

  • The multiples of 2 in order are: 2, 4, 6, 8, ...
  • 2 is in the array, 4 is in the array, but 6 is not.
  • Therefore, the answer is 6.

The goal is to check the multiples of k one by one, starting from the smallest (k * 1), and return the first one that is missing from the array.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Hash Table / Counting?

This problem maps to Hash Table / Counting through a short path in the full flowchart.

Tree orgraph?noFastlookup orcounting?yesHash Table /Counting

Building a hash set for O(1) membership queries lets us check each multiple of k sequentially until finding a missing one.

Open in Flowchart

Intuition

The problem asks for the smallest missing positive multiple of k, which naturally suggests a simple strategy: check the multiples of k one by one in increasing order — k * 1, k * 2, k * 3, ... — and stop as soon as we find one that is not in nums. Since we check them from smallest to largest, the first missing one we encounter is guaranteed to be the answer.

The only remaining concern is efficiency. For each multiple, we need to ask: "does this value exist in nums?" If we scan the entire array every time, each check costs O(n). Instead, we can put all elements of nums into a hash set first. A hash set answers membership queries in O(1) on average, so every check becomes instant.

We also know this process must terminate quickly. The array has only n elements, so it can contain at most n distinct multiples of k. That means by the time we reach the multiple k * (n + 1), at least one of the first n + 1 multiples must be missing. Therefore, the enumeration runs at most n + 1 rounds, giving an overall linear-time solution.

Solution Approach

We use a hash table (set) combined with enumeration, following these steps:

Step 1: Build a hash set from the array

We first store all the numbers from nums into a set s:

s = set(nums)

This is the key data structure choice. Converting the array into a set takes O(n) time once, and afterwards each membership check x in s runs in O(1) on average — far better than scanning the array repeatedly.

Step 2: Enumerate multiples of k in increasing order

Starting from i = 1, we generate each positive multiple x = k * i in sequence:

for i in count(1):
    x = k * i

Here count(1) from the itertools module produces the infinite sequence 1, 2, 3, ..., so x takes the values k, 2k, 3k, ... in order.

Step 3: Return the first missing multiple

For each multiple x, we check whether it exists in the set. The moment we find one that is absent, we return it immediately:

if x not in s:
    return x

Because we enumerate multiples from smallest to largest, the first absent multiple is guaranteed to be the smallest missing one — exactly what the problem asks for.

Complete Code

class Solution:
    def missingMultiple(self, nums: List[int], k: int) -> int:
        s = set(nums)
        for i in count(1):
            x = k * i
            if x not in s:
                return x

Complexity Analysis

  • Time Complexity: O(n), where n is the length of nums. Building the set costs O(n). Since nums contains at most n distinct multiples of k, the loop runs at most n + 1 iterations, each with an O(1) set lookup.
  • Space Complexity: O(n), used by the hash set storing the elements of nums.

Example Walkthrough

Let's trace through the solution with nums = [3, 9, 6, 10] and k = 3.

Step 1: Build the hash set

Convert the array into a set for fast lookups:

s = {3, 9, 6, 10}

This one-time O(n) step lets every subsequent membership check run in O(1).

Step 2 & 3: Enumerate multiples of k and check each one

We generate multiples of 3 in increasing order and test each against the set:

ix = k * iIs x in s?Action
13Yes (3 ∈ s)Continue
26Yes (6 ∈ s)Continue
39Yes (9 ∈ s)Continue
412NoReturn 12

The multiples 3, 6, and 9 all appear in the array, so the loop keeps going. When we reach 12, the set lookup fails — this is the first multiple of 3 missing from nums.

Result: 12

Notice two key properties confirmed by this trace:

  1. Correctness — since multiples are checked from smallest to largest, the first absent one (12) is guaranteed to be the smallest missing multiple. Note that 10 being in the array is irrelevant; it isn't a multiple of 3, so it never affects the enumeration.
  2. Bounded iterations — the array has n = 4 elements, so at most 4 distinct multiples of 3 can appear in it. The loop is therefore guaranteed to terminate within n + 1 = 5 iterations; here it stopped at the 4th.

Solution Implementation

1from typing import List
2from itertools import count
3
4
5class Solution:
6    def missingMultiple(self, nums: List[int], k: int) -> int:
7        # Store all numbers in a hash set for O(1) membership checks
8        num_set = set(nums)
9
10        # Enumerate positive multiples of k: k * 1, k * 2, k * 3, ...
11        for multiplier in count(1):
12            multiple = k * multiplier
13            # The first multiple of k not present in the set is the answer
14            if multiple not in num_set:
15                return multiple
16
1class Solution {
2    public int missingMultiple(int[] nums, int k) {
3        // Use a boolean array as a presence set for values in nums.
4        // Values are assumed to be in the range [0, 100].
5        boolean[] present = new boolean[101];
6
7        // Mark each number in nums as present.
8        for (int num : nums) {
9            present[num] = true;
10        }
11
12        // Check multiples of k in increasing order: k, 2k, 3k, ...
13        for (int i = 1;; ++i) {
14            int multiple = k * i;
15
16            // Return the first multiple that is either out of the array's
17            // range (and therefore cannot appear in nums) or not present.
18            if (multiple >= present.length || !present[multiple]) {
19                return multiple;
20            }
21        }
22    }
23}
24```
25
26**Explanation of the approach:**
27
281. **Presence tracking:** A `boolean` array `present` of size 101 acts as a lightweight hash set, marking which values from `nums` exist. This works because the values are bounded by 100.
29
302. **Iterating multiples:** Starting from `i = 1`, each multiple `k * i` is computed in ascending order, guaranteeing the *smallest* missing multiple is found first.
31
323. **Termination condition:** The loop returns when a multiple either exceeds the array bounds (meaning it can't possibly be in `nums`) or is simply absent from the set. This ensures the loop always terminates.
33
34**Alternative perspective:** A `HashSet<Integer>` could replace the boolean array if the value range were unbounded, trading constant-factor speed for flexibility:
35
36```java
37Set<Integer> seen = new HashSet<>();
38for (int num : nums) seen.add(num);
39for (int i = 1;; ++i) {
40    if (!seen.contains(k * i)) return k * i;
41}
42
1class Solution {
2public:
3    int missingMultiple(vector<int>& nums, int k) {
4        // Store all elements of nums in a hash set for O(1) lookups
5        unordered_set<int> numSet(nums.begin(), nums.end());
6
7        // Check multiples of k in increasing order: k, 2k, 3k, ...
8        for (int i = 1;; ++i) {
9            int multiple = k * i;
10            // The first multiple of k not present in the set is the answer
11            if (!numSet.contains(multiple)) {
12                return multiple;
13            }
14        }
15    }
16};
17
1/**
2 * Finds the smallest positive multiple of k that is missing from the given array.
3 *
4 * @param nums - The array of numbers to search within.
5 * @param k - The base number whose multiples are checked.
6 * @returns The smallest positive multiple of k not present in nums.
7 */
8function missingMultiple(nums: number[], k: number): number {
9    // Store all elements of nums in a Set for O(1) lookups
10    const numSet = new Set<number>(nums);
11
12    // Iterate over positive integers, checking each multiple of k
13    for (let i = 1; ; ++i) {
14        // Compute the i-th multiple of k
15        const multiple = k * i;
16
17        // If this multiple is not in the set, it is the smallest missing one
18        if (!numSet.has(multiple)) {
19            return multiple;
20        }
21    }
22}
23

Time and Space Complexity

  • Time complexity: O(n), where n is the length of the array nums.

    • Building the set s = set(nums) takes O(n) time.
    • The loop iterates over multiples of k (i.e., k * 1, k * 2, ...). Since the set s contains at most n elements, among the first n + 1 multiples of k, at least one must be missing from s. Therefore, the loop runs at most n + 1 times, and each membership check x not in s takes O(1) on average.
    • Overall: O(n) + O(n) = O(n).
  • Space complexity: O(n), where n is the length of the array nums.

    • The set s stores up to n elements from nums, requiring O(n) extra space.
    • All other variables (i, x) use only O(1) space.

Pattern Learn more about how to find time and space complexity quickly.

Common Pitfalls

Pitfall 1: Checking membership against the list instead of a set

A very common mistake is to skip the set conversion and write the check directly on the array:

class Solution:
    def missingMultiple(self, nums: List[int], k: int) -> int:
        for i in count(1):
            x = k * i
            if x not in nums:   # ❌ O(n) lookup on a list!
                return x

Why it's wrong (or at least bad): The result is still correct, but x not in nums performs a linear scan of the list every iteration. Since the loop can run up to n + 1 times, the overall time complexity degrades from O(n) to O(n²), which can time out on large inputs.

Solution: Always convert nums to a set first (s = set(nums)) so each membership test is O(1) on average.


Pitfall 2: Starting the enumeration from 0 instead of 1

for i in count(0):      # ❌ starts at i = 0
    x = k * i           # first candidate is 0
    if x not in s:
        return x

Why it's wrong: k * 0 = 0 is not a positive multiple of k. If 0 happens to be absent from nums (which is typical), this code immediately returns 0, which is invalid. The problem explicitly defines multiples as starting from k * 1.

Solution: Begin the counter at 1count(1) or while True with i = 1 — so the first candidate is k itself.


Pitfall 3: Inverting the logic — scanning nums for multiples instead of enumerating multiples

Some attempts iterate over the array, collect multiples of k, and then try to "find the gap" by sorting:

multiples = sorted(x for x in nums if x % k == 0)
expected = k
for m in multiples:
    if m == expected:
        expected += k
return expected         # ❌ breaks when nums contains duplicates

Why it's wrong: Duplicates derail the matching. For nums = [2, 2, 4] and k = 2, the sorted multiples are [2, 2, 4]; the second 2 fails to match expected = 4, the pointer never advances past it correctly unless extra duplicate handling is added, and the code may return a wrong answer. It also adds an unnecessary O(n log n) sort.

Solution: Deduplicate via a set and enumerate candidates k, 2k, 3k, ... directly, as in the reference solution. This sidesteps duplicates and sorting entirely.


Pitfall 4: Worrying about (or causing) an unbounded loop

At first glance, for i in count(1) looks like it could run forever, and some defensive rewrites cap it incorrectly:

for i in range(1, len(nums)):   # ❌ off-by-one: loop bound is too small
    ...

Why it's wrong: The array contains at most n distinct multiples of k, so by the pigeonhole principle the answer is found within the first n + 1 multiples — the infinite iterator is guaranteed to terminate. But if you replace it with a bounded loop, the bound must cover n + 1 candidates. range(1, len(nums)) only checks n - 1 multiples and can fall off the end without returning (e.g., nums = [2, 4], k = 2 → never tests 6).

Solution: Either trust count(1) (termination is provable), or use range(1, len(nums) + 2) so all n + 1 necessary candidates are covered.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Consider the classic dynamic programming of fibonacci numbers, what is the recurrence relation?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More