LeetCode-365. 水壶问题

241 篇文章 1 订阅
210 篇文章 0 订阅

有两个容量分别为 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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值