LeetCode 365:水壶问题
有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?比如3升和 5升水壶,可以倒出 4 升水。
数学表达:mx + ny = z,求整数解
数学思路:根据贝祖公式,设c为x和y的最大公约数,则一定存在等式c = mx+ny,m和n为整数,并且mn < 0
因此,z只要是最大公约数的倍数即可。
最大公约数的求法
- 辗转相除法:大数a/小数b,求余数temp,若temp=0,则b为最大公约数,否则,令a=b, b=temp;
- 更相减损法:a > b,它们的最大公约数等于a-b的差值c和较小数b的最大公约数。依次递归下去,直到两个数相等。这相等两个数的值就是所求最大公约数。
// 辗转相除法
int gcd(int a, int b){
int temp = a % b;
while(temp!=0){
a = b;
b = temp;
temp = a%b;
}
return b; }
题解:
bool canMeasureWater(int x, int y, int z) {
if(x+y<z) return false;
if(x==0||y==0) return z==0|| x+y==z;
int temp = x % y;
while(temp!=0){
x = y;
y = temp;
temp = x % y;
}
return z%y==0?true:false;
}
自己的思路(Fail)
bool canMeasureWater(int x, int y, int z) {
// 假设桶id 0,1,分别对应大小x,y
vector<int> bucket; bucket.push_back(x); bucket.push_back(y);
// 假设飘动水量属性water[余量,桶id],初始情况有二
// 设置数组,记录能否获得相应水量,初始化大小为[x+y+1],并设置真值
vector<bool> res(x + y + 1, false); res[0] = true;
// 设置终止条件,当水的余量和桶id已经有记录,就退出。
map<int, int> endjudge;
for (int i = 0; i < 2; i++) {
pair<int, int> water(bucket[i], i);
while (endjudge.find(water.first) == endjudge.end() || (*endjudge.find(water.first)).second != water.second) {
int otherbucid = (water.second + 1) % 2;
res[water.first] = true; res[water.first + bucket[otherbucid]] = true;
if (water.first > bucket[otherbucid]) {
water.first -= bucket[otherbucid]; // 倒给另一个桶,还有剩余
endjudge.insert(water);
break;
}
else {
water.first = bucket[water.second]-(bucket[otherbucid]-water.first);
water.second = otherbucid; // 全倒给另一个桶,或者不到出,这个判断就傻了。
}
}
}
return res[z];
}