leetcode365.水壺問題

有兩個容量分別爲 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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/water-and-jug-problem
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

完整代碼

基本思想:
BFS
需要確定水壺的六種狀態:

  • A空
  • B空
  • A滿
  • B滿
  • A向B倒水
  • B向A倒水
    在當前狀態下,每一次都考慮下這六種狀態,如果出現了:x + y = z的情況,說明成功了
class Solution {
   
    
public:
    bool canMeasureWater(int x, int y, int z) {
        queue<pair<int, int>> q;
        unordered_set<pair<int, int>, myHash> s;//確保狀態不會重複考慮
        q.push({0, 0}); //初始情況下是0狀態
        s.insert({0, 0});
        while(!q.empty()){
            auto temp = q.front();
            q.pop();
            if(temp.first + temp.second == z)
                return true;
            for(int i = 0; i < 6; ++i){//針對當前的水量,考慮這6中狀態
                auto next = op(i, temp, x, y);
                if(s.find(next) != s.end()){
                    continue;
                }
                s.insert(next);
                q.push(next);
            }            
        }
        return false;
    }
private:
    
    struct myHash{//自定義的哈希函數
        size_t operator()(const pair<int, int> &val) const {
            return static_cast<size_t>(val.first) * 100000007 + val.second;   
        }            
    };
    pair<int, int> op(int i, pair<int, int> temp, int x, int y){
        switch(i){
            case 0: return make_pair(x, temp.second);//A滿
            case 1: return make_pair(temp.first, y);//B滿
            case 2: return make_pair(0, temp.second);//A空
            case 3: return make_pair(temp.first, 0);//B空
            case 4: {//A向B倒水
                int t = min(temp.first, y - temp.second);
                return make_pair(temp.first - t, temp.second + t);
            }
            case 5:{//B向A倒水
                //A中能盛B中的全部的水,還是隻能盛A所需的那一部分水,二者取最小
                int t = min(x - temp.first, temp.second);
                return make_pair(temp.first + t, temp.second - t);
            }            
        }
        return make_pair(0, 0);
    }
    

    
};

代碼說明:上述代碼中使用了unordered_set

  • unordered_set內部實現是基於Hash實現,內部元素無序
  • set內部實現是基於紅黑樹實現,內部元素有序
  • 對比來看,如果不要求元素有序,只是爲了保證元素不重複出現,用unordered_set效率高,因爲unordered_set在對數據進行增刪時時間複雜度是O(1),set是O(logn)
  • 在使用unordered_set時,默認的Hash函數只支持string類型等少數類型,多數情況下需要自己定義哈希函數

數學思想
ax + by = z, 求x,y的最大公因數m, 如果z是m的倍數,那麼可以達到目標,否則不行

  • 求x , y的最大公因數
  • 判斷 z 是否是該最大公因數的倍數
class Solution {
public:
    bool canMeasureWater(int x, int y, int z) {
        if(z == 0)
            return true;
        if(x + y == 0 || x + y < z)
            return false;
        int m = __gcd(x, y);      
        return z % m == 0;//一定要注意:m不能爲0
    }
};

自己實現求最大公約數的代碼

class Solution {
public:
    bool canMeasureWater(int x, int y, int z) {
        if(z == 0)
            return true;
        if(x + y == 0 || x + y < z)
            return false;
        int m = gcd(x, y); 
      
        return z % m == 0;
    }
private: 
    int gcd(int x, int y){
        if(x > y)
            return gcd(y, x);
        while(x){
            int t = y % x;
            y = x;
            x = t;
        }
        return y;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章