modify code

master
algorithmzuo 1 year ago
parent c047c3caeb
commit ca5d66d6ef

@ -0,0 +1,83 @@
package class_2023_06_3_week;
import java.util.Arrays;
// 课前放松一下
// 做一个令人不开心的实验
// 一开始有100个人每个人都有100元
// 在每一轮都做如下的事情 :
// 每个人都必须拿出1元钱给除自己以外的其他人给谁完全随机
// 如果某个人在这一轮的钱数为0那么他可以不给但是可以接收
// 发生很多很多轮之后这100人的社会财富分布很均匀吗
public class Code01_UnhappyExperiment {
public static void main(String[] args) {
System.out.println("一个社会的基尼系数是一个在0~1之间的小数");
System.out.println("基尼系数为0代表所有人的财富完全一样");
System.out.println("基尼系数为1代表有1个人掌握了全社会的财富");
System.out.println("基尼系数越小,代表社会财富分布越均衡;越大则代表财富分布越不均衡");
System.out.println("在2022年世界各国的平均基尼系数为0.44");
System.out.println("目前普遍认为,当基尼系数到达 0.5 时");
System.out.println("就意味着社会贫富差距非常大,分布非常不均匀");
System.out.println("社会可能会因此陷入危机,比如大量的犯罪或者经历社会动荡");
System.out.println("测试开始");
int n = 100;
int t = 1000000;
System.out.println("人数 : " + n);
System.out.println("轮数 : " + t);
experiment(n, t);
System.out.println("测试结束");
}
// 完全按照说的来实验
public static void experiment(int n, int t) {
double[] wealth = new double[n];
boolean[] hasMoney = new boolean[n];
Arrays.fill(wealth, 100);
for (int i = 0; i < t; i++) {
Arrays.fill(hasMoney, false);
for (int j = 0; j < n; j++) {
if (wealth[j] > 0) {
hasMoney[j] = true;
}
}
for (int j = 0; j < n; j++) {
if (hasMoney[j]) {
int other = j;
do {
other = (int) (Math.random() * n);
} while (other == j);
wealth[j]--;
wealth[other]++;
}
}
}
Arrays.sort(wealth);
System.out.println("列出每个人的财富(贫穷到富有) : ");
for (int i = 0; i < n; i++) {
System.out.print((int) wealth[i] + " ");
if (i % 10 == 9) {
System.out.println();
}
}
System.out.println();
System.out.println("这个社会的基尼系数为 : " + calculateGini(wealth));
}
// 计算基尼系数
// 这个函数是正确的
public static double calculateGini(double[] wealth) {
Arrays.sort(wealth);
double sumOfAbsoluteDifferences = 0;
double sumOfWealth = 0;
int n = wealth.length;
for (int i = 0; i < n; i++) {
sumOfWealth += wealth[i];
for (int j = 0; j < n; j++) {
sumOfAbsoluteDifferences += Math.abs(wealth[i] - wealth[j]);
}
}
return sumOfAbsoluteDifferences / (2 * n * sumOfWealth);
}
}

@ -0,0 +1,75 @@
package class_2023_06_3_week;
// 来自字节
// 密码是一串长度为n的小写字母一则关于密码的线索纸条
// 首先将字母a到z编号为0到25编号
// 纸条上共有n个整数ai其中a1表示密码里第一个字母的编号
// 若i>1的话就表示第i个字母和第i-1个字母编号的差值
// 例如a2就代表密码中第1个字母和第2个字母编号的差值
// 若密码是acb那么纸条上的数字就是[5, 2, 1]
// a b c d e f
// 0 1 2 3 4 5
// 返回可能的密码的个数,由于结果可能很大,
// 输出对1000000007取模的结果
// 1 <= n <= 10^5
// 0 <= ai <= 25
public class Code02_PasswordWays {
// 暴力递归
public static int ways1(int[] arr) {
//
// 0 -> a
// 1 -> b
return process1(arr, 1, arr[0]);
}
// arr : 字条 i现在来到的位置
// pre : 前一个字符的编号
// f ?...
// 5
// 3
// 返回最终,有多少合法的字符串
// -1 >=26
// pre pre
public static int process1(int[] arr, int i, int pre) {
int ans = 0;
if (pre < 0 || pre > 25) {
ans = 0;
} else {
// pre 有效!
if (i == arr.length) {
// 之前的转化,一定走到尽头了
ans = 1;
} else {
// pre f 2
// f+2.....
// f-2.....
ans += process1(arr, i + 1, pre - arr[i]);
ans += process1(arr, i + 1, pre + arr[i]);
}
}
return ans;
}
// 动态规划
public static int ways2(int[] arr) {
int mod = 1000000007;
int n = arr.length;
int[][] dp = new int[n + 1][26];
for (int j = 0; j < 26; j++) {
dp[n][j] = 1;
}
for (int i = n - 1; i >= 1; i--) {
for (int j = 0; j < 26; j++) {
if (j - arr[i] >= 0) {
dp[i][j] = dp[i + 1][j - arr[i]];
}
if (j + arr[i] < 26) {
dp[i][j] = (dp[i][j] + dp[i + 1][j + arr[i]]) % mod;
}
}
}
return dp[1][arr[0]];
}
}

@ -0,0 +1,118 @@
package class_2023_06_3_week;
// 来自字节
// 给定整数数组arr求删除任一元素后
// 新数组中长度为k的子数组累加和的最大值
public class Code03_DeleteOneNumberLenKMaxSum {
// 暴力方法
// 为了测试
public static int maxSum1(int[] arr, int k) {
int n = arr.length;
if (n <= k) {
return 0;
}
int ans = Integer.MIN_VALUE;
for (int i = 0; i < n; i++) {
int[] rest = delete(arr, i);
ans = Math.max(ans, lenKmaxSum(rest, k));
}
return ans;
}
// 暴力方法
// 为了测试
public static int[] delete(int[] arr, int index) {
int len = arr.length - 1;
int[] ans = new int[len];
int i = 0;
for (int j = 0; j < arr.length; j++) {
if (j != index) {
ans[i++] = arr[j];
}
}
return ans;
}
// 暴力方法
// 为了测试
public static int lenKmaxSum(int[] arr, int k) {
int n = arr.length;
int ans = Integer.MIN_VALUE;
for (int i = 0; i <= n - k; i++) {
int cur = 0;
for (int j = i, cnt = 0; cnt < k; j++, cnt++) {
cur += arr[j];
}
ans = Math.max(ans, cur);
}
return ans;
}
// 正式方法
// 时间复杂度O(N)
public static int maxSum2(int[] arr, int k) {
int n = arr.length;
if (n <= k) {
return 0;
}
// 窗口内最小值的更新结构,双端队列!
// 看课体系学习班章节25
int[] window = new int[n];
int l = 0;
int r = 0;
// 维持窗口内的累加和
long sum = 0;
int ans = Integer.MIN_VALUE;
// k = 10
// 0,1,2,3,.....10 11 12 13
// 0... 10
// 1 ...11
// 2 ...12
// 3....13
for (int i = 0; i < n; i++) {
while (l < r && arr[window[r - 1]] >= arr[i]) {
r--;
}
window[r++] = i;
sum += arr[i];
if (i >= k) {
ans = Math.max(ans, (int) (sum - arr[window[l]]));
if (window[l] == i - k) {
l++;
}
sum -= arr[i - k];
}
}
return ans;
}
// 为了测试
// 生成长度为n值在[-v, +v]之间
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() * (2 * v + 1)) - v;
}
return ans;
}
public static void main(String[] args) {
int N = 100;
int V = 1000;
int testTimes = 10000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int[] arr = randomArray(n, V);
int k = (int) (Math.random() * N) + 1;
int ans1 = maxSum1(arr, k);
int ans2 = maxSum2(arr, k);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
}

@ -0,0 +1,187 @@
package class_2023_06_3_week;
import java.util.Arrays;
import java.util.HashMap;
// 来自字节
// 给定一个数组arr长度为n在其中要选两个不相交的子数组
// 两个子数组的累加和都要是T返回所有满足情况中两个子数组长度之和最小是多少
// 如果没有有效方法,返回-1
// 正式 :
// 2 <= n <= 10^6
// 0 <= arr[i] <= 10000
// 1 <= T <= 10^8
// 扩展 :
// 2 <= n <= 10^6
// -10000 <= arr[i] <= 10000
// 1 <= T <= 10^8
// 都能时间复杂度做到O(N)
public class Code04_TowSubArrayMinLengthBothSumT {
// 暴力方法
// 为了验证
// 假设数组中的值可以正、负、0(就是扩展数据范围也能正确的暴力方法)
public static int minLenBothT1(int[] arr, int t) {
int n = arr.length;
int[] sum = new int[n];
sum[0] = arr[0];
for (int i = 1; i < n; i++) {
sum[i] = sum[i - 1] + arr[i];
}
int ans = Integer.MAX_VALUE;
for (int a = 0; a < n - 1; a++) {
for (int b = a; b < n - 1; b++) {
for (int c = b + 1; c < n; c++) {
for (int d = c; d < n; d++) {
if (sum(sum, a, b) == t && sum(sum, c, d) == t) {
ans = Math.min(ans, b + d - a - c + 2);
}
}
}
}
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
// 暴力方法
// 为了验证
public static int sum(int[] sum, int l, int r) {
return l == 0 ? sum[r] : (sum[r] - sum[l - 1]);
}
// 正式方法
// 时间复杂度O(N)
// 数组都是非负数情况下的正确方法
public static int minLenBothT2(int[] arr, int t) {
int n = arr.length;
if (t < 0) {
return -1;
}
if (t == 0) {
int cnt = 0;
for (int num : arr) {
if (num == 0) {
cnt++;
}
}
return cnt >= 2 ? 2 : -1;
}
int[] right = new int[n];
Arrays.fill(right, Integer.MAX_VALUE);
for (int l = 1, r = 1, sum = 0; l < n; l++) {
r = Math.max(r, l);
while (r < n && sum < t) {
sum += arr[r++];
}
if (sum == t) {
right[l] = r - l;
}
sum -= arr[l];
}
for (int i = n - 2; i >= 0; i--) {
right[i] = Math.min(right[i], right[i + 1]);
}
int ans = Integer.MAX_VALUE;
for (int r = n - 2, l = n - 2, sum = 0; r >= 0; r--) {
l = Math.min(l, r);
while (l >= 0 && sum < t) {
sum += arr[l--];
}
if (sum == t && right[r + 1] != Integer.MAX_VALUE) {
ans = Math.min(ans, r - l + right[r + 1]);
}
sum -= arr[r];
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
// 扩展方法
// 时间复杂度O(N)
// 假设数组中的值可以正、负、0就是扩展数据范围也能正确的方法
public static int minLenBothT3(int[] arr, int t) {
int n = arr.length;
HashMap<Integer, Integer> sums = new HashMap<>();
sums.put(0, -1);
int[] left = new int[n];
Arrays.fill(left, Integer.MAX_VALUE);
for (int i = 0, sum = 0; i < n - 1; i++) {
sum += arr[i];
if (sums.containsKey(sum - t)) {
left[i] = i - sums.get(sum - t);
}
sums.put(sum, i);
}
for (int i = 1; i < n - 1; i++) {
left[i] = Math.min(left[i - 1], left[i]);
}
int ans = Integer.MAX_VALUE;
sums.clear();
sums.put(0, n);
for (int i = n - 1, sum = 0; i >= 1; i--) {
sum += arr[i];
if (sums.containsKey(sum - t) && left[i - 1] != Integer.MAX_VALUE) {
ans = Math.min(ans, left[i - 1] + sums.get(sum - t) - i);
}
sums.put(sum, i);
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
// 为了测试
// 随机数组长度为n
// 值在[0, v]之间随机
public static int[] randomArray1(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;
}
// 为了测试
// 随机数组长度为n
// 值在[-v,+v]之间随机
public static int[] randomArray2(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * (2 * v + 1)) - v;
}
return ans;
}
public static void main(String[] args) {
int N = 100;
int V = 100;
int T = 100;
int testTimes = 10000;
System.out.println("正式方法测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 2;
int v = (int) (Math.random() * V) + 1;
int[] arr = randomArray1(n, v);
int t = (int) (Math.random() * T);
int ans1 = minLenBothT1(arr, t);
int ans2 = minLenBothT2(arr, t);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
System.out.println("正式方法测试结束");
System.out.println("扩展方法测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 2;
int v = (int) (Math.random() * V) + 1;
int[] arr = randomArray2(n, v);
int t = (int) (Math.random() * T);
int ans1 = minLenBothT1(arr, t);
int ans3 = minLenBothT3(arr, t);
if (ans1 != ans3) {
System.out.println("出错了!");
}
}
System.out.println("扩展方法测试结束");
}
}

@ -0,0 +1,74 @@
package class_2023_06_3_week;
// 来自华为OD
// 一支n个士兵的军队正在趁夜色逃亡途中遇到一条湍急的大河
// 敌军在T的时长后到达河面没到过对岸的士兵都会被消灭
// 现在军队只找到了1只小船这船最多能同时坐上2个士兵。
// 1) 当1个士兵划船过河用时为a[i]
// 2) 当2个士兵坐船同时划船过河时, 用时为max(a[j],a[i])两士兵中用时最长的
// 3) 当2个士兵坐船只有1个士兵划船时, 用时为a[i] * 10, a[i]为划船士兵用时
// 请帮忙给出一种解决方案,保证存活的士兵最多,且过河用时最短
// 我们先看一下如下的题再讲一下华为OD的扩展
// 测试链接 : https://www.luogu.com.cn/problem/P1809
// 有一个大晴天, Oliver与同学们一共N人出游, 他们走到一条河的东岸边,想要过河到西岸
// 而东岸边有一条小船。船太小了一次只能乘坐两人每个人都有一个渡河时间T
// 船划到对岸的时间等于船上渡河时间较长的人所用时间
// 现在已知N个人的渡河时间Ti
// Oliver 想要你告诉他,他们最少要花费多少时间,才能使所有人都过河
// 注意,只有船在东岸(西岸)的人才能坐上船划到对岸。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;
public class Code05_CrossRiver {
public static int MAXN = 100001;
public static int[] arr = new int[MAXN];
public static int[] dp = new int[MAXN];
public static int n;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
n = (int) in.nval;
for (int i = 0; i < n; i++) {
in.nextToken();
arr[i] = (int) in.nval;
}
int ans = minCost();
out.println(ans);
out.flush();
}
}
public static int minCost() {
Arrays.sort(arr, 0, n);
if (n >= 1) {
dp[0] = arr[0];
}
if (n >= 2) {
dp[1] = arr[1];
}
if (n >= 3) {
dp[2] = arr[0] + arr[1] + arr[2];
}
for (int i = 3; i < n; i++) {
dp[i] = Math.min(
dp[i - 2] + arr[1] + arr[0] + arr[i] + arr[1],
dp[i - 1] + arr[i] + arr[0]);
}
return dp[n - 1];
}
}

@ -0,0 +1,273 @@
package class_2023_06_3_week;
import java.util.Arrays;
import java.util.ArrayList;
// 来自华为OD
// 1号店铺贿赂问题
// 店铺数量n编号1~n
// 人的数量m编号1~m
// 每个人有自己投票的店铺p和改投1号店的报价x
// 返回想让1号店铺成为人气最高的店至少花多少钱
// 1 <= p,n,m <= 3000
// 1 <= x <= 10^9
public class Code06_BecomeMostPopularShop {
// 暴力方法
// 为了测试
// n : 店铺数量
// m : 人的数量
// arr : 长度m每个人有支持的店铺以及改投1号店的钱数
// 如果有某个人已经支持了1号店铺那么钱数认为无意义
// 返回至少要花多少钱才能让1号店铺成为人气最高的点
public static long minCost1(int n, int m, int[][] arr) {
// 统计每个店铺的支持人数
int[] cnts = new int[n + 1];
for (int[] p : arr) {
cnts[p[0]]++;
}
boolean needChange = false;
for (int i = 2; i <= n; i++) {
if (cnts[i] >= cnts[1]) {
needChange = true;
break;
}
}
// 如果1号店铺已经是最大人气直接返回0
if (!needChange) {
return 0;
}
return process(arr, 0, n, new boolean[m]);
}
// 暴力方法
// 为了测试
// 暴力走两个分支:每个人要么改,要么不改
// 如果i号人改投那么change[i] = true;
// 如果i号人不改投那么change[i] = false;
// n : 店铺数量,固定参数
public static long process(int[][] arr, int i, int n, boolean[] change) {
if (i == arr.length) {
// 统计投票结果
int[] cnts = new int[n + 1];
long sum = 0;
for (int j = 0; j < arr.length; j++) {
if (change[j]) {
// 改投的店人气都给1号店
cnts[1]++;
// 并且统计改投的钱数
sum += arr[j][1];
} else {
// 没有改投的店,统计词频
cnts[arr[j][0]]++;
}
}
// 看看此时1号店是不是人气最高的
boolean ok = true;
for (int j = 2; j <= n; j++) {
if (cnts[j] >= cnts[1]) {
ok = false;
break;
}
}
if (!ok) {
// 如果1号店不是人气最高的
// 说明当前的方案无效
return Long.MAX_VALUE;
} else {
// 否则说明当前的方案有效
// 返回这种方案的改投钱数
return sum;
}
} else {
// 可能性1改投
long p1 = Long.MAX_VALUE;
if (arr[i][0] != 1) {
// 如果当前用户不支持1号店才存在改投的可能性
change[i] = true;
p1 = process(arr, i + 1, n, change);
change[i] = false;
}
// 可能性1不改投
long p2 = process(arr, i + 1, n, change);
return Math.min(p1, p2);
}
}
// n : 店铺的数量
// m : 人的数量
// arr : i [本来支持的店号, 如果改投1号店贿赂的钱]
public static long minCost2(int n, int m, int[][] arr) {
// 统计每个店铺的支持人数
// 1 ~ n
int[] cnts = new int[n + 1];
for (int[] p : arr) {
cnts[p[0]]++;
}
// needChange : 到底需不需要贿赂呢?
boolean needChange = false;
for (int i = 2; i <= n; i++) {
if (cnts[i] >= cnts[1]) {
needChange = true;
break;
}
}
// 如果1号店铺已经是最大人气直接返回0
if (!needChange) {
return 0;
}
// 1号店铺目前不是人气最高需要贿赂
// 把所有的人,根据改投的钱数排序
// 钱少的在前面
// 排序之后,人也重新编号了,因为每个人的下标变了
Arrays.sort(arr, (a, b) -> a[1] - b[1]);
// 每个店拥有哪些人做统计
// 比如5号店有13号人、16号人、23号人
// shops.get(5) = {13, 16, 23}
// 注意,这个编号是排序之后的编号
// 也就是说,如果经历了排序,然后此时分组
// 5号店有13号人、16号人、23号人
// 那么13号人的转投钱数 <= 16号人的 <= 23号人的
// shops.get(5) = {13, 16, 23}
// 每一个下标,都是排序之后的数组中,人的下标
ArrayList<ArrayList<Integer>> shops = new ArrayList<>();
for (int i = 0; i <= n; i++) {
shops.add(new ArrayList<>());
}
for (int i = 0; i < m; i++) {
shops.get(arr[i][0]).add(i);
}
// 某个用户是否已经改投1号店了
boolean[] used = new boolean[m];
// 最小的钱数
long ans = Long.MAX_VALUE;
// 1号店已经有50人支持了没赢
// 51 52 53 ...
for (int i = cnts[1] + 1; i <= m; i++) {
// 1号店铺只允许最终有i个人投它
// 返回赢的情况下,最少的钱数
// 如果规定好的人数,怎么都赢不了,返回-1
long money = f(arr, n, cnts[1], i, shops, used);
if (money != -1) {
ans = Math.min(ans, money);
}
}
return ans;
}
// arr : 所有人都在arr里并且根据钱数排好序了
// n : 一共有多少店
// already : 一号店已经有的人数
// must : 一号店最后一定要达到的人数,并且一定要以这个人数成为人气最高的店
// shops : 每个店铺里都有哪些支持者,固定的
// used : 某个人是否已经改投1号店了辅助数组
// 返回值 :
// 如果一号店人数最后一定要达到must并且一定可以成为人气最高的店那么返回至少花的钱数
// 如果上面说的做不到,返回-1
public static long f(
int[][] arr, int n,
int already, int must,
ArrayList<ArrayList<Integer>> shops,
boolean[] used) {
// 最开始时,任何人都没有转投
Arrays.fill(used, false);
// 总钱数
long sum = 0;
for (int i = 2; i <= n; i++) {
// 从2号店开始考察每个店铺
// 如果当前店铺人数>=must那么一定要减到must以下
// needChange : 当前的店有多少人需要转投
int needChange = Math.max(0, shops.get(i).size() - must + 1);
for (int j = 0; j < needChange; j++) {
// 因为arr中已经根据钱数排序
// 所以当前店铺拥有的支持者里
// 也一定是根据钱数从小到大排列的
// 这些人都给1号店铺
int people = shops.get(i).get(j);
sum += arr[people][1];
// 当前的人已经算用过了,改投过了
used[people] = true;
}
// 改投的人要归属给1号店铺
already += needChange;
if (already > must) {
// 如果超过了must
// 说明1号店铺就严格达到must的人数是做不到成为人气最高的店铺的
// 因为别的店的人数要降到must以下转移的人都会超过must
// 所以返回-1
return -1;
}
}
// 经过上面的过程
// 1号店已经接受一些人了
// 接受的人是:
// 别的店的人数要降到must以下所以转移过来的人
// 但是有可能1号店此时的人数already还是不够must个
// 那么要凑齐must个必须再选花钱少的人补齐
for (int i = 0, j = 0; already + j < must; i++) {
// 补齐的人员不能原本就属于1号店铺
// 也不能是上面的过程中,转移过来的,因为已经用掉了
// 所以两个条件都具备才能给1号店去补
if (arr[i][0] != 1 && !used[i]) {
sum += arr[i][1];
j++;
}
}
// 返回最终花的钱数
return sum;
}
// 为了测试
// 生成人数为len的数据
// 每个人支持的店铺在1~n之间随机
// 每个人改投的钱数在1~v之间随机
public static int[][] randomArray(int len, int n, int v) {
int[][] arr = new int[len][2];
for (int i = 0; i < len; i++) {
arr[i][0] = (int) (Math.random() * n) + 1;
arr[i][1] = (int) (Math.random() * v) + 1;
}
return arr;
}
// 为了测试
public static void main(String[] args) {
int N = 10;
int M = 16;
int V = 100;
int testTimes = 10000;
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(m, n, V);
long ans1 = minCost1(n, m, arr);
long ans2 = minCost2(n, m, arr);
if (ans1 != ans2) {
System.out.println("出错了!");
System.out.println("n : " + n);
System.out.println("m : " + m);
for (int[] p : arr) {
System.out.println(p[0] + " , " + p[1]);
}
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("测试结束");
// 这已经是题目给的最大数据量了
// 完全可以运行通过
int n = 3000;
int m = 3000;
int v = 1000000000;
int[][] arr = randomArray(n, m, v);
long start = System.currentTimeMillis();
minCost2(n, m, arr);
long end = System.currentTimeMillis();
System.out.println("最大数据量时的运行时间 : " + (end - start) + " 毫秒");
}
}

@ -3899,21 +3899,71 @@ nums[i] < nums[k] < nums[j] < nums[l] 。
第073节 2023年6月3周流行算法题目解析
课前放松一下
做一个令人不开心的实验
一开始有100个人每个人都有100元
在每一轮都做如下的事情 :
每个人都必须拿出1元钱给除自己以外的其他人给谁完全随机
如果某个人在这一轮的钱数为0那么他可以不给但是可以接收
发生很多很多轮之后这100人的社会财富分布很均匀吗
来自字节
密码是一串长度为n的小写字母一则关于密码的线索纸条
首先将字母a到z编号为0到25编号
纸条上共有n个整数ai其中a1表示密码里第一个字母的编号
若i>1的话就表示第i个字母和第i-1个字母编号的差值
例如a2就代表密码中第1个字母和第2个字母编号的差值
若密码是acb那么纸条上的数字就是[0, 2, 1]
返回可能的密码的个数,由于结果可能很大,
输出对1000000007取模的结果
1 <= n <= 10^5
0 <= ai <= 25
来自字节
给定整数数组arr求删除任一元素后
新数组中长度为k的子数组累加和的最大值
来自字节
给定一个数组arr长度为n在其中要选两个不相交的子数组
两个子数组的累加和都要是T返回所有满足情况中两个子数组长度之和最小是多少
如果没有有效方法,返回-1
正式 :
2 <= n <= 10^6
0 <= arr[i] <= 10000
1 <= T <= 10^8
扩展 :
2 <= n <= 10^6
-10000 <= arr[i] <= 10000
1 <= T <= 10^8
都能时间复杂度做到O(N)
来自华为OD
一支n个士兵的军队正在趁夜色逃亡途中遇到一条湍急的大河
敌军在T的时长后到达河面没到过对岸的士兵都会被消灭
现在军队只找到了1只小船这船最多能同时坐上2个士兵。
1) 当1个士兵划船过河用时为a[i]
2) 当2个士兵坐船同时划船过河时, 用时为max(a[j],a[i])两士兵中用时最长的
3) 当2个士兵坐船只有1个士兵划船时, 用时为a[i] * 10, a[i]为划船士兵用时
请帮忙给出一种解决方案,保证存活的士兵最多,且过河用时最短
我们先看一下如下的题再讲一下华为OD的扩展
测试链接 : https://www.luogu.com.cn/problem/P1809
有一个大晴天, Oliver与同学们一共N人出游, 他们走到一条河的东岸边,想要过河到西岸
而东岸边有一条小船。船太小了一次只能乘坐两人每个人都有一个渡河时间T
船划到对岸的时间等于船上渡河时间较长的人所用时间
现在已知N个人的渡河时间Ti
Oliver 想要你告诉他,他们最少要花费多少时间,才能使所有人都过河
注意,只有船在东岸(西岸)的人才能坐上船划到对岸。
来自华为OD
1号店铺贿赂问题
店铺数量n编号1~n
人的数量m编号1~m
每个人有自己投票的店铺p和改投1号店的报价x
返回想让1号店铺成为人气最高的店至少花多少钱
1 <= p,n,m <= 3000
1 <= x <= 10^9

Loading…
Cancel
Save