← Home

935. Knight Dialer

LeetCode article · C++ solution
Website made by wuisabel-gif · Original C++ code by keineahnung2345
DFS + memoizationC++Markdown
935

The trick here is to name the state correctly, then let the implementation follow. For 935. Knight Dialer, the solution in this repository is mainly a DFS + memoization 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: DFS + memoization, dynamic programming.

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

  • recursion + memorization

Guide

When?

This is the kind of solution you want when the problem has structure hiding inside a messy-looking input. The accepted code reduces that pressure by storing exactly the information that remains useful later.

The important function names to track are dfs, knightDialer.

Guide

Why?

The solution works because it narrows the problem until every update has a clear reason to exist.

  • The two-dimensional vector is the memory of the solution: grid state, DP state, or adjacency shape.
  • 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. Read the setup variables first.
  2. Follow the main loop or recursive helper next.
  3. Watch where invalid states get skipped.
  4. Check which value survives to the return statement.

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) to O(n log n), depending on the dominant loop or data structure operation
  • Space: O(n) in the usual case for auxiliary containers or recursion

Guide

C++ Solution

Your submission

The accepted solution

solution.cpp
01//recursion + memorization
02//Runtime: 328 ms, faster than 27.43% of C++ online submissions for Knight Dialer.
03//Memory Usage: 23.2 MB, less than 57.37% of C++ online submissions for Knight Dialer.
04class Solution {
05public:
06    int MOD = 1e9+7;
07    vector<vector<int>> edges;
08    vector<vector<int>> memo;
09    
10    int dfs(int cur, int N){
11        if(N == 0) return 1;
12        if(N == 1) return edges[cur].size();
13        if(memo[cur][N] != -1) return memo[cur][N];
14        
15        memo[cur][N] = 0;
16
17        for(int nei : edges[cur]){
18            memo[cur][N] = (memo[cur][N] + dfs(nei, N-1)) % MOD;
19        }
20        return memo[cur][N];
21    }
22    
23    int knightDialer(int N) {
24        int ans = 0;
25        edges = vector<vector<int>>(10);
26
27        edges[0] = {4,6};
28        edges[1] = {6,8};
29        edges[2] = {7,9};
30        edges[3] = {4,8};
31        edges[4] = {3,9,0};
32        edges[5] = {};
33        edges[6] = {1,7,0};
34        edges[7] = {2,6};
35        edges[8] = {1,3};
36        edges[9] = {2,4};
37        
38        memo = vector<vector<int>>(10, vector<int>(N, -1));
39        
40        for(int i = 0; i <= 9; i++){
41            ans = (ans + dfs(i, N-1)) % MOD;
42        }
43        
44        return ans;
45    }
46};
47
48//bottom-up DP
49//Runtime: 344 ms, faster than 26.23% of C++ online submissions for Knight Dialer.
50//Memory Usage: 21.7 MB, less than 58.60% of C++ online submissions for Knight Dialer.
51class Solution {
52public:
53    int MOD = 1e9+7;
54    vector<vector<int>> edges;
55    vector<vector<int>> memo;
56    
57    int knightDialer(int N) {
58        int ans = 0;
59        edges = vector<vector<int>>(10);
60
61        edges[0] = {4,6};
62        edges[1] = {6,8};
63        edges[2] = {7,9};
64        edges[3] = {4,8};
65        edges[4] = {3,9,0};
66        edges[5] = {};
67        edges[6] = {1,7,0};
68        edges[7] = {2,6};
69        edges[8] = {1,3};
70        edges[9] = {2,4};
71        
72        vector<vector<int>> dp(10, vector<int>(N, 0));
73        
74        for(int n = 0; n < N; n++){
75            for(int cur = 0; cur <= 9; cur++){
76                if(n == 0){
77                    dp[cur][n] = 1;
78                }else if(n == 1){
79                    dp[cur][n] = edges[cur].size();
80                }else{
81                    for(int nei : edges[cur]){
82                        dp[cur][n] = (dp[cur][n] + dp[nei][n-1]) % MOD;
83                    }
84                }
85                // cout << "(" << cur << ", " << n << "): " << dp[cur][n] << endl;
86            }
87        }
88        
89        for(int cur = 0; cur <= 9; cur++){
90            ans = (ans + dp[cur][N-1]) % MOD;
91        }
92        
93        return ans;
94    }
95};
96
97//DP, space optimized
98//Runtime: 184 ms, faster than 55.96% of C++ online submissions for Knight Dialer.
99//Memory Usage: 6.1 MB, less than 88.12% of C++ online submissions for Knight Dialer.
100class Solution {
101public:
102    int MOD = 1e9+7;
103    vector<vector<int>> edges;
104    vector<vector<int>> memo;
105    
106    int knightDialer(int N) {
107        int ans = 0;
108        edges = vector<vector<int>>(10);
109
110        edges[0] = {4,6};
111        edges[1] = {6,8};
112        edges[2] = {7,9};
113        edges[3] = {4,8};
114        edges[4] = {3,9,0};
115        edges[5] = {};
116        edges[6] = {1,7,0};
117        edges[7] = {2,6};
118        edges[8] = {1,3};
119        edges[9] = {2,4};
120        
121        vector<vector<int>> dp(2, vector<int>(10, 0));
122        
123        for(int n = 0; n < N; n++){
124            for(int cur = 0; cur <= 9; cur++){
125                if(n == 0){
126                    dp[n%2][cur] = 1;
127                }else if(n == 1){
128                    dp[n%2][cur] = edges[cur].size();
129                }else{
130                    dp[n%2][cur] = 0;
131                    for(int nei : edges[cur]){
132                        dp[n%2][cur] = (dp[n%2][cur] + dp[(n-1)%2][nei]) % MOD;
133                    }
134                }
135            }
136        }
137        
138        for(int cur = 0; cur <= 9; cur++){
139            ans = (ans + dp[(N-1)%2][cur]) % MOD;
140        }
141        
142        return ans;
143    }
144};

Cost

Complexity

Time
O(n) to O(n log n), depending on the dominant loop or data structure operation
Dominated by the main traversal, recursion, or data-structure operations in the code.
Space
O(n) in the usual case for auxiliary containers or recursion
Auxiliary state plus the answer structure where the problem requires one.