-
Notifications
You must be signed in to change notification settings - Fork 106
/
minimum-knight-moves.cpp
92 lines (86 loc) · 3.15 KB
/
minimum-knight-moves.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Time: O(1)
// Space: O(1)
class Solution {
private:
template <typename T>
struct PairHash {
size_t operator()(const pair<T, T>& p) const {
size_t seed = 0;
seed ^= std::hash<T>{}(p.first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
seed ^= std::hash<T>{}(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2);
return seed;
}
};
public:
int minKnightMoves(int x, int y) {
// we can observe from:
// [0]
// [3, 2]
// [2,(1),4]
// [3, 2, 3, 2]
// [2, 3,(2) 3, 4]
// [3, 4, 3, 4, 3, 4]
// [4, 3, 4,(3),4, 5, 4]
// [5, 4, 5, 4, 5, 4, 5, 6]
// [4, 5, 4, 5,(4),5, 6, 5, 6]
// [5, 6, 5, 6, 5, 6, 5, 6, 7, 6]
// [6, 5, 6, 5, 6,(5),6, 7, 6, 7, 8]
// [7, 6, 7, 6, 7, 6, 7, 6, 7, 8, 7, 8]
// [6, 7, 6, 7, 6, 7,(6),7, 8, 7, 8, 9, 8]
// [7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 9, 8, 9, 10]
// [8, 7, 8, 7, 8, 7, 8,(7),8, 9, 8, 9, 10, 9, 10]
// [9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 10, 9, 10, 11, 10]
x = abs(x), y = abs(y);
if (x < y) {
swap(x, y);
}
static const unordered_map<pair<int, int>, int, PairHash<int>> lookup =
{{{0, 0}, 0}, {{1, 0}, 3}, {{2, 2}, 4}}; // special cases
if (lookup.count({x, y})) {
return lookup.at({x, y});
}
const auto& k = x - y;
if (y > k) {
// if 2y > x, every period 3 of y (or k) with fixed another is increased by 2 (or 1)
// and start from (2k, k) with (k) when y = k (diagonal line)
// ex. (0, 0) ~ (12, 12) ~ ... : 0 => 2,4(special case),2 => 4,4,4 => 6,6,6 => 8,8,8 => ...
// ex. (2, 1) ~ (14, 13) ~ ... : 1 => 3,3,3 => 5,5,5 => 7,7,7 => 9,9,9 => ...
return k + 2 * ((y - k - 1) / 3 + 1);
}
// if 2y <= x, every period 4 of k (or y) with fixed another is increased by 2
// and start from (2k, k) with (k) when y = k (vertical line)
// ex. (0, 0) ~ (11, 0) ~ ... : 0,3(special case),2,3 => 2,3,4,5 => 4,5,6,7 => ...
// ex. (2, 1) ~ (13, 1) ~ ... : 1,2,3,4 => 3,4,5,6 => 5,6,7,8 => ...
return k - 2 * ((k - y) / 4);
}
};
// Time: O(n^2)
// Space: O(n^2)
class Solution2 {
public:
int minKnightMoves(int x, int y) {
return dp(x, y);
}
private:
template <typename T>
struct PairHash {
size_t operator()(const pair<T, T>& p) const {
size_t seed = 0;
seed ^= std::hash<T>{}(p.first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
seed ^= std::hash<T>{}(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2);
return seed;
}
};
int dp(int x, int y) {
static unordered_map<pair<int, int>, int, PairHash<int>> lookup =
{{{0, 0}, 0}, {{1, 1}, 2}, {{1, 0}, 3}}; // special cases
x = abs(x), y = abs(y);
if (x < y) {
swap(x, y);
}
if (!lookup.count({x, y})) { // greedy, smaller x, y is always better if not special cases
lookup[{x, y}] = min(dp(x - 1, y - 2), dp(x - 2, y - 1)) + 1;
}
return lookup[{x, y}];
}
};