365. 水壶问题

image.png
思路:刚看这题是懵圈的状态的,完全不知道如何入手。但是仔细想想会发现这是一个搜索问题。抽象出来的话,就是你有两个容器,你需要用这两个容器凑出“一定容量”的水。允许的操作有3个,如题中所述,实际上是有6个操作的。这就是回到了递归执行可执行操作,然后寻找结束条件这类的问题了,最容易想到的就是DFS算法或BFS算法。

  1. /**
  2. 6种操作
  3. 1. 装满水壶1
  4. 2. 装满水壶2
  5. 3. 清空水壶1
  6. 4. 清空水壶2
  7. 5. 水壶1倒向水壶2,直到水壶2满或水壶1倒尽了
  8. 6. 水壶2倒向水壶1,直到水壶1满或水壶2倒尽了
  9. 结束条件
  10. 水壶1凑出 || 水壶2凑出 || 水壶1+水壶2凑出
  11. */
  12. class Solution {
  13. public boolean canMeasureWater(int jug1Capacity, int jug2Capacity, int targetCapacity) {
  14. int x = jug1Capacity;
  15. int y = jug2Capacity;
  16. int z = targetCapacity;
  17. LinkedList<int[]> stack = new LinkedList<>(); //装水壶1和水壶2的当前水量
  18. stack.addLast(new int[]{0, 0});
  19. Set<Long> visited = new HashSet(); //已经查过了,使用hash函数
  20. while (!stack.isEmpty()) {
  21. if (visited.contains(hash(stack.getLast()))) {
  22. stack.pollLast();
  23. continue;
  24. }
  25. visited.add(hash(stack.getLast()));
  26. int[] state = stack.pollLast();
  27. int remainX = state[0];
  28. int remainY = state[1];
  29. if (remainX==z || remainY==z || (remainX+remainY)==z) {
  30. return true;
  31. }
  32. //上述6种操作
  33. stack.push(new int[]{x, remainY});
  34. stack.push(new int[]{remainX, y});
  35. stack.push(new int[]{0, remainY});
  36. stack.push(new int[]{remainX, 0});
  37. int xToy = Math.min(remainX,y-remainY);
  38. stack.push(new int[]{remainX - xToy, remainY + xToy});
  39. int yTox = Math.min(x-remainX,remainY);
  40. stack.push(new int[]{remainX + yTox, y - yTox});
  41. }
  42. return false;
  43. }
  44. public long hash(int[] state) {
  45. return (long) state[0] * 10000001 + state[1];
  46. }
  47. }