|
51 | 51 |
|
52 | 52 | ## 解法
|
53 | 53 |
|
54 |
| -### 方法一 |
| 54 | +### 方法一:DFS |
| 55 | + |
| 56 | +我们不妨记 $jug1Capacity$ 为 $x$, $jug2Capacity$ 为 $y$, $targetCapacity$ 为 $z$。 |
| 57 | + |
| 58 | +接下来,我们设计一个函数 $dfs(i, j)$,表示当前 $jug1$ 中有 $i$ 升水,$jug2$ 中有 $j$ 升水,是否可以得到 $z$ 升水。 |
| 59 | + |
| 60 | +函数 $dfs(i, j)$ 的执行过程如下: |
| 61 | + |
| 62 | +- 如果 $(i, j)$ 已经被访问过,返回 $false$。 |
| 63 | +- 如果 $i = z$ 或者 $j = z$ 或者 $i + j = z$,返回 $true$。 |
| 64 | +- 如果我们给 $jug1$ 倒满水,或者给 $jug2$ 倒满水,或者将 $jug1$ 清空,或者将 $jug2$ 清空,可以得到 $z$ 升水,返回 $true$。 |
| 65 | +- 如果我们将 $jug1$ 中的水倒入 $jug2$,或者将 $jug2$ 中的水倒入 $jug1$,可以得到 $z$ 升水,返回 $true$。 |
| 66 | + |
| 67 | +答案即为 $dfs(0, 0)$。 |
| 68 | + |
| 69 | +时间复杂度 $O(x + y)$,空间复杂度 $O(x + y)$。其中 $x$ 和 $y$ 分别为 $jug1Capacity$ 和 $jug2Capacity$ 的大小。 |
55 | 70 |
|
56 | 71 | <!-- tabs:start -->
|
57 | 72 |
|
58 | 73 | ```python
|
59 | 74 | class Solution:
|
60 |
| - def canMeasureWater( |
61 |
| - self, jug1Capacity: int, jug2Capacity: int, targetCapacity: int |
62 |
| - ) -> bool: |
63 |
| - stk, seen = [], set() |
64 |
| - stk.append([0, 0]) |
65 |
| - |
66 |
| - def get_hash(nums): |
67 |
| - return nums[0] * 10000006 + nums[1] |
68 |
| - |
69 |
| - while stk: |
70 |
| - if get_hash(stk[-1]) in seen: |
71 |
| - stk.pop() |
72 |
| - continue |
73 |
| - seen.add(get_hash(stk[-1])) |
74 |
| - cur = stk.pop() |
75 |
| - cur1, cur2 = cur[0], cur[1] |
76 |
| - if ( |
77 |
| - cur1 == targetCapacity |
78 |
| - or cur2 == targetCapacity |
79 |
| - or cur1 + cur2 == targetCapacity |
80 |
| - ): |
| 75 | + def canMeasureWater(self, x: int, y: int, z: int) -> bool: |
| 76 | + def dfs(i: int, j: int) -> bool: |
| 77 | + if (i, j) in vis: |
| 78 | + return False |
| 79 | + vis.add((i, j)) |
| 80 | + if i == z or j == z or i + j == z: |
81 | 81 | return True
|
82 |
| - stk.append([jug1Capacity, cur2]) |
83 |
| - stk.append([0, cur2]) |
84 |
| - stk.append([cur1, jug2Capacity]) |
85 |
| - stk.append([cur1, 0]) |
86 |
| - if cur1 + cur2 > jug1Capacity: |
87 |
| - stk.append([jug1Capacity, cur2 - jug1Capacity + cur1]) |
88 |
| - else: |
89 |
| - stk.append([cur1 + cur2, 0]) |
90 |
| - if cur1 + cur2 > jug2Capacity: |
91 |
| - stk.append([cur1 - jug2Capacity + cur2, jug2Capacity]) |
92 |
| - else: |
93 |
| - stk.append([0, cur1 + cur2]) |
94 |
| - return False |
| 82 | + if dfs(x, j) or dfs(i, y) or dfs(0, j) or dfs(i, 0): |
| 83 | + return True |
| 84 | + a = min(i, y - j) |
| 85 | + b = min(j, x - i) |
| 86 | + return dfs(i - a, j + a) or dfs(i + b, j - b) |
| 87 | + |
| 88 | + vis = set() |
| 89 | + return dfs(0, 0) |
95 | 90 | ```
|
96 | 91 |
|
97 | 92 | ```java
|
98 | 93 | class Solution {
|
| 94 | + private Set<Long> vis = new HashSet<>(); |
| 95 | + private int x, y, z; |
| 96 | + |
99 | 97 | public boolean canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) {
|
100 |
| - Deque<int[]> stk = new ArrayDeque<>(); |
101 |
| - stk.add(new int[] {0, 0}); |
102 |
| - Set<Long> seen = new HashSet<>(); |
103 |
| - while (!stk.isEmpty()) { |
104 |
| - if (seen.contains(hash(stk.peek()))) { |
105 |
| - stk.pop(); |
106 |
| - continue; |
107 |
| - } |
108 |
| - int[] cur = stk.pop(); |
109 |
| - seen.add(hash(cur)); |
110 |
| - int cur1 = cur[0], cur2 = cur[1]; |
111 |
| - if (cur1 == targetCapacity || cur2 == targetCapacity || cur1 + cur2 == targetCapacity) { |
112 |
| - return true; |
113 |
| - } |
114 |
| - stk.offer(new int[] {jug1Capacity, cur2}); |
115 |
| - stk.offer(new int[] {0, cur2}); |
116 |
| - stk.offer(new int[] {cur1, jug1Capacity}); |
117 |
| - stk.offer(new int[] {cur2, 0}); |
118 |
| - if (cur1 + cur2 > jug1Capacity) { |
119 |
| - stk.offer(new int[] {jug1Capacity, cur2 - jug1Capacity + cur1}); |
120 |
| - } else { |
121 |
| - stk.offer(new int[] {cur1 + cur2, 0}); |
122 |
| - } |
123 |
| - if (cur1 + cur2 > jug2Capacity) { |
124 |
| - stk.offer(new int[] {cur1 - jug2Capacity + cur2, jug2Capacity}); |
125 |
| - } else { |
126 |
| - stk.offer(new int[] {0, cur1 + cur2}); |
127 |
| - } |
| 98 | + x = jug1Capacity; |
| 99 | + y = jug2Capacity; |
| 100 | + z = targetCapacity; |
| 101 | + return dfs(0, 0); |
| 102 | + } |
| 103 | + |
| 104 | + private boolean dfs(int i, int j) { |
| 105 | + long st = f(i, j); |
| 106 | + if (!vis.add(st)) { |
| 107 | + return false; |
128 | 108 | }
|
129 |
| - return false; |
| 109 | + if (i == z || j == z || i + j == z) { |
| 110 | + return true; |
| 111 | + } |
| 112 | + if (dfs(x, j) || dfs(i, y) || dfs(0, j) || dfs(i, 0)) { |
| 113 | + return true; |
| 114 | + } |
| 115 | + int a = Math.min(i, y - j); |
| 116 | + int b = Math.min(j, x - i); |
| 117 | + return dfs(i - a, j + a) || dfs(i + b, j - b); |
130 | 118 | }
|
131 | 119 |
|
132 |
| - public long hash(int[] nums) { |
133 |
| - return nums[0] * 10000006L + nums[1]; |
| 120 | + private long f(int i, int j) { |
| 121 | + return i * 1000000L + j; |
134 | 122 | }
|
135 | 123 | }
|
136 | 124 | ```
|
137 | 125 |
|
138 | 126 | ```cpp
|
139 | 127 | class Solution {
|
140 | 128 | public:
|
141 |
| - bool canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) { |
142 |
| - if (jug1Capacity + jug2Capacity < targetCapacity) return false; |
143 |
| - if (jug1Capacity == 0 || jug2Capacity == 0) |
144 |
| - return targetCapacity == 0 || jug1Capacity + jug2Capacity == targetCapacity; |
145 |
| - return targetCapacity % gcd(jug1Capacity, jug2Capacity) == 0; |
146 |
| - } |
147 |
| - |
148 |
| - int gcd(int a, int b) { |
149 |
| - return b == 0 ? a : gcd(b, a % b); |
| 129 | + bool canMeasureWater(int x, int y, int z) { |
| 130 | + using pii = pair<int, int>; |
| 131 | + stack<pii> stk; |
| 132 | + stk.emplace(0, 0); |
| 133 | + auto hash_function = [](const pii& o) { return hash<int>()(o.first) ^ hash<int>()(o.second); }; |
| 134 | + unordered_set<pii, decltype(hash_function)> vis(0, hash_function); |
| 135 | + while (stk.size()) { |
| 136 | + auto st = stk.top(); |
| 137 | + stk.pop(); |
| 138 | + if (vis.count(st)) { |
| 139 | + continue; |
| 140 | + } |
| 141 | + vis.emplace(st); |
| 142 | + auto [i, j] = st; |
| 143 | + if (i == z || j == z || i + j == z) { |
| 144 | + return true; |
| 145 | + } |
| 146 | + stk.emplace(x, j); |
| 147 | + stk.emplace(i, y); |
| 148 | + stk.emplace(0, j); |
| 149 | + stk.emplace(i, 0); |
| 150 | + int a = min(i, y - j); |
| 151 | + int b = min(j, x - i); |
| 152 | + stk.emplace(i - a, j + a); |
| 153 | + stk.emplace(i + b, j - b); |
| 154 | + } |
| 155 | + return false; |
150 | 156 | }
|
151 | 157 | };
|
152 | 158 | ```
|
153 | 159 |
|
154 | 160 | ```go
|
155 |
| -func canMeasureWater(jug1Capacity int, jug2Capacity int, targetCapacity int) bool { |
156 |
| - if jug1Capacity+jug2Capacity < targetCapacity { |
157 |
| - return false |
158 |
| - } |
159 |
| - if jug1Capacity == 0 || jug2Capacity == 0 { |
160 |
| - return targetCapacity == 0 || jug1Capacity+jug2Capacity == targetCapacity |
161 |
| - } |
162 |
| - |
163 |
| - var gcd func(a, b int) int |
164 |
| - gcd = func(a, b int) int { |
165 |
| - if b == 0 { |
166 |
| - return a |
| 161 | +func canMeasureWater(x int, y int, z int) bool { |
| 162 | + type pair struct{ x, y int } |
| 163 | + vis := map[pair]bool{} |
| 164 | + var dfs func(int, int) bool |
| 165 | + dfs = func(i, j int) bool { |
| 166 | + st := pair{i, j} |
| 167 | + if vis[st] { |
| 168 | + return false |
167 | 169 | }
|
168 |
| - return gcd(b, a%b) |
| 170 | + vis[st] = true |
| 171 | + if i == z || j == z || i+j == z { |
| 172 | + return true |
| 173 | + } |
| 174 | + if dfs(x, j) || dfs(i, y) || dfs(0, j) || dfs(i, 0) { |
| 175 | + return true |
| 176 | + } |
| 177 | + a := min(i, y-j) |
| 178 | + b := min(j, x-i) |
| 179 | + return dfs(i-a, j+a) || dfs(i+b, j-b) |
169 | 180 | }
|
170 |
| - return targetCapacity%gcd(jug1Capacity, jug2Capacity) == 0 |
171 |
| -} |
172 |
| -``` |
173 |
| - |
174 |
| -```cs |
175 |
| -using System; |
176 |
| - |
177 |
| -public class Solution { |
178 |
| - public bool CanMeasureWater(int x, int y, int z) { |
179 |
| - if (x == 0 || y == 0) return z == x || z == y; |
180 |
| - var gcd = GetGcd(x, y); |
181 |
| - return z >= 0 && z <= x + y && z % gcd == 0; |
182 |
| - } |
183 |
| - |
184 |
| - private int GetGcd(int x, int y) |
185 |
| - { |
186 |
| - while (x > 0) |
187 |
| - { |
188 |
| - var quotient = x / y; |
189 |
| - var reminder = x % y; |
190 |
| - if (reminder == 0) |
191 |
| - { |
192 |
| - return y; |
193 |
| - } |
194 |
| - x = y; |
195 |
| - y = reminder; |
196 |
| - } |
197 |
| - throw new Exception("Invalid x or y"); |
198 |
| - } |
199 |
| -} |
200 |
| -``` |
201 |
| - |
202 |
| -<!-- tabs:end --> |
203 |
| - |
204 |
| -### 方法二 |
205 |
| - |
206 |
| -<!-- tabs:start --> |
207 |
| - |
208 |
| -```python |
209 |
| -class Solution: |
210 |
| - def canMeasureWater( |
211 |
| - self, jug1Capacity: int, jug2Capacity: int, targetCapacity: int |
212 |
| - ) -> bool: |
213 |
| - if jug1Capacity + jug2Capacity < targetCapacity: |
214 |
| - return False |
215 |
| - if jug1Capacity == 0 or jug2Capacity == 0: |
216 |
| - return targetCapacity == 0 or jug1Capacity + jug2Capacity == targetCapacity |
217 |
| - return targetCapacity % gcd(jug1Capacity, jug2Capacity) == 0 |
218 |
| -``` |
219 |
| - |
220 |
| -```java |
221 |
| -class Solution { |
222 |
| - public boolean canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) { |
223 |
| - if (jug1Capacity + jug2Capacity < targetCapacity) { |
224 |
| - return false; |
225 |
| - } |
226 |
| - if (jug1Capacity == 0 || jug2Capacity == 0) { |
227 |
| - return targetCapacity == 0 || jug1Capacity + jug2Capacity == targetCapacity; |
228 |
| - } |
229 |
| - return targetCapacity % gcd(jug1Capacity, jug2Capacity) == 0; |
230 |
| - } |
231 |
| - |
232 |
| - private int gcd(int a, int b) { |
233 |
| - return b == 0 ? a : gcd(b, a % b); |
234 |
| - } |
| 181 | + return dfs(0, 0) |
235 | 182 | }
|
236 | 183 | ```
|
237 | 184 |
|
|
0 commit comments