LeetCode——365.水壶问题

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

解法一:

此题只需要判断是否能得到z升水,无需关注过程,故可使用数学知识直接解答。当z 能被x 和y 的最大公因数整除时,即能用x,y 测出z 升水。使用辗转相除法求最大公因数,再与z 取模进行判断

class solution{
	public boolean canMeasureWater(int x, int y, int z) {
        if (z == 0) {
            return true;
        }
        if (x + y < z) {
            return false;
        } else {
            return z % gcd(x, y) == 0 ? true : false;
        }
    }
}

在这里插入图片描述
解法二:
BFS,思路参考:LeetCode题解

/**
     * 表示桶两桶情况的类,x,y分别表示两桶内水的体积
     */
    private class MyState {
        private int x;
        private int y;

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public MyState(int x, int y) {
            this.x = x;
            this.y = y;
        }
        //如果重写以下方法会提示运行超时
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            MyState state = ( MyState) o;
            return x == state.x &&
                    y == state.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }

    public boolean canMeasureWater(int x, int y, int z) {
        // 特殊情况判定
        if (z == 0) {
            return true;
        }
        if (x + y < z) {
            return false;
        }
        // 初始化情况
        MyState initState = new MyState(0, 0);

        // 使用队列进行广度优先遍历
        // 使用set标记已经遍历过的情况
        Queue<MyState> queue = new LinkedList<>();
        Set<MyState> visited = new HashSet<>();

        queue.offer(initState);
        visited.add(initState);

        // 广度遍历
        while (!queue.isEmpty()) {
            MyState head = queue.poll();
            int curX = head.getX();
            int curY = head.getY();

            // 对获取值进行一次判断
            if (curX == z || curY == z || curX + curY == z) {
                return true;
            }

            // 获取后去下一步可能出现的状态
            List<MyState> nextStates = getNextStates(curX, curY, x, y);
            // 打开以便于观察,调试代码
            // System.out.println(head + " => " + nextStates);
            
            for (MyState nextState : nextStates) {
                if (!visited.contains(nextState)) {
                    queue.offer(nextState);
                    // 添加到队列以后,必须马上设置为已经访问,否则会出现死循环
                    visited.add(nextState);
                }
            }
        }
        return false;
    }

    /**
     * 获取所有可能状态
     * 
     * @param curX 当前x桶的水量
     * @param curY 当前y桶的水量
     * @param x    x桶的容积
     * @param y    y桶的容积
     * @return 所有可能的情况
     */
    private List<MyState> getNextStates(int curX, int curY, int x, int y) {
        List<MyState> nextStates = new ArrayList<>(8);

        // 外部加水把x桶加满
        MyState nextState1 = new MyState(x, curY);
        // 外部加水把y桶加满
        MyState nextState2 = new MyState(curX, y);
        // 把x桶清空
        MyState nextState3 = new MyState(0, curY);
        // 把y桶清空
        MyState nextState4 = new MyState(curX, 0);
        // x桶的水到给y桶
            // y桶满了,x桶有剩余
        MyState nextState5 = new MyState(curX - (y - curY), y);
            // y桶未满,x桶倒空
        MyState nextState6 = new MyState(0, curY + curX);
        // y桶的水打入x桶
            // x桶满了,y桶有剩余
        MyState nextState7 = new MyState(x, curY - (x - curX));
            // x桶未满,y桶已空
        MyState nextState8 = new MyState(curX + curY, 0);
        
        //桶没满时倒水进桶
        if (curX < x) {
            nextStates.add(nextState1);
        }
        if (curY < y) {
            nextStates.add(nextState2);
        }
        //桶有水时,将水倒出
        if (curX > 0) {
            nextStates.add(nextState3);
        }
        if (curY > 0) {
            nextStates.add(nextState4);
        }

        // 有剩余才倒
        if (curX - (y - curY) > 0) {
            nextStates.add(nextState5);
        }
        if (curY - (x - curX) > 0) {
            nextStates.add(nextState7);
        }

        // 倒过去倒不满才倒
        if (curX + curY < y) {
            nextStates.add(nextState6);
        }
        if (curX + curY < x) {
            nextStates.add(nextState8);
        }
        return nextStates;

    }

在这里插入图片描述

发布了24 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44804750/article/details/105015161