You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

235 lines
5.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_09_2_week;
// 来自学员问题
// 有一个数组包含0、1、2三种值
// 有m次修改机会第一种将所有连通的1变为0修改次数-1
// 第二种将所有连通的2变为1或0修改次数-2
// 返回m次修改机会的情况下让最大的0连通区最长能是多少
// 1 <= arr长度 <= 10^6
// 0 <= 修改机会 <= 10^6
public class Code04_RunThroughZero2 {
// 时间复杂度O(N^3)的方法
// 为了验证
public static int maxZero1(int[] arr, int k) {
int n = arr.length;
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = n - 1; j >= i; j--) {
if (cost1(arr, i, j) <= k) {
ans = Math.max(ans, j - i + 1);
break;
}
}
}
return ans;
}
// 为了验证
public static int cost1(int[] arr, int l, int r) {
int num0 = 0;
int num2 = 0;
int n = r - l + 1;
for (int i = l; i <= r; i++) {
num0 += arr[i] == 0 ? 1 : 0;
num2 += arr[i] == 2 ? 1 : 0;
}
if (num0 == n) {
return 0;
}
if (num2 == n) {
return 2;
}
int area2 = arr[l] == 2 ? 1 : 0;
for (int i = l; i < r; i++) {
if (arr[i] != 2 && arr[i + 1] == 2) {
area2++;
}
}
boolean has1 = false;
int areaHas1No0 = 0;
for (int i = l; i <= r; i++) {
if (arr[i] == 0) {
if (has1) {
areaHas1No0++;
}
has1 = false;
}
if (arr[i] == 1) {
has1 = true;
}
}
if (has1) {
areaHas1No0++;
}
return 2 * area2 + areaHas1No0;
}
// 正式方法
// 时间复杂度O(N)
public static int[] left10 = new int[1000001];
public static int[] left2x = new int[1000001];
public static int[] right10 = new int[1000001];
public static int[] right2x = new int[1000001];
public static int[] area2s = new int[1000001];
public static int[] area1s = new int[1000001];
public static int maxZero2(int[] arr, int k) {
int n = arr.length;
int last = -1;
for (int i = 0; i < n; i++) {
if (arr[i] == 0) {
last = i;
}
if (arr[i] == 1) {
left10[i] = last;
}
}
last = -1;
for (int i = 0; i < n; i++) {
if (arr[i] != 2) {
last = i;
}
if (arr[i] == 2) {
left2x[i] = last;
}
}
last = n;
for (int i = n - 1; i >= 0; i--) {
if (arr[i] == 0) {
last = i;
}
if (arr[i] == 1) {
right10[i] = last;
}
}
last = n;
for (int i = n - 1; i >= 0; i--) {
if (arr[i] != 2) {
last = i;
}
if (arr[i] == 2) {
right2x[i] = last;
}
}
int area2 = arr[0] == 2 ? 1 : 0;
for (int i = 0; i < n - 1; i++) {
if (arr[i] != 2) {
area2s[i] = area2;
if (arr[i + 1] == 2) {
area2++;
}
}
}
if (arr[n - 1] != 2) {
area2s[n - 1] = area2;
}
boolean has1 = false;
int area1 = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == 0) {
if (has1) {
area1++;
}
has1 = false;
area1s[i] = area1;
}
if (arr[i] == 1) {
has1 = true;
}
}
int ans = 0;
int right = 0;
for (int left = 0; left < n; left++) {
while (right < n && cost2(arr, left, right) <= k) {
right++;
}
ans = Math.max(ans, right - left);
right = Math.max(right, left + 1);
}
return ans;
}
public static int cost2(int[] arr, int left, int right) {
if (arr[left] == 2 && right2x[left] > right) {
return 2;
}
int area2 = arr[left] == 2 ? 1 : 0;
area2 += arr[right] == 2 ? 1 : 0;
left = arr[left] == 2 ? right2x[left] : left;
right = arr[right] == 2 ? left2x[right] : right;
area2 += area2s[right] - area2s[left];
int area1 = 0;
if (arr[left] == 0 && arr[right] == 0) {
area1 = area1s[right] - area1s[left];
} else if (arr[left] == 0) {
area1++;
right = left10[right];
area1 += area1s[right] - area1s[left];
} else if (arr[right] == 0) {
area1++;
left = right10[left];
area1 += area1s[right] - area1s[left];
} else {
if (right10[left] > right) {
area1++;
} else {
area1 += 2;
left = right10[left];
right = left10[right];
area1 += area1s[right] - area1s[left];
}
}
return 2 * area2 + area1;
}
// 为了测试
public static int[] randomArray(int n) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * 3);
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 100;
int K = 100;
int testTimes = 5000;
System.out.println("功能测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int k = (int) (Math.random() * K);
int[] arr = randomArray(n);
int ans1 = maxZero1(arr, k);
int ans2 = maxZero2(arr, k);
if (ans1 != ans2) {
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
System.out.println("k : " + k);
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("功能测试结束");
System.out.println("性能测试开始");
int n = 1000000;
int k = 1000000;
System.out.println("数组长度 : " + n);
System.out.println("修改次数 : " + k);
int[] arr = randomArray(n);
long start = System.currentTimeMillis();
maxZero2(arr, k);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + "毫秒");
System.out.println("性能测试结束");
}
}