2. 问题引入
boolean
是 Java 的基本数据类型之一,只有两个值:true
和 false
。本文要解决的问题很简单:**给定三个布尔值,判断其中至少有两个为 true
**。
虽然问题本身不难,但我们将探索几种优雅的解决方案,并分析每种方法是否易于扩展为更通用的场景:**给定 n 个布尔值,判断其中至少 x 个为 true
**。
为验证各方案,我们先用 Map
存储测试用例和预期结果:
static final Map<boolean[], Boolean> TEST_CASES_AND_EXPECTED = Map.of(
new boolean[]{true, true, true}, true,
new boolean[]{true, true, false}, true,
new boolean[]{true, false, false}, false,
new boolean[]{false, false, false}, false
);
说明:这里使用 Java 9+ 的
Map.of
创建不可变 Map。若使用 Java 8,可改用 Guava 的ImmutableMap
。
接下来,我们逐步分析解决方案。
3. 遍历布尔值
最直接的思路是遍历三个布尔值并统计 true
的个数。一旦计数器 ≥ 2 就立即返回 true
,否则最终返回 false
:
public static boolean twoOrMoreAreTrueByLoop(boolean a, boolean b, boolean c) {
int count = 0;
for (boolean i : new Boolean[] { a, b, c }) {
count += i ? 1 : 0;
if (count >= 2) {
return true;
}
}
return false;
}
测试验证:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByLoop(array[0], array[1], array[2])).isEqualTo(expected)
);
优势:逻辑清晰,且易于扩展为通用方案(接受布尔数组和阈值 x):
public static boolean xOrMoreAreTrueByLoop(boolean[] booleans, int x) {
int count = 0;
for (boolean i : booleans) {
count += i ? 1 : 0;
if (count >= x) {
return true;
}
}
return false;
}
4. 转换为数值计算
另一种思路是将布尔值转换为整数后求和,判断结果是否 ≥ 2:
public static boolean twoOrMoreAreTrueBySum(boolean a, boolean b, boolean c) {
return (a ? 1 : 0) + (b ? 1 : 0) + (c ? 1 : 0) >= 2;
}
测试验证:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueBySum(array[0], array[1], array[2])).isEqualTo(expected)
);
同样可扩展为通用方案,使用 Stream API 实现更简洁:
public static boolean xOrMoreAreTrueBySum(Boolean[] booleans, int x) {
return Arrays.stream(booleans)
.mapToInt(b -> Boolean.TRUE.equals(b) ? 1 : 0)
.sum() >= x;
}
注意:参数类型为
Boolean[]
而非boolean[]
,因为 Stream 不支持基本类型数组。
5. 使用逻辑运算符
通过逻辑与(&&
)运算组合所有两两布尔对,只要有一对为 true
即满足条件:
public static boolean twoOrMoreAreTrueByOperators(boolean a, boolean b, boolean c) {
return (a && b) || (a && c) || (b && c);
}
测试验证:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByOperators(array[0], array[1], array[2])).isEqualTo(expected)
);
局限性:
- 仅适用于判断至少两个
true
的场景 - 当布尔值数量 n 增大时,需要构造极长的逻辑表达式链
- 无法扩展为通用方案
6. 使用卡诺图
卡诺图(Karnaugh Map)是简化布尔代数表达式的经典工具。针对三个布尔值 A、B、C,构建卡诺图:
| C | !C
------|---|----
A B | 1 | 1
A !B | 1 | 0
!A !B | 0 | 0
!A B | 1 | 0
解读:
1
表示至少两个true
的情况- 按行/列分组简化表达式:
- 第一行(A、B 均为
true
):A && B
- 第一列(C 为
true
且 A/B 至少一个true
):C && (A || B)
最终表达式为:
public static boolean twoOrMoreAreTrueByKarnaughMap(boolean a, boolean b, boolean c) {
return (c && (a || b)) || (a && b);
}
测试验证:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByKarnaughMap(array[0], array[1], array[2])).isEqualTo(expected)
);
局限性:
- 当布尔值数量 n 增大时,构建卡诺图复杂度急剧上升
- 不适合动态通用场景
7. 使用异或运算符
利用异或(^
)的特性设计巧妙解法:
- 若
a ^ b
为true
,说明 a、b 值不同,此时结果取决于 c - 若
a ^ b
为false
,说明 a、b 值相同,此时结果取决于 a
public static boolean twoOrMoreAreTrueByXor(boolean a, boolean b, boolean c) {
return a ^ b ? c : a;
}
测试验证:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByXor(array[0], array[1], array[2])).isEqualTo(expected)
);
特点:
- 代码极简,但理解门槛较高
- 仅适用于三个布尔值且判断至少两个
true
的固定场景 - 无法扩展为通用方案
8. 总结
我们分析了五种判断三个布尔值中至少两个为 true
的方案:
方案 | 可扩展性 | 适用场景 |
---|---|---|
遍历统计 | ⭐⭐⭐⭐⭐ | 通用场景(n 个布尔值,x 个阈值) |
数值求和 | ⭐⭐⭐⭐ | 通用场景 |
逻辑运算符 | ⭐ | 仅固定三个布尔值 |
卡诺图 | ⭐ | 仅固定三个布尔值 |
异或运算 | ⭐ | 仅固定三个布尔值 |
推荐选择:
- 需要通用性 → 遍历统计 或 数值求和
- 仅处理三个布尔值 → 异或运算(代码最简)或 逻辑运算符(可读性更佳)
踩坑提醒:卡诺图和异或方案虽然巧妙,但扩展性差,实际开发中除非有特殊需求,否则不建议使用。