有两个容量分别为 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
通过题意我们可以了解到:
总共的水壶状态如下:
1.倒空 x。
2.倒空 y。
3.装满 x。
4.装满 y。
5.将 x 水壶里面的水倒入y水壶,直到倒满或倒空。
6.将 y 水壶里面的水倒入x水壶,直到倒满或倒空。
总的来说水壶的操作就是以上这几种状态,可以很容易想到使用回溯和哈希,我开头的想法是,
在递归过程当中记录唯一的x和唯一的y。想着用unordered_map<int, vector<int>>> m_map去
实现唯一的cur_x遍历查找多个cur_y。结果数据太大超出内存限制,
最后改成 unordered_set<pair<long, long>, pair_hash> m_set
自己写一个简单的哈希函数去计算,结果栈溢出,我看了一下边界值,觉得都考虑到了。实在想不懂
错哪里了,看了一下大佬解析。原来递归深度太深导致栈溢出。大佬给的方法是用栈模拟递归过程。
不得不说真的很巧妙,虽然过了,但是我时间和空间的效率依然很低。
#include <iostream>
#include <algorithm>
#include <unordered_set>
#include <string>
#include <stack>
using namespace std;
class Solution {
public:
bool canMeasureWater(int x, int y, int z) {
volumeX = x;
volumeY = y;
/* 两种情况,x水浒倒满,y水浒倒满 */
backtrace(0, 0, z);
return CanGetZ;
}
private:
bool CanGetZ = false;
int volumeX;
int volumeY;
void backtrace(int cur_x, int cur_y, int z) {
stack<pair<int, int>> m_stack;
m_stack.emplace(make_pair(cur_x, cur_y));
while (!m_stack.empty()) {
if (m_set.count(m_stack.top())) {
m_stack.pop();
continue;
}
m_set.insert(m_stack.top());
/* 取出栈顶的cur_x,cur_y值, pTop.first等于x, pTop.second等于y */
pair<int, int>& pTop = m_stack.top();
/* 判断x,y 是否满足条件 */
if (pTop.first < 0 || pTop.second < 0) {
return;
}
if (pTop.first == z || pTop.second == z || (pTop.first + pTop.second == z)) {
CanGetZ = true;
return;
}
/* 装满 x */
m_stack.emplace(make_pair(volumeX, pTop.second));
/* 装满 y */
m_stack.emplace(make_pair(pTop.first, volumeY));
/* 倒空x */
m_stack.emplace(make_pair(0, pTop.second));
/* 倒空y */
m_stack.emplace(make_pair(pTop.first, 0));
/* x倒进y,直到装满或者为空 */
if (pTop.first + pTop.second > volumeY) {
m_stack.emplace(make_pair(pTop.first + pTop.second - volumeY, volumeY));
}
else {
m_stack.emplace(make_pair(0, pTop.first + pTop.second));
}
/* y倒进x,直到装满或者为空*/
if (pTop.first + pTop.second > volumeX) {
m_stack.emplace(make_pair(volumeX, pTop.first + pTop.second - volumeX));
}
else {
m_stack.emplace(make_pair(pTop.first + pTop.second, 0));
}
}
}
private:
struct pair_hash {
inline size_t operator()(const pair<long, long>& p) const {
return p.first * 2 + p.second;
}
};
unordered_set<pair<long, long>, pair_hash> m_set; /* 记录已经存在的x,y */
};
int main() {
Solution* ps = new Solution();
cout << ps->canMeasureWater(3, 5, 4) << endl;
return 0;
}