LeetCode3.18-3.21

3.18 每日一题

题目:矩形以列表 [x1, y1, x2, y2] 的形式表示,其中 (x1, y1) 为左下角的坐标,(x2, y2) 是右上角的坐标。
如果相交的面积为正,则称两矩形重叠。需要明确的是,只在角或边接触的两个矩形不构成重叠。
给出两个矩形,判断它们是否重叠并返回结果。

解法1:

判断几种不重叠的情况,取反即可。
假设矩形rec1在坐标系中,另一个矩形rec2如果和rec1不重叠,那么rec2至少符合以下4种情况之一:

  • rec1在rec2左侧;
  • rec1在rec2右侧;
  • rec1在rec2上方;
  • rec1在rec2下方;

以坐标的形式表示为:

  • rec1[2] <= rec2[0];
  • rec1[0] >= rec2[2];
  • rec1[1] >= rec2[3];
  • rec1[3] <= rec2[1];
public class Solution {
	/*
	 * 找出不可能叠加的情况取反
	 */
	public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
		return !(rec1[0] >= rec2[2] || rec1[2] <= rec2[0] 
		|| rec1[1] >= rec2[3] || rec1[3] <= rec2[1]);
	}
	
}

解法2:

判断rec1和rec2在x轴和y轴的投影线段是否有交集

public class Solution1 {
	public boolean isRectangleOverlap(int[] rec1, int[] rec2) {
		return ((Math.min(rec1[2], rec2[2]) > Math.max(rec1[0], rec2[0]))
		 && (Math.min(rec1[3], rec2[3]) > Math.max(rec1[1], rec2[1])));
	}
}

剑指offer 面试题27

题目: 请完成一个函数,输入一个二叉树,该函数输出它的镜像。

解法1:

DFS: 二叉树前序遍历,每遍历一个节点,将左右子树交换。

class Solution {
    public TreeNode mirrorTree(TreeNode root) {
      	if(root == null) return null;
		TreeNode temp = root.left;
		root.left = root.right;
		root.right = temp;
		mirrorTree(root.left);
		mirrorTree(root.right);
		return root;
	}
    
}

解法2

BFS: 广度优先遍历,相同思路。

public class Solution {
	public TreeNode mirrorTree(TreeNode root) {
		if(root == null) return null;
		List<TreeNode> queue = new LinkedList<>();
		queue.add(root);
		while(!queue.isEmpty()) {
			TreeNode node = queue.remove(0);
			TreeNode temp = node.left;
			node.left = node.right;
			node.right = temp;
			if(node.left != null) 
				queue.add(node.left);
			if(node.right != null)
				queue.add(node.right);
		}
		return root;
	}
}

3.21每日一题

题目:
有两个容量分别为 x升 和 y升 的水壶以及无限多的水。请判断能否通过使用这两个水壶,从而可以得到恰好 z升 的水?

如果可以,最后请用以上水壶中的一或两个来盛放取得的 z升 水。

你允许:

  • 装满任意一个水壶
  • 清空任意一个水壶
  • 从一个水壶向另外一个水壶倒水,直到装满或者倒空

两种思路,BFS(DFS)或数学

BFS

package day19__365_canMeasureWater;

import java.util.AbstractMap.SimpleEntry;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;

public class Solution {
	/*
	 * 广度优先搜索 在任意时刻可以执行的操作有: 把X壶的水灌到Y壶,直至灌满或倒空 把Y壶的水灌到X壶,直至灌满或倒空 把X壶灌满 把Y壶灌满 把X壶倒空
	 * 把Y壶倒空 在每一时刻将可以做的所有操作存储到队列中, 使用一个set保存已经遍历过的情况,避免重复遍历一种情况
	 * 注意:两个壶不可能同时半满。如果一个壶是半满的,另一个壶必然是全满或者空的。如果有一个壶半满就不能把这个壶灌满或者倒空,这样会回到初始状态,没有意义。
	 */
	public boolean canMeasureWater(int x, int y, int z) {
		if (x == z || y == z || x + y == z)
			return true;
		if (x + y < z)
			return false;
		// 初始状态的x和y罐
		SimpleEntry<Integer, Integer> init = new SimpleEntry<>(0, 0);
		// 遍历使用的队列
		Queue<SimpleEntry<Integer, Integer>> queue = new LinkedList<>();
		// 存储结果的set
		Set<SimpleEntry<Integer, Integer>> visited = new HashSet<>();
		queue.add(init);
		visited.add(init);
		while (!queue.isEmpty()) {
			SimpleEntry<Integer, Integer> entry = queue.poll();
			int curX = entry.getKey();
			int curY = entry.getValue();
			if (curX == z || curY == z || curX + curY == z)
				return true;
			// x罐倒满
			addIntoQueue(new SimpleEntry<>(x, curY), queue, visited);
			// y罐倒满
			addIntoQueue(new SimpleEntry<>(curX, y), queue, visited);
			// x罐倒空
			addIntoQueue(new SimpleEntry<>(0, curY), queue, visited);
			// y罐倒空
			addIntoQueue(new SimpleEntry<>(curX, 0), queue, visited);

			// 把x罐的水倒进y罐,两种情况:1.x罐水倒完;2.y罐倒满。倒水的体积为min(y-curY,curX)。(y-curY是y桶还能加水的体积)
			int moveSize = Math.min(y - curY, curX);
			addIntoQueue(new SimpleEntry<>(curX - moveSize, curY + moveSize), queue, visited);
			// 同理,把y罐的水倒进x罐
			moveSize = Math.min(x - curX, curY);
			addIntoQueue(new SimpleEntry<>(curX + moveSize, curY - moveSize), queue, visited);
		}
		// 遍历所有没有符合条件的情况
		return false;
	}

	public void addIntoQueue(SimpleEntry<Integer, Integer> entry, Queue<SimpleEntry<Integer, Integer>> queue,
			Set<SimpleEntry<Integer, Integer>> visited) {
		if (!visited.contains(entry)) {
			queue.add(entry);
			visited.add(entry);
		}
	}
}

数学

package day19__365_canMeasureWater;

public class Solution1 {
	/*
	 * 数学
	 * 可以认为每次操作只会让桶里的水总量增加 x,增加 y,减少 x,或者减少 y。
	 * 首先要清楚,在题目所给的操作下,两个桶不可能同时有水且不满。因为观察所有题目中的操作,操作的结果都至少有一个桶是空的或者满的;
	 * 其次,对一个不满的桶加水是没有意义的。因为如果另一个桶是空的,那么这个操作的结果等价于直接从初始状态给这个桶加满水;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态分别给两个桶加满;
	 * 再次,把一个不满的桶里面的水倒掉是没有意义的。因为如果另一个桶是空的,那么这个操作的结果等价于回到初始状态;而如果另一个桶是满的,那么这个操作的结果等价于从初始状态直接给另一个桶倒满。
	 * 那么可以改写目标:找到一对整数 a,b,使得
	 * 			ax+by=z
	 * 贝祖定理,ax+by=z 有解当且仅当 z 是 x,y 的最大公约数的倍数。因此我们只需要找到 x,y 的最大公约数并判断 z 是否是它的倍数即可。
	 */
	public boolean canMeasureWater(int x, int y, int z) {
		if(x == 0 && y == 0)
			return z == 0;
		if(x + y < z) return false;
		//找x和y的最大公约数
		return (z % gcd(x, y) == 0);
	}
	
	public int gcd(int x, int y) {
		if(y == 0) return x;
		return (gcd(y, x%y));
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值