檢查 Java 中至少三分之二的布爾值是否為真
一、概述
boolean
是 Java 的原語之一。這是一個非常簡單的數據類型,只有兩個值: true
和false
。
在本教程中,我們將研究一個問題:檢查給定的三個boolean
中是否至少有兩個true
。
2. 問題介紹
問題很簡單。我們將獲得三個booleans
。如果其中至少有兩個為true
,我們的方法應該返回true
。
解決問題對我們來說不是挑戰。但是,在本教程中,我們將探索一些不錯的解決方案。此外,我們將討論每種方法是否可以輕鬆擴展以解決一般問題:給定n
布爾值,檢查它們中的至少x
是否為true
。
我們將通過單元測試來驗證每種方法。因此,讓我們首先創建一個Map
對象來保存測試用例和預期結果:
static final Map<boolean[], Boolean> TEST_CASES_AND_EXPECTED = ImmutableMap.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
);
如上面的代碼所示, TEST_CASES_AND_EXPECTED
映射包含四種場景及其預期結果。稍後,我們將遍歷這個 map 對象並將每個boolean
數組作為參數傳遞給每個方法,並驗證該方法是否返回預期值。
接下來,讓我們看看如何解決這個問題。
3. 循環遍曆三個布爾值
解決這個問題的最直接的想法可能是遍曆三個給定的布爾值併計算trues
值。
一旦計數器大於或等於2
,我們就會停止檢查並返回true
。否則,三個trues
booleans
中的 true 數小於 2。因此,我們返回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
映射來測試此方法是否有效:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByLoop(array[0], array[1], array[2])).isEqualTo(expected));
如果我們運行這個測試,不出所料,它通過了。
這種方法很容易理解。此外,假設我們將方法的參數更改為boolean
數組(或Collection
)和int x
。在這種情況下,它可以很容易地擴展為解決問題的通用解決方案:給定n booleans,
檢查其中至少x
個是否為true
:
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));
我們還可以將這種方法轉變為一種通用解決方案,以從n booleans
中檢查至少x trues
個真值:
public static boolean xOrMoreAreTrueBySum(Boolean[] booleans, int x) {
return Arrays.stream(booleans)
.mapToInt(b -> Boolean.TRUE.equals(b) ? 1 : 0)
.sum() >= x;
}
我們使用 Stream API 將每個boolean
轉換為int
並在上面的代碼中計算總和。
5. 使用邏輯運算符
我們通過將布爾值轉換為整數解決了這個問題。或者,我們可以使用邏輯運算來確定三個布爾值中的至少兩個是否為true.
我們可以對每兩個布爾值執行邏輯 AND ( &&
) 操作。因此,我們將對給定的三個布爾值執行三個 AND 操作。如果三個布爾值中有兩個是true
,那麼至少一個邏輯 AND 運算應該導致true
:
public static boolean twoOrMoreAreTrueByOpeators(boolean a, boolean b, boolean c) {
return (a && b) || (a && c) || (b && c);
}
接下來,如果我們使用TEST_CASES_AND_EXPECTED
映射測試此方法,它也會通過:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByOpeators(array[0], array[1], array[2])).isEqualTo(expected));
現在,讓我們考慮一下是否可以將這種方法擴展到一般情況。只有當x
為 2 時才有效。另外,如果n
足夠大,我們可能需要構建一個長的邏輯運算鏈。
因此,它不適用於一般問題。
6. 使用卡諾圖
卡諾圖是一種簡化布爾代數表達式的方法。此外,我們可以從卡諾圖寫出表達式。因此,有時,它可以幫助我們解決複雜的布爾代數問題。
接下來,讓我們看看如何使用卡諾圖解決這個問題。鑑於我們有三個布爾值 A、B 和 C,我們可以構建一個卡諾圖:
| C | !C
------|---|----
AB | 1 | 1
A !B | 1 | 0
!A !B | 0 | 0
!AB | 1 | 0
在上表中,A、B 和 C 表示它們的true
值。相反,!A、!B 和 !C 表示它們的false
值。
因此,正如我們所見,該表涵蓋了給定三個布爾值的所有可能組合。此外,我們可以找到至少兩個布爾值為真的所有組合情況。對於這些情況,我們在表中寫入了“1”。因此,有兩組包含這些:第一行(組 1)和第一列(組 2)。
因此,產生一個的最終布爾代數表達式將是:( (the expression to obtain all ones in group1 ) || (the expression to obtain all ones in group2)
。
接下來,讓我們分而治之。
- 第 1 組(第一行)——A 和 B 都為真。無論 C 有什麼值,我們都會有一個。因此,我們有:
A && B
- 第 2 組(第一列)——首先,C 始終為真。而且,A 和 B 中必須至少有一個為真。因此,我們得到: 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. 使用xor
或運算符
最後,讓我們看看另一種有趣的方法。
在這個問題中,我們得到了三個布爾值。此外,我們知道boolean
只能有兩個不同的值: true
和false
。
所以,讓我們首先從三個中取任意兩個布爾值,比如a
和b
。然後,我們檢查表達式a != b
的結果:
-
a != b
為true
b
a
真。所以,如果c
為真,那麼我們有兩個真。否則,我們在三個布爾值中有兩個 false。也就是說,c
的值就是答案。 -
a != b
為false
a
b
具有相同的值。由於我們只有三個布爾值,因此a
(或b
)值就是答案。
因此,我們可以得出解決方案: a != b ? c : a
。此外, a != b
檢查實際上是一個 XOR 操作。因此,解決方案可以很簡單:
public static boolean twoOrMoreAreTrueByXor(boolean a, boolean b, boolean c) {
return a ^ b ? c : a;
}
當我們使用TEST_CASES_AND_EXPECTED
映射測試方法時,測試將通過:
TEST_CASES_AND_EXPECTED.forEach((array, expected) ->
assertThat(ThreeBooleans.twoOrMoreAreTrueByXor(array[0], array[1], array[2])).isEqualTo(expected));
這個解決方案非常緊湊和棘手。但是,我們不能擴展它來解決一般問題。
8. 結論
在本文中,我們探索了幾種不同的方法來檢查三個給定布爾值中是否至少有兩個真。
此外,我們還討論了哪種方法可以輕鬆擴展以解決更一般的問題:檢查n 個布爾值中是否至少有x
個為真。
與往常一樣,完整的源代碼可在 GitHub 上獲得。