Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

967. Numbers With Same Consecutive Differences - Leetcode Solution

Problem Description

The "Numbers With Same Consecutive Differences" problem asks you to find all positive integers of length n such that the absolute difference between every two consecutive digits is exactly k.

  • You are given two integers: n (the length of the number) and k (the required absolute difference between every pair of consecutive digits).
  • Each number must not have leading zeros (i.e., the first digit cannot be 0).
  • Return all valid numbers in any order as a list.

For example, if n = 3 and k = 7, valid numbers include 181 and 292 (since |1-8|=7, |8-1|=7).

Thought Process

To solve this problem, let's break down what is required:

  • We need to generate all numbers of length n where the difference between every two consecutive digits is exactly k.
  • We must avoid numbers with leading zeros.
  • Simply generating all n-digit numbers and filtering them would be too slow, especially for large n.

The brute-force approach would be to check all numbers from 10^{n-1} to 10^n - 1, but this is not efficient for large n. Instead, we can build the numbers digit by digit, making sure that each new digit maintains the required consecutive difference.

This leads us to a recursive or breadth-first search (BFS) approach: for each possible starting digit (1-9), we add valid next digits (previous digit + k and previous digit - k, if they are between 0 and 9), and continue until we reach n digits.

Solution Approach

We can use either depth-first search (DFS) or BFS to build valid numbers:

  1. Initialization:
    • Start with all digits from 1 to 9 (since numbers cannot have leading zeros).
  2. Recursive/BFS Construction:
    • For each number built so far, get its last digit.
    • Compute possible next digits: last digit + k and last digit - k.
    • If the next digit is between 0 and 9, append it to the current number and continue.
    • Repeat until the number has n digits.
  3. Edge Case:
    • When k = 0, avoid adding the same digit twice.
  4. Result:
    • Collect all numbers of length n built in this way.

This approach is efficient because it only explores valid combinations, avoiding unnecessary computation.

Example Walkthrough

Let's walk through an example with n = 3 and k = 7:

  • Start with digits 1 to 9.
  • For digit 1:
    • Next digit can be 1 + 7 = 8 (since 8 is valid, 1 - 7 = -6 is not valid).
    • Now we have 18.
    • For 18, last digit is 8:
      • 8 + 7 = 15 (invalid), 8 - 7 = 1 (valid), so 181 is a valid number.
  • For digit 2:
    • 2 + 7 = 9 (valid), so 29.
    • For 29, last digit is 9:
      • 9 + 7 = 16 (invalid), 9 - 7 = 2 (valid), so 292 is valid.
  • Repeat for all starting digits. The valid numbers are [181, 292, 707, 818, 929].

Time and Space Complexity

  • Brute-force approach:
    • There are 9 * 10^{n-1} numbers to check, and each check takes O(n) time, so total time is O(n * 10^n).
    • Space is O(1) for checking, O(output) for storing results.
  • Optimized (DFS/BFS) approach:
    • At each of the n-1 steps, each number can branch to at most 2 new numbers (depending on k).
    • So, total number of generated numbers is O(2^n), but in practice much less due to digit constraints.
    • Time: O(2^n) in the worst case, but usually far fewer.
    • Space: O(2^n) for recursion and result storage.

Summary

The "Numbers With Same Consecutive Differences" problem is elegantly solved by building numbers digit by digit, always maintaining the required consecutive difference. By using DFS or BFS, we avoid generating invalid numbers and greatly reduce computation compared to brute-force checking. The solution is efficient, leverages recursion or iterative construction, and highlights the power of combinatorial generation with constraints.

Code Implementation

class Solution:
    def numsSameConsecDiff(self, n: int, k: int) -> List[int]:
        if n == 1:
            return [i for i in range(10)]
        res = []
        def dfs(num, length):
            if length == n:
                res.append(num)
                return
            last_digit = num % 10
            next_digits = set()
            next_digits.add(last_digit + k)
            next_digits.add(last_digit - k)
            for next_digit in next_digits:
                if 0 <= next_digit <= 9:
                    dfs(num * 10 + next_digit, length + 1)
        for i in range(1, 10):
            dfs(i, 1)
        return res
      
class Solution {
public:
    vector<int> numsSameConsecDiff(int n, int k) {
        vector<int> res;
        if (n == 1) {
            for (int i = 0; i < 10; ++i) res.push_back(i);
            return res;
        }
        function<void(int, int)> dfs = [&](int num, int length) {
            if (length == n) {
                res.push_back(num);
                return;
            }
            int last_digit = num % 10;
            set<int> next_digits = {last_digit + k, last_digit - k};
            for (int next_digit : next_digits) {
                if (0 <= next_digit && next_digit <= 9) {
                    dfs(num * 10 + next_digit, length + 1);
                }
            }
        };
        for (int i = 1; i < 10; ++i) {
            dfs(i, 1);
        }
        return res;
    }
};
      
class Solution {
    public int[] numsSameConsecDiff(int n, int k) {
        List<Integer> res = new ArrayList<>();
        if (n == 1) {
            for (int i = 0; i < 10; i++) res.add(i);
            return res.stream().mapToInt(j -> j).toArray();
        }
        dfs(n, k, 0, 0, res);
        int[] ans = new int[res.size()];
        for (int i = 0; i < res.size(); i++) ans[i] = res.get(i);
        return ans;
    }
    private void dfs(int n, int k, int num, int length, List<Integer> res) {
        if (length == n) {
            res.add(num);
            return;
        }
        if (length == 0) {
            for (int i = 1; i < 10; i++) {
                dfs(n, k, i, 1, res);
            }
        } else {
            int lastDigit = num % 10;
            Set<Integer> nextDigits = new HashSet<>();
            nextDigits.add(lastDigit + k);
            nextDigits.add(lastDigit - k);
            for (int next : nextDigits) {
                if (next >= 0 && next <= 9) {
                    dfs(n, k, num * 10 + next, length + 1, res);
                }
            }
        }
    }
}
      
var numsSameConsecDiff = function(n, k) {
    if (n === 1) return Array.from({length: 10}, (_, i) => i);
    let res = [];
    function dfs(num, length) {
        if (length === n) {
            res.push(num);
            return;
        }
        let lastDigit = num % 10;
        let nextDigits = new Set([lastDigit + k, lastDigit - k]);
        for (let next of nextDigits) {
            if (next >= 0 && next <= 9) {
                dfs(num * 10 + next, length + 1);
            }
        }
    }
    for (let i = 1; i < 10; i++) {
        dfs(i, 1);
    }
    return res;
};