modify code

master
algorithmzuo 3 years ago
parent fb1da4a0a3
commit 4d0768b8f7

@ -0,0 +1,189 @@
package class_2022_09_2_week;
import java.util.Arrays;
import java.util.Comparator;
import java.util.TreeSet;
// 来自百度
// 二狗买了一些小兵玩具,和大胖一起玩
// 一共有n个小兵这n个小兵拍成一列
// 第i个小兵战斗力为hi然后他们两个开始对小兵进行排列
// 一共进行m次操作二狗每次操作选择一个数k将前k个小兵战斗力从小到大排列
// 大胖每次操作选择一个数k将前k个小兵战斗力从大到小排列
// 问所有操作结束后,排列顺序什么样
// 给定一个长度为n的数组arr表示每个小兵的战斗力
// 给定一个长度为m的数组op,
// op[i] = { k , 0 }, 表示对前k个士兵执行从小到大的操作
// op[i] = { k , 1 }, 表示对前k个士兵执行从大到小的操作
// 返回数组ans表示最终的排列
// 1 <= n, m <= 2 * 10^5
// - 10^9 <= arr[i] <= + 10^9
public class Code01_SortGame {
// 暴力方法
// 为了验证
public static int[] game1(int[] arr, int[][] op) {
int n = arr.length;
Integer[] help = new Integer[n];
for (int i = 0; i < n; i++) {
help[i] = arr[i];
}
for (int[] o : op) {
if (o[1] == 0) {
Arrays.sort(help, 0, o[0], (a, b) -> a - b);
} else {
Arrays.sort(help, 0, o[0], (a, b) -> b - a);
}
}
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = help[i];
}
return ans;
}
// 正式方法
// 时间复杂度O(M) + O(N*logN)
public static int[] game2(int[] arr, int[][] op) {
int n = arr.length;
int m = op.length;
int[] stack = new int[m];
int r = 0;
for (int i = 0; i < m; i++) {
while (r != 0 && op[stack[r - 1]][0] <= op[i][0]) {
r--;
}
stack[r++] = i;
}
int[] ans = new int[n];
int ansi = n - 1;
int l = 0;
for (; ansi >= op[stack[l]][0]; ansi--) {
ans[ansi] = arr[ansi];
}
TreeSet<Number> sorted = new TreeSet<>(new NumberComparator());
for (int i = 0; i < op[stack[l]][0]; i++) {
sorted.add(new Number(arr[i], i));
}
while (l != r) {
// 当前处理的指令
int[] cur = op[stack[l++]];
if (l != r) {
int[] next = op[stack[l]];
int num = cur[0] - next[0];
if (cur[1] == 0) {
for (int i = 0; i < num; i++) {
ans[ansi--] = sorted.pollLast().value;
}
} else {
for (int i = 0; i < num; i++) {
ans[ansi--] = sorted.pollFirst().value;
}
}
} else {
if (cur[1] == 0) {
while (!sorted.isEmpty()) {
ans[ansi--] = sorted.pollLast().value;
}
} else {
while (!sorted.isEmpty()) {
ans[ansi--] = sorted.pollFirst().value;
}
}
}
}
return ans;
}
public static class Number {
public int value;
public int index;
public Number(int v, int i) {
value = v;
index = i;
}
}
public static class NumberComparator implements Comparator<Number> {
@Override
public int compare(Number o1, Number o2) {
if (o1.value != o2.value) {
return o1.value - o2.value;
} else {
return o1.index - o2.index;
}
}
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v) + 1;
}
return ans;
}
// 为了测试
public static int[][] randomOp(int m, int n) {
int[][] ans = new int[m][2];
for (int i = 0; i < m; i++) {
ans[i][0] = (int) (Math.random() * (n + 1));
ans[i][1] = Math.random() < 0.5 ? 0 : 1;
}
return ans;
}
// 为了测试
public static boolean isEqual(int[] arr1, int[] arr2) {
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
// 为了测试
public static void main(String[] args) {
// int[] arr = { 3, 3, 7, 7, 7 };
//
// TreeSet<Number> set = new TreeSet<>(new NumberComparator());
//
// for (int i = 0; i < arr.length; i++) {
// set.add(new Number(arr[i], i));
// }
//
//// System.out.println(set.size());
//
// while(!set.isEmpty()) {
// System.out.println(set.pollLast().value);
// }
int N = 100;
int M = 100;
int V = 200;
int testTimes = 5000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int m = (int) (Math.random() * M) + 1;
int[] arr = randomArray(n, V);
int[][] op = randomOp(m, n);
int[] ans1 = game1(arr, op);
int[] ans2 = game2(arr, op);
if (!isEqual(ans1, ans2)) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
}

@ -0,0 +1,148 @@
package class_2022_09_2_week;
// 来自微众银行
// 给定一个数字n代表数组的长度
// 给定一个数字m代表数组每个位置都可以在1~m之间选择数字
// 所有长度为n的数组中最长递增子序列长度为3的数组叫做达标数组
// 返回达标数组的数量
// 1 <= n <= 500
// 1 <= m <= 10
// 500 * 10 * 10 * 10
// 结果对998244353取模
// 实现的时候没有取模的逻辑,因为非重点
public class Code02_NLengthMValueLIS3 {
// 暴力方法
// 为了验证
public static int number1(int n, int m) {
return process1(0, n, m, new int[n]);
}
public static int process1(int i, int n, int m, int[] path) {
if (i == n) {
return lengthOfLIS(path) == 3 ? 1 : 0;
} else {
int ans = 0;
for (int cur = 1; cur <= m; cur++) {
path[i] = cur;
ans += process1(i + 1, n, m, path);
}
return ans;
}
}
public static int lengthOfLIS(int[] arr) {
if (arr == null || arr.length == 0) {
return 0;
}
int[] ends = new int[arr.length];
ends[0] = arr[0];
int right = 0;
int max = 1;
for (int i = 1; i < arr.length; i++) {
int l = 0;
int r = right;
while (l <= r) {
int m = (l + r) / 2;
if (arr[i] > ends[m]) {
l = m + 1;
} else {
r = m - 1;
}
}
right = Math.max(right, l);
ends[l] = arr[i];
max = Math.max(max, l + 1);
}
return max;
}
// i : 当前来到的下标
// f、s、t : ends数组中放置的数字
// ? == 0没放
// n : 一共的长度!
// m : 每一位都可以在1~m中随意选择数字
// 返回值i..... 有几个合法的数组!
public static int zuo(int i, int f, int s, int t, int n, int m) {
if (i == n) {
return f != 0 && s != 0 && t != 0 ? 1 : 0;
}
// i < n
int ans = 0;
for (int cur = 1; cur <= m; cur++) {
if (f == 0 || f >= cur) {
ans += zuo(i + 1, cur, s, t, n, m);
} else if (s == 0 || s >= cur) {
ans += zuo(i + 1, f, cur, t, n, m);
} else if (t == 0 || t >= cur) {
ans += zuo(i + 1, f, s, cur, n, m);
}
}
return ans;
}
// 正式方法
// 需要看最长递增子序列!
// 尤其是理解ends数组的意义
public static int number2(int n, int m) {
int[][][][] dp = new int[n][m + 1][m + 1][m + 1];
for (int i = 0; i < n; i++) {
for (int f = 0; f <= m; f++) {
for (int s = 0; s <= m; s++) {
for (int t = 0; t <= m; t++) {
dp[i][f][s][t] = -1;
}
}
}
}
return process2(0, 0, 0, 0, n, m, dp);
}
public static int process2(int i, int f, int s, int t, int n, int m, int[][][][] dp) {
if (i == n) {
return f != 0 && s != 0 && t != 0 ? 1 : 0;
}
if (dp[i][f][s][t] != -1) {
return dp[i][f][s][t];
}
int ans = 0;
for (int cur = 1; cur <= m; cur++) {
if (f == 0 || cur <= f) {
ans += process2(i + 1, cur, s, t, n, m, dp);
} else if (s == 0 || cur <= s) {
ans += process2(i + 1, f, cur, t, n, m, dp);
} else if (t == 0 || cur <= t) {
ans += process2(i + 1, f, s, cur, n, m, dp);
}
}
dp[i][f][s][t] = ans;
return ans;
}
public static void main(String[] args) {
System.out.println("功能测试开始");
for (int n = 4; n <= 8; n++) {
for (int m = 1; m <= 5; m++) {
int ans1 = number1(n, m);
int ans2 = number2(n, m);
if (ans1 != ans2) {
System.out.println(ans1);
System.out.println(ans2);
System.out.println("出错了!");
}
}
}
System.out.println("功能测试结束");
System.out.println("性能测试开始");
int n = 2000;
int m = 20;
System.out.println("序列长度 : " + n);
System.out.println("数字范围 : " + m);
long start = System.currentTimeMillis();
number2(n, m);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + " 毫秒");
System.out.println("性能测试结束");
}
}

@ -0,0 +1,94 @@
package class_2022_09_2_week;
import java.util.HashMap;
// 来自微软
// 给定一个字符串s其中都是英文小写字母
// 如果s中的子串含有的每种字符都是偶数个
// 那么这样的子串就是达标子串,子串要求是连续串
// 返回s中达标子串的最大长度
// 1 <= s的长度 <= 10^5
// 字符种类都是英文小写
public class Code03_EvenTimesMaxSubstring {
// 为了测试
// 暴力方法
public static int maxLen1(String s) {
int n = s.length();
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = n - 1; j >= i; j--) {
if (ok(s, i, j)) {
ans = Math.max(ans, j - i + 1);
break;
}
}
}
return ans;
}
// 为了测试
// 暴力方法
public static boolean ok(String s, int l, int r) {
if (((r - l + 1) & 1) == 1) {
return false;
}
int[] cnts = new int[26];
for (int i = l; i <= r; i++) {
cnts[s.charAt(i) - 'a']++;
}
for (int cnt : cnts) {
if ((cnt & 1) == 1) {
return false;
}
}
return true;
}
public static int maxLen2(String s) {
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
int status = 0;
int ans = 0;
int n = s.length();
for (int i = 0; i < n; i++) {
status ^= 1 << (s.charAt(i) - 'a');
if (map.containsKey(status)) {
ans = Math.max(ans, i - map.get(status));
} else {
map.put(status, i);
}
}
return ans;
}
// 为了测试
public static String randomString(int n, int v) {
char[] s = new char[n];
for (int i = 0; i < n; i++) {
s[i] = (char) ((int) (Math.random() * v) + 'a');
}
return String.valueOf(s);
}
// 为了测试
public static void main(String[] args) {
int n = 50;
int v = 6;
int testTimes = 2000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
String s = randomString(n, v);
int ans1 = maxLen1(s);
int ans2 = maxLen2(s);
if (ans1 != ans2) {
System.out.println(s);
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("测试结束");
}
}

@ -0,0 +1,127 @@
package class_2022_09_2_week;
// 来自学员问题
// 本文件仅为贪心的验证文件
// 有一个数组包含0、1、2三种值
// 有n次修改机会第一种将所有连通的1变为0修改次数-1
// 第二种将所有连通的2变为1或0修改次数-2
// 返回n次修改机会的情况下连通的0最长能是多少
// 1 <= arr长度 <=10^6
// 0 <= 修改机会 <=10^6
public class Code04_RunThroughZero1 {
public static int best1(int[] arr) {
int zero = 0;
int two = 0;
int n = arr.length;
for (int num : arr) {
zero += num == 0 ? 1 : 0;
two += num == 2 ? 1 : 0;
}
if (zero == n) {
return 0;
}
if (two == n) {
return 2;
}
int ans = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
if (arr[i] != 0 && (i == 0 || arr[i - 1] != arr[i])) {
if (arr[i] == 2) {
ans = Math.min(ans, 2 + Math.min(best1(change(arr, i, 1)), best1(change(arr, i, 0))));
} else {
ans = Math.min(ans, 1 + best1(change(arr, i, 0)));
}
}
}
return ans;
}
public static int[] change(int[] arr, int i, int to) {
int l = i;
int r = i;
while (l >= 0 && arr[l] == arr[i]) {
l--;
}
while (r < arr.length && arr[r] == arr[i]) {
r++;
}
int[] ans = new int[arr.length];
for (i = 0; i < arr.length; i++) {
ans[i] = arr[i];
}
for (i = l + 1; i < r; i++) {
ans[i] = to;
}
return ans;
}
public static int cost(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;
}
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 = 9;
int testTimes = 1000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int[] arr = randomArray(n);
int ans1 = best1(arr);
int ans2 = cost(arr, 0, arr.length - 1);
if (ans1 != ans2) {
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("测试结束");
}
}

@ -0,0 +1,234 @@
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("性能测试结束");
}
}

@ -1853,6 +1853,45 @@ graph[i] = {a,b,c,d} 表示i讨厌(a,b,c,d),讨厌关系为双向的
第040节 2022年9月第2周流行算法题目解析
来自百度
二狗买了一些小兵玩具,和大胖一起玩
一共有n个小兵这n个小兵拍成一列
第i个小兵战斗力为hi然后他们两个开始对小兵进行排列
一共进行m次操作二狗每次操作选择一个数k将前k个小兵战斗力从小到大排列
大胖每次操作选择一个数k将前k个小兵战斗力从大到小排列
问所有操作结束后,排列顺序什么样
给定一个长度为n的数组arr表示每个小兵的战斗力
给定一个长度为m的数组op,
op[i] = { k , 0 }, 表示对前k个士兵执行从小到大的操作
op[i] = { k , 1 }, 表示对前k个士兵执行从大到小的操作
返回数组ans表示最终的排列
1 <= n, m <= 2 * 10^5
- 10^9 <= arr[i] <= + 10^9
来自微众银行
给定一个数字n代表数组的长度
给定一个数字m代表数组每个位置都可以在1~m之间选择数字
所有长度为n的数组中最长递增子序列长度为3的数组叫做达标数组
返回达标数组的数量
1 <= n <= 500
1 <= m <= 10
来自微软
给定一个字符串s其中都是英文小写字母
如果s中的子串含有的每种字符都是偶数个
那么这样的子串就是达标子串,子串要求是连续串
返回s中达标子串的最大长度
1 <= s的长度 <= 10^5
字符种类都是英文小写
来自学员问题
有一个数组包含0、1、2三种值
有m次修改机会第一种将所有连通的1变为0修改次数-1
第二种将所有连通的2变为1或0修改次数-2
返回m次修改机会的情况下让最大的0连通区最长能是多少
1 <= arr长度 <= 10^6
0 <= 修改机会 <= 10^6

Loading…
Cancel
Save