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];
}