(1)
答案选ABC。 - A选项: throws 关键字在方法声明时使用,用于告知调用者该方法可能会抛出哪些异常类型,方便调用者进行异常处理,A选项正确。 - B选项: throw 关键字用于在程序执行过程中,当满足特定条件时,手动创建并抛出一个异常对象,来表示程序出现了异常情况,B选项正确。 - C选项:当 throw 抛出异常对象后,当前方法的后续代码不再执行,程序会跳转到调用该方法的地方,并将异常对象传递给调用者,由调用者进行处理,C选项正确。 - D选项: throw 不仅能抛出Java标准库中定义的异常类对象,还可以抛出用户自定义的异常类对象,只要该类继承自 Exception 或其子类,D选项错误。
(2)
ThreadLocalMap中使用开放地址法来处理散列冲突,而HashMap中使用的是分离链表法。之所以采用不同的方式主要是因为:在ThreadLocalMap中的散列值分散得十分均匀,很少会出现冲突。并且ThreadLocalMap经常需要清除无用的对象,使用纯数组更加方便。
(3)
A错误:m1()是private方法,private修饰的方法对子类是不可见的,因此子类无法继承和覆盖私有方法。
B错误:m2()使用默认访问权限(package-private),只对同一包内的类可见。如果子类与父类不在同一个包中,则无法继承和覆盖该方法。所以不能说"一定"能够继承和覆盖。
D错误:m4()是static方法(静态方法)。静态方法可以被子类继承,但不能被覆盖(重写)。子类中定义相同签名的静态方法,这种行为称为隐藏(hide),而不是覆盖(override)。
(4)
算法思路
该解决方案采用了以下策略:
- 先计算 Alice 和 Bob 各自糖果的总尺寸
- 对于 Alice 的每一个糖果,使用二分查找在 Bob 的糖果中寻找合适的交换对象
- 通过数学推导确定需要寻找的目标值
- 找到符合条件的糖果对后立即返回
代码详细解析
class Solution {
public int[] fairCandySwap(int[] aliceSizes, int[] bobSizes) {
// 计算Alice和Bob各自糖果的总尺寸
int sumA = Arrays.stream(aliceSizes).sum();
int sumB = Arrays.stream(bobSizes).sum();
// 遍历Alice的每一个糖果
for (int i = 0; i < aliceSizes.length; i++) {
int value = aliceSizes[i]; // 当前Alice的糖果尺寸
// 在Bob的糖果中使用二分查找寻找合适的交换对象
int left = 0;
int right = bobSizes.length - 1;
while (left <= right) {
int middle = left + (right - left) / 2; // 计算中间位置,避免整数溢出
// 计算交换后的总尺寸
int source = sumA - value + bobSizes[middle]; // Alice交换后的总尺寸
int target = sumB + value - bobSizes[middle]; // Bob交换后的总尺寸
// 如果两者相等,找到合适的交换对
if (source == target) {
return new int[]{value, bobSizes[middle]};
} else if (source < target) {
// Alice的总尺寸小于Bob,需要增大Alice的尺寸
left = middle + 1;
} else {
// Alice的总尺寸大于Bob,需要减小Alice的尺寸
right = middle - 1;
}
}
}
// 如果没有找到合适的交换对(理论上不会发生)
return new int[]{0, 0};
}
}
关键数学推导
算法的核心在于这个等式:
sumA - a + b = sumB - b + a
变形可得:
2(b - a) = sumB - sumA
b = a + (sumB - sumA) / 2
这意味着对于 Alice 的每个糖果 a,我们需要在 Bob 的糖果中找到 b,使得 b = a + (sumB - sumA)/2。