「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
一、题目一
给定一个非负数组成的数组,长度一定大于1,想知道数组中哪两个数&的结果最大,返回这个最大结果。
要求:时间复杂度O(N),额外空间复杂度O(1)
提示:
- 非负数即数组中都是正整数,任何数都可以用二进制表示,非负数说明最高位为0
- 剩余31位,从31位到0位,两个数每位上进行&操作,尽量高位&上结果为1,才能最大
- 数据始终在数组上移动,没有产生额外的空间
思路:
- 二进制&,不是1就是0,所以最高位&为1时,结果最大。
- 始终在数组中通过数据交换淘汰数据:空间复杂度O(1)
- M:指向数据淘汰的指针
- arr[0...M-1]:有效数
- arr[M...]:淘汰的数,垃圾数
// O(N^2)的暴力解
public static int maxAndValue1(int[] arr) {
int N = arr.length;
int max = Integer.MIN_VALUE;
for (int i = 0; i < N; i++) {
for (int j = i + 1; j < N; j++) {
max = Math.max(max, arr[i] & arr[j]);
}
}
return max;
}
// 时间复杂度O(N),额外空间复杂度O(1)
public static int maxAndValue2(int[] arr) {
// arr[0...M-1] arr[M....]
int M = arr.length;
int ans = 0;
for (int bit = 30; bit >= 0; bit--) {
// arr[0...M-1] arr[M...]
int i = 0;
int tmp = M;
while (i < M) { // arr[0...M-1]
if ((arr[i] & (1 << bit)) == 0) {
swap(arr, i, --M);
} else {
i++;
}
}
if (M == 2) { // arr[0,1]
return arr[0] & arr[1];
}
if (M < 2) { // 不淘汰,接受该位置为0的情况
M = tmp;
} else { // > 2个数 bit位上有1
ans |= (1 << bit);
}
}
return ans;
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
二、题目二
给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
思路:
x为空树,需不需要被覆盖?不需要覆盖,可以认为空树是直接被覆盖的的状态,
所以空树就不存在被覆盖的情况,假设为系统最大。
空树上边没法放相机,假设为系统最大。
空树就认为被覆盖,且不能放相机
以任意节点为头节点的二叉树,存在三种可能:
1. 头节点放向机,且被覆盖
2. 头节点没放相机,且被覆盖
3. 头节点没放相机,且没被覆盖
public static class TreeNode {
public int value;
public TreeNode left;
public TreeNode right;
}
public static int minCameraCover(TreeNode root) {
Info data = process(root);
return (int) Math.min(data.uncovered + 1, Math.min(data.coveredNoCamera, data.coveredHasCamera));
}
// 潜台词:x是头节点,x下方的点都被覆盖的情况下
public static class Info {
public long uncovered; // x没有被覆盖,x为头的树至少需要几个相机
public long coveredNoCamera; // x被相机覆盖,但是x没相机,x为头的树至少需要几个相机
public long coveredHasCamera; // x被相机覆盖了,并且x上放了相机,x为头的树至少需要几个相机
public Info(long un, long no, long has) {
uncovered = un;
coveredNoCamera = no;
coveredHasCamera = has;
}
}
// 所有可能性都穷尽了
public static Info process(TreeNode X) {
if (X == null) { // base case
return new Info(Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
}
Info left = process1(X.left);
Info right = process1(X.right);
// x uncovered x自己不被覆盖,x下方所有节点,都被覆盖
// 左孩子: 左孩子没被覆盖,左孩子以下的点都被覆盖
// 左孩子被覆盖但没相机,左孩子以下的点都被覆盖
// 右孩子被覆盖也有相机,右孩子以下的点都被覆盖
long uncovered = left.coveredNoCamera + right.coveredNoCamera;
// x下方的点都被covered,x也被cover,但x上没相机
long coveredNoCamera = Math.min(
// 1)
left.coveredHasCamera + right.coveredHasCamera,
Math.min(
// 2)
left.coveredHasCamera + right.coveredNoCamera,
// 3)
left.coveredNoCamera + right.coveredHasCamera));
// x下方的点都被covered,x也被cover,且x上有相机
long coveredHasCamera =
Math.min(left.uncovered, Math.min(left.coveredNoCamera, left.coveredHasCamera))
+ Math.min(right.uncovered, Math.min(right.coveredNoCamera, right.coveredHasCamera))
+ 1;
return new Info(uncovered, coveredNoCamera, coveredHasCamera);
}