紅綠正方形染色問題
紅綠正方形染色問題
作者:Grey
原文地址:
題目描述
有一些排成一行的正方形。每個正方形已經被染成紅色或者綠色。現在可以選擇任意一個正方形然後用這兩種顏色的任意一種進行染色,這個正方形的顏色將會被覆蓋。目標是在完成染色之後,每個紅色 R 都比每個綠色 G 距離最左側近。 返回最少需要塗染幾個正方形,示例: s = RGRGR,我們塗染之後變成 RRRGG 滿足要求了,塗染的個數為 2, 沒有比這個更好的塗染方案。
題目鏈接見:牛客:紅和綠
思路
要滿足染色後,每個紅色 R 都比每個綠色 G 距離最左側近,只有可能是下述三種情況:
-
R 都在左邊,G 都在右邊;
-
全 G;
-
全 R。
定義兩個數組
int[] leftG = new int[N];
leftG[i]
表示 i 位置的左邊包括 i 在內有幾個 G。
通過從右往左遍歷一次數組可以預處理得到leftG
數組。
int[] rightR = new int[N];
rightR[i]
表示 i 位置右邊包括 i 在內有幾個 R。
通過從左往右遍歷一次數組可以預處理得到rightR
數組
如果rightR[0] == N || leftG[N - 1] == N
,說明數組全為 R 或者全為 G,此時無需染色,直接返回 0。
如果是普遍情況,那就直接判斷每個位置為分割點,左側都變為 R,右側都變為 G,需要的最小染色次數是多少,即:leftG[i] + rightR[i] - 1
,之所以要減 1 是因為重複算了 i 位置的情況。
完整代碼見
import java.util.Scanner;
// R都在左邊,G都在右邊,或者全G,全R
public class Main {
// 兩個預處理數組
// TODO 空間方面可以優化
public static int minColors(String str) {
if (str == null || str.length() <= 1) {
return 0;
}
char[] strs = str.toCharArray();
int N = strs.length;
// leftG[i]表示左邊包括i在內有幾個G
int[] leftG = new int[N];
// rightR[i]表示右邊包括i在內有幾個R
int[] rightR = new int[N];
for (int i = 0; i < N; i++) {
if (strs[i] == 'G') {
if (i == 0) {
leftG[i]++;
} else {
leftG[i] = leftG[i - 1] + 1;
}
} else {
if (i != 0) {
leftG[i] = leftG[i - 1];
}
}
}
for (int i = N - 1; i >= 0; i--) {
if (strs[i] == 'R') {
if (i == N - 1) {
rightR[i]++;
} else {
rightR[i] = rightR[i + 1] + 1;
}
} else {
if (i != N - 1) {
rightR[i] = rightR[i + 1];
}
}
}
// 全R或者全G的情況
if (rightR[0] == N || leftG[N - 1] == N ) {
return 0;
}
int min = N;
for (int i = 0; i < N; i++) {
// 之所以要-1是因為重複算了i位置的處理情況
min = Math.min(leftG[i] + rightR[i] - 1, min);
}
return min;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String colors = in.nextLine();
System.out.println(minColors(colors));
in.close();
}
}
空間複雜度O(N)
,時間複雜度O(N)
。