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:
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));
}
}