← Home

967. Numbers With Same Consecutive Differences

LeetCode article · C++ solution
Website made by wuisabel-gif · Original C++ code by keineahnung2345
backtrackingC++Markdown
967

This problem looks busy at first, but the accepted solution is built around one steady invariant. For 967. Numbers With Same Consecutive Differences, the solution in this repository is mainly a backtracking solution.

Guide

What?

We want to turn the problem statement into a smaller set of decisions the computer can repeat safely. Instead of trying to be clever immediately, read the code as a sequence of questions:

  • What state are we keeping?
  • How do we move from one state to the next?
  • When do we know the answer is already determined?

For this file, the main tools are: backtracking.

The notes already sitting in the source point us in the right direction:

  • Backtrack

Guide

When?

This pattern shows up when the brute force version has too many repeated checks, too many possible branches, or too much bookkeeping to do by hand. The accepted code reduces that pressure by storing exactly the information that remains useful later.

The important function names to track are backtrack, numsSameConsecDiff, dfs.

Guide

Why?

The win comes from making each line carry responsibility: store the useful state, discard the rest, keep moving.

  • The queue gives the solution a level-by-level or frontier-style traversal.
  • The final return is not magic; it is the invariant after the loops or recursion have finished doing their accounting.

Guide

How?

Walk through the solution in this order:

  1. Start from the smallest reliable state.
  2. Expand one legal move at a time.
  3. Cache, count, or merge information as soon as it becomes settled.
  4. Let the final stored value answer the original question.

The most important competitive-programming habit here is to trust the invariant. Once the invariant is right, the loops become much less scary.

Guide

Complexity

  • Time: O(N*2^N), we have 9*(2^(N-1)) potention combinations, and to generate each combination, we need O(N) for recursion
  • Space: O(2^N), recursion space: O(N), answer space: O(9*(2^(N-1))) = O(2^N)

Guide

C++ Solution

Your submission

The accepted solution

solution.cpp
01//Backtrack
02//Runtime: 4 ms, faster than 77.11% of C++ online submissions for Numbers With Same Consecutive Differences.
03//Memory Usage: 8.4 MB, less than 24.87% of C++ online submissions for Numbers With Same Consecutive Differences.
04class Solution {
05public:
06    int N, K;
07    vector<int> ans;
08    
09    void backtrack(int cur){
10        int digit = (cur == 0) ? 1 : log10(cur)+1;
11        // cout << "cur: " << cur << ", " << digit << endl;
12        if(digit == N){
13            ans.push_back(cur);
14        }else{
15            int last = cur%10;
16            
17            if(last-K >= ((cur == 0) ? 1 : 0)) backtrack(cur*10 + last-K);
18            //K!=0: to avoid duplicate
19            if(K != 0 && last+K <= 9) backtrack(cur*10 + last+K);
20        }
21    }
22    
23    vector<int> numsSameConsecDiff(int N, int K) {
24        this->N = N;
25        this->K = K;
26        
27        if(N == 1) ans.push_back(0);
28        
29        /*
30        here we skip 0,
31        because it may generate duplicate number
32        
33        For example, N=3 and K=7:
34        cur: 0->7->70->707
35        and 
36        cur: 7->70->707
37        */
38        for(int i = 1; i <= 9; ++i){
39            backtrack(i);
40        }
41        
42        return ans;
43    }
44};
45
46//Approach 1: DFS (Depth-First Search)
47//Runtime: 0 ms, faster than 100.00% of C++ online submissions for Numbers With Same Consecutive Differences.
48//Memory Usage: 8 MB, less than 46.79% of C++ online submissions for Numbers With Same Consecutive Differences.
49//time: O(N*2^N), we have 9*(2^(N-1)) potention combinations, and to generate each combination, we need O(N) for recursion
50//space: O(2^N), recursion space: O(N), answer space: O(9*(2^(N-1))) = O(2^N)
51class Solution {
52public:
53    int K;
54    vector<int> ans;
55    
56    void dfs(int N, int num){
57        if(N == 0){
58            ans.push_back(num);
59        }else{
60            int d = num%10;
61            
62            if(d-K >= 0){
63                dfs(N-1, num*10 + (d-K));
64            }
65            
66            if(K != 0 && d+K <= 9){
67                dfs(N-1, num*10 + (d+K));
68            }
69        }
70    }
71    
72    vector<int> numsSameConsecDiff(int N, int K) {
73        this->K = K;
74        
75        if(N == 1) ans.push_back(0);
76        
77        for(int num = 1; num <= 9; ++num){
78            dfs(N-1, num);
79        }
80        
81        return ans;
82    }
83};
84
85//Approach 2: BFS (Breadth-First Search)
86//Runtime: 0 ms, faster than 100.00% of C++ online submissions for Numbers With Same Consecutive Differences.
87//Memory Usage: 7.1 MB, less than 96.29% of C++ online submissions for Numbers With Same Consecutive Differences.
88//time: O(N*2^N), we have 9*(2^(N-1)) potention combinations, and to generate each combination, we need O(N)
89//space: O(2^N), in the queue, we could have at most two level of elements, for first level, it takes O(9*2^(N-1)), for 2nd level, it takes O(9*2^(N-1-1))
90class Solution {
91public:
92    vector<int> numsSameConsecDiff(int N, int K) {
93        if(N == 1){
94            return {0,1,2,3,4,5,6,7,8,9};
95        }
96        
97        queue<int> q;
98        
99        for(int i = 1; i <= 9; ++i){
100            q.push(i);
101        }
102        
103        int level = 1;
104        vector<int> ans;
105        
106        while(level <= N){
107            int level_size = q.size();
108            
109            while(level_size-- > 0){
110                int cur = q.front(); q.pop();
111                
112                if(level == N){
113                    ans.push_back(cur);
114                }else{
115                    int d = cur%10;
116            
117                    if(d-K >= 0){
118                        q.push(cur*10 + (d-K));
119                    }
120
121                    if(K != 0 && d+K <= 9){
122                        q.push(cur*10 + (d+K));
123                    }
124                }
125            }
126            
127            ++level;
128        }
129        
130        return ans;
131    }
132};

Cost

Complexity

Time
O(N*2^N), we have 9*(2^(N-1)) potention combinations, and to generate each combination, we need O(N) for recursion
Dominated by the main traversal, recursion, or data-structure operations in the code.
Space
O(2^N), recursion space: O(N), answer space: O(9*(2^(N-1))) = O(2^N)
Auxiliary state plus the answer structure where the problem requires one.