1、leetcode 力扣 365 水壶问题 题解 算法题题目:水壶问题有两个容量分别为x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好z升 的水?如果可以,最后请用以上水壶中的一或两个来盛放取得的z升水。你允许:装满任意一个水壶清空任意一个水壶从一个水壶向另外一个水壶倒水,直到装满或者倒空示例 1: (From the famous Die Hard example)输入: x = 3, y = 5, z = 4输出: True示例 2:输入: x = 2, y = 6, z = 5输出: False语言:Pythonclass Solution: def c
2、anMeasureWater(self, x: int, y: int, z: int) - bool: stack = (0, 0) self.seen = set() while stack: remain_x, remain_y = stack.pop() if remain_x = z or remain_y = z or remain_x + remain_y = z: return True if (remain_x, remain_y) in self.seen: continue self.seen.add(remain_x, remain_y) # 把 X 壶灌满。 stac
3、k.append(x, remain_y) # 把 Y 壶灌满。 stack.append(remain_x, y) # 把 X 壶倒空。 stack.append(0, remain_y) # 把 Y 壶倒空。 stack.append(remain_x, 0) # 把 X 壶的水灌进 Y 壶,直至灌满或倒空。 stack.append(remain_x - min(remain_x, y - remain_y), remain_y + min(remain_x, y - remain_y) # 把 Y 壶的水灌进 X 壶,直至灌满或倒空。 stack.append(remain_x + m
4、in(remain_y, x - remain_x), remain_y - min(remain_y, x - remain_x) return False语言:Pythonclass Solution: def canMeasureWater(self, x: int, y: int, z: int) - bool: if x + y z: return False if x = 0 or y = 0: return z = 0 or x + y = z return z % math.gcd(x, y) = 0语言:C+using PII = pair;class Solution pu
5、blic: bool canMeasureWater(int x, int y, int z) stack stk; stk.emplace(0, 0); auto hash_function = (const PII& o) return hash()(o.first) hash()(o.second); unordered_set seen(0, hash_function); while (!stk.empty() if (seen.count(stk.top() stk.pop(); continue; seen.emplace(stk.top(); auto remain_x, re
6、main_y = stk.top(); stk.pop(); if (remain_x = z | remain_y = z | remain_x + remain_y = z) return true; / 把 X 壶灌满。 stk.emplace(x, remain_y); / 把 Y 壶灌满。 stk.emplace(remain_x, y); / 把 X 壶倒空。 stk.emplace(0, remain_y); / 把 Y 壶倒空。 stk.emplace(remain_x, 0); / 把 X 壶的水灌进 Y 壶,直至灌满或倒空。 stk.emplace(remain_x - m
7、in(remain_x, y - remain_y), remain_y + min(remain_x, y - remain_y); / 把 Y 壶的水灌进 X 壶,直至灌满或倒空。 stk.emplace(remain_x + min(remain_y, x - remain_x), remain_y - min(remain_y, x - remain_x); return false; ;语言:C+class Solution public: bool canMeasureWater(int x, int y, int z) if (x + y z) return false; if
8、(x = 0 | y = 0) return z = 0 | x + y = z; return z % gcd(x, y) = 0; ;语言:C+class Solution inline pair op(int type, const pair &state, int x, int y) switch(type) case 0 : return make_pair(x, state.second); case 1 : return make_pair(state.first, y); case 2 : return make_pair(0, state.second); case 3 :
9、return make_pair(state.first, 0); case 4 : int move = min(state.first, y-state.second); return make_pair(state.first - move, state.second + move); case 5 : int move = min(x-state.first, state.second); return make_pair(state.first + move, state.second - move); return make_pair(0,0); struct HashPair s
10、ize_t operator()(const pair &key) const noexcept return (size_t(key.first)31) | size_t(key.second); ; inline int64_t Hash(int x, int y) return int64_t(x) 32 | y; public: bool canMeasureWater(int x, int y, int z) if(x + y z) /加了一个很蠢的剪枝,作用比较大。 return false; unordered_set mark; /pair 换成int64_t, 但是意义不大。
11、 queuepair q; q.push(make_pair(0,0); while(q.empty() = false) auto f = q.front(); q.pop(); if(f.first + f.second = z) return true; for(int i = 0; i 6; i+) auto next = op(i, f, x, y); int64_t h = Hash(next.first, next.second); if(mark.find(h) != mark.end() continue; mark.insert(h); q.push(next); retu
12、rn false; ;语言:Javaclass Solution public boolean canMeasureWater(int x, int y, int z) Deque stack = new LinkedList(); stack.push(new int0, 0); Set seen = new HashSet(); while (!stack.isEmpty() if (seen.contains(hash(stack.peek() stack.pop(); continue; seen.add(hash(stack.peek(); int state = stack.pop
13、(); int remain_x = state0, remain_y = state1; if (remain_x = z | remain_y = z | remain_x + remain_y = z) return true; / 把 X 壶灌满。 stack.push(new intx, remain_y); / 把 Y 壶灌满。 stack.push(new intremain_x, y); / 把 X 壶倒空。 stack.push(new int0, remain_y); / 把 Y 壶倒空。 stack.push(new intremain_x, 0); / 把 X 壶的水灌
14、进 Y 壶,直至灌满或倒空。 stack.push(new intremain_x - Math.min(remain_x, y - remain_y), remain_y + Math.min(remain_x, y - remain_y); / 把 Y 壶的水灌进 X 壶,直至灌满或倒空。 stack.push(new intremain_x + Math.min(remain_y, x - remain_x), remain_y - Math.min(remain_y, x - remain_x); return false; public long hash(int state) re
15、turn (long) state0 * 1000001 + state1; 语言:Javaclass Solution public boolean canMeasureWater(int x, int y, int z) if (x + y z) return false; if (x = 0 | y = 0) return z = 0 | x + y = z; return z % gcd(x, y) = 0; public int gcd(int x, int y) int remainder = x % y; while (remainder != 0) x = y; y = rem
16、ainder; remainder = x % y; return y; 语言:Javaimport java.util.ArrayList;import java.util.HashSet;import java.util.LinkedList;import java.util.List;import java.util.Objects;import java.util.Queue;import java.util.Set;public class Solution public boolean canMeasureWater(int x, int y, int z) / 特判 if (z
17、= 0) return true; if (x + y z) return false; State initState = new State(0, 0); / 广度优先遍历使用队列 Queue queue = new LinkedList(); Set visited = new HashSet(); queue.offer(initState); visited.add(initState); while (!queue.isEmpty() State head = queue.poll(); int curX = head.getX(); int curY = head.getY();
18、 / curX + curY = z 比较容易忽略 if (curX = z | curY = z | curX + curY = z) return true; / 从当前状态获得所有可能的下一步的状态 List nextStates = getNextStates(curX, curY, x, y); / 打开以便于观察,调试代码 / System.out.println(head + = + nextStates); for (State nextState : nextStates) if (!visited.contains(nextState) queue.offer(nextSt
19、ate); / 添加到队列以后,必须马上设置为已经访问,否则会出现死循环 visited.add(nextState); return false; private List getNextStates(int curX, int curY, int x, int y) / 最多 8 个对象,防止动态数组扩容,不过 Java 默认的初始化容量肯定大于 8 个 List nextStates = new ArrayList(8); / 按理说应该先判断状态是否存在,再生成状态对象,这里为了阅读方便,一次生成 8 个对象 / 以下两个状态,对应操作 1 / 外部加水,使得 A 满 State ne
20、xtState1 = new State(x, curY); / 外部加水,使得 B 满 State nextState2 = new State(curX, y); / 以下两个状态,对应操作 2 / 把 A 清空 State nextState3 = new State(0, curY); / 把 B 清空 State nextState4 = new State(curX, 0); / 以下四个状态,对应操作 3 / 从 A 到 B,使得 B 满,A 还有剩 State nextState5 = new State(curX - (y - curY), y); / 从 A 到 B,此时
21、A 的水太少,A 倒尽,B 没有满 State nextState6 = new State(0, curX + curY); / 从 B 到 A,使得 A 满,B 还有剩余 State nextState7 = new State(x, curY - (x - curX); / 从 B 到 A,此时 B 的水太少,B 倒尽,A 没有满 State nextState8 = new State(curX + curY, 0); / 没有满的时候,才需要加水 if (curX x) nextStates.add(nextState1); if (curY 0) nextStates.add(ne
22、xtState3); if (curY 0) nextStates.add(nextState4); / 有剩余才倒 if (curX - (y - curY) 0) nextStates.add(nextState5); if (curY - (x - curX) 0) nextStates.add(nextState7); / 倒过去倒不满才倒 if (curX + curY y) nextStates.add(nextState6); if (curX + curY x) nextStates.add(nextState8); return nextStates; private cla
23、ss State private int x; private int y; public State(int x, int y) this.x = x; this.y = y; public int getX() return x; public int getY() return y; Override public String toString() return State + x= + x + , y= + y + ; Override public boolean equals(Object o) if (this = o) return true; if (o = null |
24、getClass() != o.getClass() return false; State state = (State) o; return x = state.x & y = state.y; Override public int hashCode() return Objects.hash(x, y); public static void main(String args) Solution solution = new Solution(); int x = 3; int y = 5; int z = 4;/ int x = 2;/ int y = 6;/ int z = 5;/
25、 int x = 1;/ int y = 2;/ int z = 3; boolean res = solution.canMeasureWater(x, y, z); System.out.println(res); 语言:phpclass Solution /* * param Integer $x * param Integer $y * param Integer $z * return Boolean */贝祖定理 function canMeasureWater($x, $y, $z) if($x+$ygcd($x,$y); return ($z % $gcd )=0 ? true
26、 : false;/比fmod快 /欧几里得算法 function gcd($n,$m) if(!$m) return $n; return $this-gcd($m,($n % $m ); 语言:gofunc canMeasureWater(x int, y int, z int) bool if z = 0 | z = x+y / 条件 1 return true else if z x+y | y = 0 / 条件 2 和 3 return false / 迭代公式 2、 4、 6 return canMeasureWater(y, x%y, z%y)语言:gofunc canMeasu
27、reWater(x int, y int, z int) bool for ; z != 0 & y != 0 & z x+y; x, y, z = y, x%y, z%y return z = 0 | z = x + y语言:js/* * param number x * param number y * param number z * return boolean */var canMeasureWater = function(x, y, z) if (x + y z) return false; if (z = 0) return true; if (x = 0) return y = z; if (y = 0) return x = z; function GCD(a, b) let min = Math.min(a, b); while (min) if (a % min = 0 & b % min = 0) return min; min-;
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1