From 7795d15cc01d5cb990e7b10e2ed2cc3d413b19d8 Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Fri, 28 Oct 2022 12:23:54 +0800 Subject: [PATCH] modify code --- .../Code01_MaxPrimePairs.java | 137 +++++++++++++ ...railingZerosTurnLeftOfRightAtMostOnce.java | 80 ++++++++ .../Code03_MinimumCostToCutAStick.java | 68 +++++++ .../Code04_NumberOfIncreasingRoadsThree.java | 183 ++++++++++++++++++ ...CountDifferentPalindromicSubsequences.java | 56 ++++++ .../Code06_StoreManager.java | 76 ++++++++ ...de07_RemoveMostKContinuousSameLongest.java | 105 ++++++++++ ...养的大厂算法面试题(正在直播) | 100 ++++++++++ 8 files changed, 805 insertions(+) create mode 100644 算法周更班/class_2022_10_4_week/Code01_MaxPrimePairs.java create mode 100644 算法周更班/class_2022_10_4_week/Code02_MostTrailingZerosTurnLeftOfRightAtMostOnce.java create mode 100644 算法周更班/class_2022_10_4_week/Code03_MinimumCostToCutAStick.java create mode 100644 算法周更班/class_2022_10_4_week/Code04_NumberOfIncreasingRoadsThree.java create mode 100644 算法周更班/class_2022_10_4_week/Code05_CountDifferentPalindromicSubsequences.java create mode 100644 算法周更班/class_2022_10_4_week/Code06_StoreManager.java create mode 100644 算法周更班/class_2022_10_4_week/Code07_RemoveMostKContinuousSameLongest.java diff --git a/算法周更班/class_2022_10_4_week/Code01_MaxPrimePairs.java b/算法周更班/class_2022_10_4_week/Code01_MaxPrimePairs.java new file mode 100644 index 0000000..b8f701c --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code01_MaxPrimePairs.java @@ -0,0 +1,137 @@ +package class_2022_10_4_week; + +// 来自华为 +// 若两个正整数的和为素数,则这两个正整数称之为"素数伴侣" +// 给定N(偶数)个正整数中挑选出若干对,组成"素数伴侣" +// 例如有4个正整数:2,5,6,13, +// 如果将5和6分为一组的话,只能得到一组"素数伴侣" +// 如果将2和5、6和13编组,将得到两组"素数伴侣" +// 这是得到"素数伴侣"最多的划分方案 +// 输入: +// 有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。 +// 输出: +// 输出一个整数 K ,表示最多能找出几对"素数伴侣" +// 数据范围: 1 <= n <= 100, 2 <= val <= 30000 +// 测试链接 : https://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e +// 请同学们务必参考如下代码中关于输入、输出的处理 +// 这是输入输出处理效率很高的写法 +// 提交以下的code,提交时请把类名改成"Main",可以直接通过 +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StreamTokenizer; +import java.util.Arrays; +import java.io.IOException; + +public class Code01_MaxPrimePairs { + + 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) { + int n = (int) in.nval; + int[] arr = new int[n]; + for (int i = 0; i < n; i++) { + in.nextToken(); + arr[i] = (int) in.nval; + } + int[][] graph = matrix(arr, n); + out.println(km(graph) / 2); + out.flush(); + } + + } + + public static int[][] matrix(int[] arr, int n) { + int[][] ans = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + ans[i][j] = isPrime(arr[i] + arr[j]) ? 1 : 0; + } + } + return ans; + } + + public static boolean isPrime(int num) { + int sqrt = (int) Math.sqrt(num); + for (int i = 2; i <= sqrt; i++) { + if (num % i == 0) { + return false; + } + } + return true; + } + + public static int km(int[][] graph) { + int N = graph.length; + int[] match = new int[N]; + int[] lx = new int[N]; + int[] ly = new int[N]; + boolean[] x = new boolean[N]; + boolean[] y = new boolean[N]; + int[] slack = new int[N]; + int invalid = Integer.MAX_VALUE; + for (int i = 0; i < N; i++) { + match[i] = -1; + lx[i] = -invalid; + for (int j = 0; j < N; j++) { + lx[i] = Math.max(lx[i], graph[i][j]); + } + ly[i] = 0; + } + for (int from = 0; from < N; from++) { + for (int i = 0; i < N; i++) { + slack[i] = invalid; + } + Arrays.fill(x, false); + Arrays.fill(y, false); + while (!dfs(from, x, y, lx, ly, match, slack, graph)) { + int d = invalid; + for (int i = 0; i < N; i++) { + if (!y[i] && slack[i] < d) { + d = slack[i]; + } + } + for (int i = 0; i < N; i++) { + if (x[i]) { + lx[i] = lx[i] - d; + } + if (y[i]) { + ly[i] = ly[i] + d; + } + } + Arrays.fill(x, false); + Arrays.fill(y, false); + } + } + int ans = 0; + for (int i = 0; i < N; i++) { + ans += (lx[i] + ly[i]); + } + return ans; + } + + public static boolean dfs(int from, boolean[] x, boolean[] y, int[] lx, int[] ly, int[] match, int[] slack, + int[][] map) { + int N = map.length; + x[from] = true; + for (int to = 0; to < N; to++) { + if (!y[to]) { + int d = lx[from] + ly[to] - map[from][to]; + if (d != 0) { + slack[to] = Math.min(slack[to], d); + } else { + y[to] = true; + if (match[to] == -1 || dfs(match[to], x, y, lx, ly, match, slack, map)) { + match[to] = from; + return true; + } + } + } + } + return false; + } + +} diff --git a/算法周更班/class_2022_10_4_week/Code02_MostTrailingZerosTurnLeftOfRightAtMostOnce.java b/算法周更班/class_2022_10_4_week/Code02_MostTrailingZerosTurnLeftOfRightAtMostOnce.java new file mode 100644 index 0000000..9f73b46 --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code02_MostTrailingZerosTurnLeftOfRightAtMostOnce.java @@ -0,0 +1,80 @@ +package class_2022_10_4_week; + +// 来自学员问题 +// 给定一个二维数组matrix +// 每个格子都是正数,每个格子都和上、下、左、右相邻 +// 你可以从任何一个格子出发,走向相邻的格子 +// 把沿途的数字乘起来,希望得到的最终数字中,结尾的0最多 +// 走的过程中,向左走或者向右走的拐点,最多只能有一次 +// 返回结尾最多的0,能是多少 +// 1 <= 行、列 <= 400 +public class Code02_MostTrailingZerosTurnLeftOfRightAtMostOnce { + + public static int mostTrailingZeros(int[][] matrix) { + int n = matrix.length; + int m = matrix[0].length; + // f2[i][j] : matrix[i][j]自己有几个2的因子 + int[][] f2 = new int[n][m]; + // f5[i][j] : matrix[i][j]自己有几个5的因子 + int[][] f5 = new int[n][m]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + f2[i][j] = factors(matrix[i][j], 2); + f5[i][j] = factors(matrix[i][j], 5); + } + } + int[][] leftF2 = new int[n][m]; + int[][] leftF5 = new int[n][m]; + int[][] upF2 = new int[n][m]; + int[][] upF5 = new int[n][m]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + leftF2[i][j] = f2[i][j] + (j > 0 ? leftF2[i][j - 1] : 0); + leftF5[i][j] = f5[i][j] + (j > 0 ? leftF5[i][j - 1] : 0); + upF2[i][j] = f2[i][j] + (i > 0 ? upF2[i - 1][j] : 0); + upF5[i][j] = f5[i][j] + (i > 0 ? upF5[i - 1][j] : 0); + } + } + int ans = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + // 来到(i,j) + int l2 = j == 0 ? 0 : leftF2[i][j - 1]; + int l5 = j == 0 ? 0 : leftF5[i][j - 1]; + int r2 = leftF2[i][m - 1] - leftF2[i][j]; + int r5 = leftF5[i][m - 1] - leftF5[i][j]; + int u2 = i == 0 ? 0 : upF2[i - 1][j]; + int u5 = i == 0 ? 0 : upF5[i - 1][j]; + int d2 = upF2[n - 1][j] - upF2[i][j]; + int d5 = upF5[n - 1][j] - upF5[i][j]; + int p1 = Math.min(l2 + u2 + f2[i][j], l5 + u5 + f5[i][j]); + int p2 = Math.min(l2 + r2 + f2[i][j], l5 + r5 + f5[i][j]); + int p3 = Math.min(l2 + d2 + f2[i][j], l5 + d5 + f5[i][j]); + int p4 = Math.min(u2 + r2 + f2[i][j], u5 + r5 + f5[i][j]); + int p5 = Math.min(u2 + d2 + f2[i][j], u5 + d5 + f5[i][j]); + int p6 = Math.min(r2 + d2 + f2[i][j], r5 + d5 + f5[i][j]); + ans = Math.max(ans, Math.max(Math.max(p1, p2), Math.max(Math.max(p3, p4), Math.max(p5, p6)))); + } + } + return ans; + } + + public static int factors(int num, int f) { + int ans = 0; + while (num % f == 0) { + ans++; + num /= f; + } + return ans; + } + + public static void main(String[] args) { + int[][] matrix1 = { { 5, 8, 3, 1 }, { 4, 15, 12, 1 }, { 6, 7, 10, 1 }, { 9, 1, 2, 1 } }; + System.out.println(mostTrailingZeros(matrix1)); + + int[][] matrix2 = { { 7500, 10, 11, 12 }, { 6250, 13, 14, 15 }, { 134, 17, 16, 1 }, { 5500, 2093, 5120, 238 } }; + System.out.println(mostTrailingZeros(matrix2)); + + } + +} diff --git a/算法周更班/class_2022_10_4_week/Code03_MinimumCostToCutAStick.java b/算法周更班/class_2022_10_4_week/Code03_MinimumCostToCutAStick.java new file mode 100644 index 0000000..2ea9ca0 --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code03_MinimumCostToCutAStick.java @@ -0,0 +1,68 @@ +package class_2022_10_4_week; + +import java.util.Arrays; + +// 有一根长度为 n 个单位的木棍,棍上从 0 到 n 标记了若干位置 +// 给你一个整数数组 cuts ,其中 cuts[i] 表示你需要将棍子切开的位置 +// 你可以按顺序完成切割,也可以根据需要更改切割的顺序 +// 每次切割的成本都是当前要切割的棍子的长度,切棍子的总成本是历次切割成本的总和 +// 对棍子进行切割将会把一根木棍分成两根较小的木棍 +// 这两根木棍的长度和就是切割前木棍的长度 +// 返回切棍子的最小总成本 +// 测试链接 : https://leetcode.cn/problems/minimum-cost-to-cut-a-stick/ +public class Code03_MinimumCostToCutAStick { + +// public static int zuo(int[] cuts, int n) { +// return f(cuts, 0, cuts.length - 1); +// } +// +// // cuts : 3 9 13 19 21 +// // 0 1 2 3 4 +// // 0,1 3,4 +// // cuts[l....r] +// // 0...4 都切完!最小花费是多少 +// // 1) 第一刀切在cuts[0] 3 +// // 2) 第一刀切在cuts[1] 9 +// // 3) 第一刀切在cuts[2] 9 +// public static int f(int[] cuts, int l, int r) { +// +// } + + public static int minCost(int n, int[] cuts) { + int m = cuts.length; + Arrays.sort(cuts); + int[] arr = new int[m + 2]; + arr[0] = 0; + for (int i = 1; i <= m; ++i) { + arr[i] = cuts[i - 1]; + } + arr[m + 1] = n; + int[][] dp = new int[m + 2][m + 2]; + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= m; j++) { + dp[i][j] = -1; + } + } + return process(arr, 1, m, dp); + } + + public static int process(int[] arr, int l, int r, int[][] dp) { + if (l > r) { + return 0; + } + if (l == r) { + return arr[r + 1] - arr[l - 1]; + } + if (dp[l][r] != -1) { + return dp[l][r]; + } + int ans = Integer.MAX_VALUE; + for (int k = l; k <= r; k++) { + // 左 | 右 + ans = Math.min(ans, process(arr, l, k - 1, dp) + process(arr, k + 1, r, dp)); + } + ans += arr[r + 1] - arr[l - 1]; + dp[l][r] = ans; + return ans; + } +} diff --git a/算法周更班/class_2022_10_4_week/Code04_NumberOfIncreasingRoadsThree.java b/算法周更班/class_2022_10_4_week/Code04_NumberOfIncreasingRoadsThree.java new file mode 100644 index 0000000..d661cc7 --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code04_NumberOfIncreasingRoadsThree.java @@ -0,0 +1,183 @@ +package class_2022_10_4_week; + +import java.util.Arrays; + +// 来自拼多多 +// 第一行有一个正整数n(3<=n<=100000),代表小A拟定的路线数量 +// 第二行有n个正整数,第i个代表第i条路线的起始日期 +// 第三行有n个正整数,第i个代表第i条路线的终止日期 +// 输入保证起始日期小于终止日期 +// 日期最小是1,最大不超过1000000000 +// 小A打算选三个路线进行旅游,比如 A -> B -> C +// 要求A的结束日期要小于B的开始日期,B的结束日期要小于C的开始日期 +// 输出一个非负整数,代表线路的方案数量 +// 例子 +// 输入 +// 6 +// 4 1 3 2 1 2 +// 4 1 3 3 2 2 +// 输出 +// 6 +// 解释 +// [1,1] -> [2,2] -> [3,3] +// [1,1] -> [2,2] -> [4,4] +// [1,1] -> [2,3] -> [4,4] +// [1,2] -> [3,3] -> [4,4] +// [1,1] -> [3,3] -> [4,4] +// [2,2] -> [3,3] -> [4,4] +public class Code04_NumberOfIncreasingRoadsThree { + + // 暴力方法 + // 为了验证 + public static int num1(int[][] roads) { + int n = roads.length; + int max = 0; + for (int i = 0; i < n; i++) { + max = Math.max(max, roads[i][1]); + } + Arrays.sort(roads, (a, b) -> a[0] - b[0]); + int[][][] dp = new int[n][4][max + 1]; + for (int a = 0; a < n; a++) { + for (int b = 0; b < 4; b++) { + for (int c = 0; c <= max; c++) { + dp[a][b][c] = -1; + } + } + } + return process1(roads, 0, 3, 0, dp); + } + + public static int process1(int[][] roads, int i, int rest, int end, int[][][] dp) { + if (rest == 0) { + return 1; + } + if (i == roads.length) { + return 0; + } + if (dp[i][rest][end] != -1) { + return dp[i][rest][end]; + } + int p1 = process1(roads, i + 1, rest, end, dp); + int p2 = roads[i][0] > end ? process1(roads, i + 1, rest - 1, roads[i][1], dp) : 0; + int ans = p1 + p2; + dp[i][rest][end] = ans; + return ans; + } + + public static int num2(int[][] roads) { + int n = roads.length; + int[] sorted = new int[n << 1]; + for (int i = 0; i < n; i++) { + sorted[i << 1] = roads[i][0]; + sorted[i << 1 | 1] = roads[i][1]; + } + Arrays.sort(roads, (a, b) -> a[0] - b[0]); + Arrays.sort(sorted); + IndexTree it1 = new IndexTree(n << 1); + IndexTree it2 = new IndexTree(n << 1); + IndexTree it3 = new IndexTree(n << 1); + for (int[] road : roads) { + int l = rank(sorted, road[0]); + int r = rank(sorted, road[1]); + it1.add(r, 1); + it2.add(r, it1.sum(l - 1)); + it3.add(r, it2.sum(l - 1)); + } + return it3.sum(n << 1); + } + + public static int rank(int[] sorted, int num) { + int l = 0; + int r = sorted.length - 1; + int m = 0; + int ans = 0; + while (l <= r) { + m = (l + r) / 2; + if (sorted[m] >= num) { + ans = m; + r = m - 1; + } else { + l = m + 1; + } + } + return ans + 1; + } + + // 下标从1开始! + public static class IndexTree { + + private int[] tree; + + private int N; + + public IndexTree(int size) { + N = size; + tree = new int[N + 1]; + } + + public int sum(int index) { + int ret = 0; + while (index > 0) { + ret += tree[index]; + index -= index & -index; + } + return ret; + } + + public void add(int index, int d) { + while (index <= N) { + tree[index] += d; + index += index & -index; + } + } + } + + // 为了测试 + public static int[][] randomRoads(int n, int v) { + int[][] roads = new int[n][2]; + for (int i = 0; i < n; i++) { + int a = (int) (Math.random() * v) + 1; + int b = (int) (Math.random() * v) + 1; + int start = Math.min(a, b); + int end = Math.max(a, b); + if (start == end) { + end++; + } + roads[i][0] = start; + roads[i][1] = end; + } + return roads; + } + + public static void main(String[] args) { + int N = 50; + int V = 50; + int testTime = 5000; + System.out.println("功能测试开始"); + for (int i = 0; i < testTime; i++) { + int n = (int) (Math.random() * N) + 1; + int[][] roads = randomRoads(n, V); + int ans1 = num1(roads); + int ans2 = num2(roads); + if (ans1 != ans2) { + System.out.println("出错了!"); + break; + } + } + System.out.println("功能测试结束"); + + System.out.println("性能测试开始"); + int n = 100000; + int v = 1000000000; + int[][] roads = randomRoads(n, v); + System.out.println("数组长度 : " + n); + System.out.println("数值范围 : " + v); + long start = System.currentTimeMillis(); + num2(roads); + long end = System.currentTimeMillis(); + System.out.println("运行时间 : " + (end - start) + " 毫秒"); + System.out.println("性能测试结束"); + + } + +} diff --git a/算法周更班/class_2022_10_4_week/Code05_CountDifferentPalindromicSubsequences.java b/算法周更班/class_2022_10_4_week/Code05_CountDifferentPalindromicSubsequences.java new file mode 100644 index 0000000..3bcb617 --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code05_CountDifferentPalindromicSubsequences.java @@ -0,0 +1,56 @@ +package class_2022_10_4_week; + +import java.util.HashMap; + +// 给定一个字符串 s,返回 s 中不同的非空 回文子序列 个数 +// 通过从 s 中删除 0 个或多个字符来获得子序列 +// 如果一个字符序列与它反转后的字符序列一致,那么它是 回文字符序列 +// 如果有某个 i , 满足 ai != bi ,则两个序列 a1, a2, ... 和 b1, b2, ... 不同 +// 注意:结果可能很大,你需要对 10^9 + 7 取模 +// 测试链接 : https://leetcode.cn/problems/count-different-palindromic-subsequences/ +public class Code05_CountDifferentPalindromicSubsequences { + + // 支持任意字符集 + // 时间复杂度O(N^2) + public static int countPalindromicSubsequences(String str) { + int mod = 1000000007; + char[] s = str.toCharArray(); + int n = s.length; + int[] right = new int[n]; + int[] left = new int[n]; + HashMap last = new HashMap<>(); + for (int i = 0; i < n; i++) { + left[i] = last.getOrDefault(s[i], -1); + last.put(s[i], i); + } + last.clear(); + for (int i = n - 1; i >= 0; i--) { + right[i] = last.getOrDefault(s[i], n); + last.put(s[i], i); + } + long[][] dp = new long[n][n]; + for (int i = 0; i < n; i++) { + dp[i][i] = 1; + } + for (int i = n - 2; i >= 0; i--) { + for (int j = i + 1; j < n; j++) { + if (s[i] == s[j]) { + int l = Math.min(j, right[i]); + int r = Math.max(i, left[j]); + if (l > r) { // 内部不再有l和r位置的字符了! + dp[i][j] = dp[i + 1][j - 1] * 2 + 2; + } else if (l == r) { // 内部仅有一个! + dp[i][j] = dp[i + 1][j - 1] * 2 + 1; + } else { // 内部有>=2个 + dp[i][j] = dp[i + 1][j - 1] * 2 - dp[l + 1][r - 1] + mod; + } + } else { + dp[i][j] = dp[i][j - 1] + dp[i + 1][j] - dp[i + 1][j - 1] + mod; + } + dp[i][j] %= mod; + } + } + return (int) dp[0][n - 1]; + } + +} diff --git a/算法周更班/class_2022_10_4_week/Code06_StoreManager.java b/算法周更班/class_2022_10_4_week/Code06_StoreManager.java new file mode 100644 index 0000000..2a903cd --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code06_StoreManager.java @@ -0,0 +1,76 @@ +package class_2022_10_4_week; + +import java.util.HashMap; +import java.util.PriorityQueue; + +// 来自学员问题 +// 设计一个仓库管理器,提供如下的方法: +// 1) void supply(String item, int num, int price) +// 名字叫item的商品,个数num,价格price +// 2) int sell(String item, int num) +// 卖出叫item的商品,个数num个,价格从低到高,返回卖出总价 +// 如果商品很多,每种商品的数量可能很多,该怎么设计这个结构 +public class Code06_StoreManager { + + public static class StoreManager { + private HashMap map; + + public StoreManager() { + map = new HashMap<>(); + } + + public void supply(String item, int num, int price) { + if (!map.containsKey(item)) { + map.put(item, new Store()); + } + map.get(item).add(num, price); + } + + public int sell(String item, int num) { + return map.get(item).remove(num); + } + + } + + public static class Store { + // 每一个价格,对应的数量 + HashMap priceNums; + // 价格组成的小根堆 + PriorityQueue heap; + + public Store() { + priceNums = new HashMap<>(); + heap = new PriorityQueue<>(); + } + + public void add(int num, int price) { + if (priceNums.containsKey(price)) { + priceNums.put(price, priceNums.get(price) + num); + } else { + priceNums.put(price, num); + heap.add(price); + } + } + + public int remove(int num) { + int money = 0; + while (!heap.isEmpty() && num != 0) { + int price = heap.poll(); + int stores = priceNums.get(price); + if (num >= stores) { + money += price * stores; + priceNums.remove(price); + num -= stores; + } else { // num < stores + money += price * num; + heap.add(price); + priceNums.put(price, stores - num); + break; + } + } + return money; + } + + } + +} diff --git a/算法周更班/class_2022_10_4_week/Code07_RemoveMostKContinuousSameLongest.java b/算法周更班/class_2022_10_4_week/Code07_RemoveMostKContinuousSameLongest.java new file mode 100644 index 0000000..13fd5c9 --- /dev/null +++ b/算法周更班/class_2022_10_4_week/Code07_RemoveMostKContinuousSameLongest.java @@ -0,0 +1,105 @@ +package class_2022_10_4_week; + +import java.util.HashMap; +import java.util.LinkedList; + +// 来自亚马逊 +// 给定一个数组arr,和一个正数k +// 你可以随意删除arr中的数字,最多删除k个 +// 目的是让连续出现一种数字的长度尽量长 +// 返回这个尽量长的长度 +// 比如数组arr = { 3, -2, 3, 3, 5, 6, 3, -2 }, k = 3 +// 你可以删掉-2、5、6(最多3个),这样数组arr = { 3, 3, 3, 3, -2 } +// 可以看到连续出现3的长度为4 +// 这是所有删除方法里的最长结果,所以返回4 +// 1 <= arr长度 <= 3 * 10^5 +// -10^9 <= arr中的数值 <= 10^9 +// 0 <= k <= 3 * 10^5 +public class Code07_RemoveMostKContinuousSameLongest { + + // 暴力方法 + // 为了测试 + public static int longest1(int[] arr, int k) { + return process1(arr, 0, new int[arr.length], 0, k); + } + + public static int process1(int[] arr, int i, int[] path, int size, int k) { + if (k < 0) { + return 0; + } + if (i == arr.length) { + if (size == 0) { + return 0; + } + int ans = 0; + int cnt = 1; + for (int j = 1; j < size; j++) { + if (path[j - 1] != path[j]) { + ans = Math.max(ans, cnt); + cnt = 1; + } else { + cnt++; + } + } + ans = Math.max(ans, cnt); + return ans; + } else { + path[size] = arr[i]; + int p1 = process1(arr, i + 1, path, size + 1, k); + int p2 = process1(arr, i + 1, path, size, k - 1); + return Math.max(p1, p2); + } + } + + // 正式方法 + // 时间复杂度O(N) + public static int longest2(int[] arr, int k) { + HashMap> valueIndies = new HashMap<>(); + int ans = 1; + for (int i = 0; i < arr.length; i++) { + int value = arr[i]; + if (!valueIndies.containsKey(value)) { + valueIndies.put(value, new LinkedList<>()); + } + LinkedList indies = valueIndies.get(value); + while (!indies.isEmpty() && i - indies.peekFirst() - indies.size() > k) { + indies.pollFirst(); + } + indies.addLast(i); + ans = Math.max(ans, indies.size()); + } + 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 = 20; + int V = 10; + int K = 5; + int testTime = 5000; + System.out.println("测试开始"); + for (int i = 0; i < testTime; i++) { + int n = (int) (Math.random() * N) + 1; + int[] arr = randomArray(n, V); + int k = (int) (Math.random() * K); + int ans1 = longest1(arr, k); + int ans2 = longest2(arr, k); + if (ans1 != ans2) { + System.out.println("出错了!"); + } + } + System.out.println("测试结束"); + } + +} diff --git a/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) b/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) index 11e37a0..2c9646d 100644 --- a/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) +++ b/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) @@ -2238,6 +2238,106 @@ n <= 3 * 10^5 +第046节 2022年10月第3周流行算法题目解析 + +来自华为 +若两个正整数的和为素数,则这两个正整数称之为"素数伴侣" +给定N(偶数)个正整数中挑选出若干对,组成"素数伴侣" +例如有4个正整数:2,5,6,13, +如果将5和6分为一组的话,只能得到一组"素数伴侣" +如果将2和5、6和13编组,将得到两组"素数伴侣" +这是得到"素数伴侣"最多的划分方案 +输入: +有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。 +输出: +输出一个整数 K ,表示最多能找出几对"素数伴侣" +数据范围: 1 <= n <= 100, 2 <= val <= 30000 +测试链接 : https://www.nowcoder.com/practice/b9eae162e02f4f928eac37d7699b352e + +来自学员问题 +给定一个二维数组matrix +每个格子都是正数,每个格子都和上、下、左、右相邻 +你可以从任何一个格子出发,走向相邻的格子 +把沿途的数字乘起来,希望得到的最终数字中,结尾的0最多 +走的过程中,向左走或者向右走的拐点,最多只能有一次 +返回结尾最多的0,能是多少 +1 <= 行、列 <= 400 + +有一根长度为 n 个单位的木棍,棍上从 0 到 n 标记了若干位置 +给你一个整数数组 cuts ,其中 cuts[i] 表示你需要将棍子切开的位置 +你可以按顺序完成切割,也可以根据需要更改切割的顺序 +每次切割的成本都是当前要切割的棍子的长度,切棍子的总成本是历次切割成本的总和 +对棍子进行切割将会把一根木棍分成两根较小的木棍 +这两根木棍的长度和就是切割前木棍的长度 +返回切棍子的最小总成本 +测试链接 : https://leetcode.cn/problems/minimum-cost-to-cut-a-stick/ + +来自拼多多 +第一行有一个正整数n(3<=n<=100000),代表小A拟定的路线数量 +第二行有n个正整数,第i个代表第i条路线的起始日期 +第三行有n个正整数,第i个代表第i条路线的终止日期 +输入保证起始日期小于终止日期 +日期最小是1,最大不超过1000000000 +小A打算选三个路线进行旅游,比如 A -> B -> C +要求A的结束日期要小于B的开始日期,B的结束日期要小于C的开始日期 +输出一个非负整数,代表线路的方案数量 +例子 +输入 +6 +4 1 3 2 1 2 +4 1 3 3 2 2 +输出 +6 +解释 +[1,1] -> [2,2] -> [3,3] +[1,1] -> [2,2] -> [4,4] +[1,1] -> [2,3] -> [4,4] +[1,2] -> [3,3] -> [4,4] +[1,1] -> [3,3] -> [4,4] +[2,2] -> [3,3] -> [4,4] + +给定一个字符串 s,返回 s 中不同的非空 回文子序列 个数 +通过从 s 中删除 0 个或多个字符来获得子序列 +如果一个字符序列与它反转后的字符序列一致,那么它是 回文字符序列 +如果有某个 i , 满足 ai != bi ,则两个序列 a1, a2, ... 和 b1, b2, ... 不同 +注意:结果可能很大,你需要对 10^9 + 7 取模 +测试链接 : https://leetcode.cn/problems/count-different-palindromic-subsequences/ + +来自学员问题 +设计一个仓库管理器,提供如下的方法: +1) void supply(String item, int num, int price) +名字叫item的商品,个数num,价格price +2) int sell(String item, int num) +卖出叫item的商品,个数num个,价格从低到高,返回卖出总价 +如果商品很多,每种商品的数量可能很多,该怎么设计这个结构 + +来自亚马逊 +给定一个数组arr,和一个正数k +你可以随意删除arr中的数字,最多删除k个 +目的是让连续出现一种数字的长度尽量长 +返回这个尽量长的长度 +比如数组arr = { 3, -2, 3, 3, 5, 6, 3, -2 }, k = 3 +你可以删掉-2、5、6(最多3个),这样数组arr = { 3, 3, 3, 3, -2 } +可以看到连续出现3的长度为4 +这是所有删除方法里的最长结果,所以返回4 +1 <= arr长度 <= 3 * 10^5 +-10^9 <= arr中的数值 <= 10^9 +0 <= k <= 3 * 10^5 + + + + + + + + + + + + + + +