diff --git a/算法周更班/class_2023_07_4_week/Code01_MinimumOperationsToHalveArraySum.java b/算法周更班/class_2023_07_4_week/Code01_MinimumOperationsToHalveArraySum.java new file mode 100644 index 0000000..3787f88 --- /dev/null +++ b/算法周更班/class_2023_07_4_week/Code01_MinimumOperationsToHalveArraySum.java @@ -0,0 +1,72 @@ +package class_2023_07_4_week; + +import java.util.PriorityQueue; + +// 给你一个正整数数组 nums +// 每一次操作中,你可以从 nums 中选择 任意 一个数并将它减小到 恰好 一半 +//(注意,在后续操作中你可以对减半过的数继续执行操作) +// 请你返回将 nums 数组和 至少 减少一半的 最少 操作数 +// 测试链接 : https://leetcode.cn/problems/minimum-operations-to-halve-array-sum/ +public class Code01_MinimumOperationsToHalveArraySum { + + public static int halveArray1(int[] nums) { + PriorityQueue heap = new PriorityQueue<>((a, b) -> b.compareTo(a)); + double sum = 0; + for (int num : nums) { + heap.add((double) num); + sum += num; + } + sum /= 2; + int ans = 0; + for (double minus = 0, cur; minus < sum; ans++, minus += cur) { + cur = heap.poll() / 2; + heap.add(cur); + } + return ans; + } + + public static int MAXN = 100001; + + public static long[] heap = new long[MAXN]; + + public static int size; + + public static int halveArray2(int[] nums) { + size = nums.length; + long sum = 0; + for (int i = size - 1; i >= 0; i--) { + heap[i] = (long) nums[i] << 20; + sum += heap[i]; + heapify(i); + } + sum /= 2; + int ans = 0; + for (long minus = 0; minus < sum; ans++) { + heap[0] /= 2; + minus += heap[0]; + heapify(0); + } + return ans; + } + + public static void heapify(int i) { + int l = i * 2 + 1; + while (l < size) { + int best = l + 1 < size && heap[l + 1] > heap[l] ? l + 1 : l; + best = heap[best] > heap[i] ? best : i; + if (best == i) { + break; + } + swap(best, i); + i = best; + l = i * 2 + 1; + } + } + + public static void swap(int i, int j) { + long tmp = heap[i]; + heap[i] = heap[j]; + heap[j] = tmp; + } + +} diff --git a/算法周更班/class_2023_07_4_week/Code02_TeamDP.java b/算法周更班/class_2023_07_4_week/Code02_TeamDP.java new file mode 100644 index 0000000..38497f8 --- /dev/null +++ b/算法周更班/class_2023_07_4_week/Code02_TeamDP.java @@ -0,0 +1,86 @@ +package class_2023_07_4_week; + +// 自 01背包问世之后,小 A 对此深感兴趣 +// 一天,小 A 去远游,却发现他的背包不同于 01 背包,他的物品大致可分为 k 组 +// 每组中的物品只能选择1件,现在他想知道最大的利用价值是多少 +// 测试链接 : www.luogu.com.cn/problem/P1757 +// 请同学们务必参考如下代码中关于输入、输出的处理 +// 这是输入输出处理效率很高的写法 +// 提交以下的code,提交时请把类名改成"Main",可以直接通过 + +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 Code02_TeamDP { + + public static int MAXN = 1001; + + public static int MAXM = 1001; + + // arr[i][0] 重量 + // arr[i][1] 价值 + // arr[i][2] 组号 + public static int[][] arr = new int[MAXN][3]; + + public static int[] dp = new int[MAXM]; + + public static int m, 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) { + // 总背包的载重 + m = (int) in.nval; + in.nextToken(); + // 物品数量 + n = (int) in.nval; + for (int i = 0; i < n; i++) { + in.nextToken(); + arr[i][0] = (int) in.nval; + in.nextToken(); + arr[i][1] = (int) in.nval; + in.nextToken(); + arr[i][2] = (int) in.nval; + } + + // 根据组号排序 + // 1 : a b c 2 : d e 3 : f g h + Arrays.sort(arr, 0, n, (a, b) -> a[2] - b[2]); + // dp[位置][剩余重量] + // dp[重量] + Arrays.fill(dp, 0, m + 1, 0); + out.println(compute()); + out.flush(); + } + } + + public static int compute() { + for (int start = 0, end = 1; start < n;) { + // start(首个物品) + // end(当前这个组的越界物品) + // a b c | d e | f g + // 0 1 2 3 4 5 6 + while (end < n && arr[end][2] == arr[start][2]) { + end++; + } + // [start...end)是一个组的物品 + for (int r = m; r >= 0; r--) { + for (int i = start; i < end; i++) { + if (r >= arr[i][0]) { + dp[r] = Math.max(dp[r], arr[i][1] + dp[r - arr[i][0]]); + } + } + } + start = end++; + } + return dp[m]; + } + +} diff --git a/算法周更班/class_2023_07_4_week/Code03_MaximumValueOfKcoinsFromPiles.java b/算法周更班/class_2023_07_4_week/Code03_MaximumValueOfKcoinsFromPiles.java new file mode 100644 index 0000000..65ebdb7 --- /dev/null +++ b/算法周更班/class_2023_07_4_week/Code03_MaximumValueOfKcoinsFromPiles.java @@ -0,0 +1,35 @@ +package class_2023_07_4_week; + +import java.util.List; + +// 一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币 +// 每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里 +// 给你一个列表 piles ,其中 piles[i] 是一个整数数组 +// 分别表示第 i 个栈里 从顶到底 的硬币面值。同时给你一个正整数 k +// 请你返回在 恰好 进行 k 次操作的前提下,你钱包里硬币面值之和 最大为多少 +// 测试链接 : https://leetcode.cn/problems/maximum-value-of-k-coins-from-piles/ +public class Code03_MaximumValueOfKcoinsFromPiles { + + public int maxValueOfCoins(List> piles, int k) { + int[] dp = new int[k + 1]; + // 物品总量,n 2000内 + // 组的数量,m 1000内 + // 挑选的次数,k 2000内 + // O( k * n) + // O( m * k^2) + // min ( O( k * n) , O( m * k^2) ) + for (List stack : piles) { // 组 + for (int w = k; w > 0; w--) { // 背包容量 + // i = 1 sum = 0 + // i = 2 sum = arr[0] + // i = 3 sum = arr[0] + arr[1] + for (int i = 1, sum = 0; i <= Math.min(stack.size(), w); i++) { + sum += stack.get(i - 1); + dp[w] = Math.max(dp[w], sum + dp[w - i]); + } + } + } + return dp[k]; + } + +} diff --git a/算法周更班/class_2023_07_4_week/Code04_OnesAndZeroes.java b/算法周更班/class_2023_07_4_week/Code04_OnesAndZeroes.java new file mode 100644 index 0000000..42a5963 --- /dev/null +++ b/算法周更班/class_2023_07_4_week/Code04_OnesAndZeroes.java @@ -0,0 +1,132 @@ +package class_2023_07_4_week; + +// 多维费用背包(概念没用) +// 给你一个二进制字符串数组 strs 和两个整数 m 和 n +// 请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 +// 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 +// 测试链接 : https://leetcode.cn/problems/ones-and-zeroes/ +public class Code04_OnesAndZeroes { + + public static int findMaxForm1(String[] strs, int m, int n) { + int len = strs.length; + int[][] arr = new int[len][2]; + for (int i = 0, zeros, ones; i < strs.length; i++) { + zeros = 0; + ones = 0; + for (int j = 0; j < strs[i].length(); j++) { + if (strs[i].charAt(j) == '0') { + zeros++; + } else { + ones++; + } + } + arr[i][0] = zeros; + arr[i][1] = ones; + } + return process1(arr, 0, m, n); + } + + public static int process1(int[][] arr, int i, int z, int o) { + if (i == arr.length) { + return 0; + } + int p1 = process1(arr, i + 1, z, o); + int p2 = 0; + if (arr[i][0] <= z && arr[i][1] <= o) { + p2 = 1 + process1(arr, i + 1, z - arr[i][0], o - arr[i][1]); + } + return Math.max(p1, p2); + } + + public static int findMaxForm2(String[] strs, int m, int n) { + int len = strs.length; + int[][] arr = new int[len][2]; + for (int i = 0, zeros, ones; i < strs.length; i++) { + zeros = 0; + ones = 0; + for (int j = 0; j < strs[i].length(); j++) { + if (strs[i].charAt(j) == '0') { + zeros++; + } else { + ones++; + } + } + arr[i][0] = zeros; + arr[i][1] = ones; + } + int[][][] dp = new int[len][m + 1][n + 1]; + for (int i = 0; i < len; i++) { + for (int j = 0; j <= m; j++) { + for (int k = 0; k <= n; k++) { + dp[i][j][k] = -1; + } + } + } + return process2(arr, 0, m, n, dp); + } + + // "101010101" -> 0 4个 1 5个 [4,5] + // "000111" -> [3,3] + public static int process2(int[][] arr, int i, int z, int o, int[][][] dp) { + if (i == arr.length) { + return 0; + } + if (dp[i][z][o] != -1) { + return dp[i][z][o]; + } + int p1 = process2(arr, i + 1, z, o, dp); + // 要当前字符串 + int p2 = 0; + if (arr[i][0] <= z && arr[i][1] <= o) { + p2 = 1 + process2(arr, i + 1, z - arr[i][0], o - arr[i][1], dp); + } + int ans = Math.max(p1, p2); + dp[i][z][o] = ans; + return ans; + } + + public static int findMaxForm3(String[] strs, int m, int n) { + int len = strs.length; + int[][][] dp = new int[len + 1][m + 1][n + 1]; + for (int i = len - 1; i >= 0; i--) { + zeroAndOne(strs[i]); + for (int z = 0; z <= m; z++) { + for (int o = 0; o <= n; o++) { + dp[i][z][o] = dp[i + 1][z][o]; + if (zeros <= z && ones <= o) { + dp[i][z][o] = Math.max(dp[i][z][o], 1 + dp[i + 1][z - zeros][o - ones]); + } + } + } + } + return dp[0][m][n]; + } + + public static int zeros, ones; + + public static void zeroAndOne(String str) { + zeros = 0; + ones = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '0') { + zeros++; + } else { + ones++; + } + } + } + + public static int findMaxForm4(String[] strs, int m, int n) { + int[][] dp = new int[m + 1][n + 1]; + for (String s : strs) { + zeroAndOne(s); + for (int i = m; i >= zeros; i--) { + for (int j = n; j >= ones; j--) { + dp[i][j] = Math.max(dp[i][j], dp[i - zeros][j - ones] + 1); + } + } + } + return dp[m][n]; + } + +} diff --git a/算法周更班/class_2023_07_4_week/Code05_ProfitableSchemes.java b/算法周更班/class_2023_07_4_week/Code05_ProfitableSchemes.java new file mode 100644 index 0000000..2ddc51d --- /dev/null +++ b/算法周更班/class_2023_07_4_week/Code05_ProfitableSchemes.java @@ -0,0 +1,99 @@ +package class_2023_07_4_week; + +// 集团里有 n 名员工,他们可以完成各种各样的工作创造利润 +// 第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与 +// 如果成员参与了其中一项工作,就不能参与另一项工作 +// 工作的任何至少产生 minProfit 利润的子集称为 盈利计划 +// 并且工作的成员总数最多为 n +// 有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7 的值。 +// 测试链接 : https://leetcode.cn/problems/profitable-schemes/ +public class Code05_ProfitableSchemes { + + // n : 员工的额度 , 不能超 + // p : 利润的额度 , 不能少 + // group[i] : 需要几个人 + // profit[i] : 产生的利润 + + public static int profitableSchemes1(int n, int minProfit, int[] group, int[] profit) { + return f1(group, profit, 0, n, minProfit); + } + + // i : 来到i号项目 + // r : 员工还有r人 + // s : 利润还有s才能达成目标! + // 返回 : 有多少种方案 + public static int f1(int[] g, int[] p, int i, int r, int s) { + if (r <= 0) { + // 人已经没了 + // s为0,或者负数,都叫完成工作了 + return s <= 0 ? 1 : 0; + } + // r > 0 + if (i == g.length) { + // 项目已经没了 + // s为0,或者负数,都叫完成工作了 + return s <= 0 ? 1 : 0; + } + int p1 = f1(g, p, i + 1, r, s); + int p2 = 0; + if (g[i] <= r) { + // 100 400 -300 -> 0 + p2 = f1(g, p, i + 1, r - g[i], s - p[i]); + } + return p1 + p2; + } + + public static int mod = 1000000007; + + public static int profitableSchemes2(int n, int minProfit, int[] group, int[] profit) { + int m = group.length; + int[][][] dp = new int[m][n + 1][minProfit + 1]; + for (int a = 0; a < m; a++) { + for (int b = 0; b <= n; b++) { + for (int c = 0; c <= minProfit; c++) { + dp[a][b][c] = -1; + } + } + } + return f2(group, profit, 0, n, minProfit, dp); + } + + public static int f2(int[] g, int[] p, int i, int r, int s, int[][][] dp) { + if (r <= 0) { + return s == 0 ? 1 : 0; + } + if (i == g.length) { + return s == 0 ? 1 : 0; + } + if (dp[i][r][s] != -1) { + return dp[i][r][s]; + } + int p1 = f2(g, p, i + 1, r, s, dp); + int p2 = 0; + if (g[i] <= r) { + p2 = f2(g, p, i + 1, r - g[i], Math.max(0, s - p[i]), dp); + } + int ans = (p1 + p2) % mod; + dp[i][r][s] = ans; + return ans; + } + + public static int profitableSchemes3(int n, int minProfit, int[] group, int[] profit) { + int[][] dp = new int[n + 1][minProfit + 1]; + for (int r = 0; r <= n; r++) { + dp[r][0] = 1; + } + int m = group.length; + for (int i = m - 1; i >= 0; i--) { + for (int r = n; r >= 0; r--) { + for (int s = minProfit; s >= 0; s--) { + int p1 = dp[r][s]; + int p2 = group[i] <= r ? dp[r - group[i]][Math.max(0, s - profit[i])] : 0; + dp[r][s] = (p1 + p2) % mod; + } + } + } + return dp[n][minProfit]; + } + +} diff --git a/算法周更班/class_2023_07_4_week/Code06_PaintHouseIII.java b/算法周更班/class_2023_07_4_week/Code06_PaintHouseIII.java new file mode 100644 index 0000000..d15180f --- /dev/null +++ b/算法周更班/class_2023_07_4_week/Code06_PaintHouseIII.java @@ -0,0 +1,207 @@ +package class_2023_07_4_week; + +// 在一个小城市里,有 m 个房子排成一排 +// 你需要给每个房子涂上 n 种颜色之一(颜色编号为 1 到 n ) +// 有的房子去年夏天已经涂过颜色了,所以这些房子不可以被重新涂色 +// 我们将连续相同颜色尽可能多的房子称为一个街区 +// 比方说 houses = [1,2,2,3,3,2,1,1] +// 它包含 5 个街区 [{1}, {2,2}, {3,3}, {2}, {1,1}] +// 给你一个数组 houses ,一个 m * n 的矩阵 cost 和一个整数 target,其中: +// houses[i]:是第 i 个房子的颜色,0 表示这个房子还没有被涂色 +// cost[i][j]:是将第 i 个房子涂成颜色 j+1 的花费 +// 请你返回房子涂色方案的最小总花费,使得每个房子都被涂色后,恰好组成 target 个街区 +// 如果没有可用的涂色方案,请返回 -1 +// 测试链接 : https://leetcode.cn/problems/paint-house-iii/ +public class Code06_PaintHouseIII { + + public static int minCost1(int[] houses, // 每个房子固有的颜色,0 :去涂,>0: 不能改的 + int[][] cost,// cost[i][j] : i号房子,涂上j这个颜色,花费多少 + int m, // 房子数量 + int n, // 颜色数量 + int target // 恰好组成 target 个街区 + ) { + int[][][] dp = new int[m][target + 1][n + 1]; + for (int i = 0; i < m; i++) { + for (int k = 0; k <= target; k++) { + for (int c = 0; c <= n; c++) { + dp[i][k][c] = -1; + } + } + } + int ans = process1(houses, cost, n, 0, target, 0, dp); + return ans == Integer.MAX_VALUE ? -1 : ans; + } + + // i.... 涂色,必须整出k个街区来! + // 上一个房子的颜色是c + // 返回最小花费 + // 返回Integer.MAX_VALUE:做不到 + // 返回正常值,代表最小花费 + public static int process1( + int[] houses, int[][] cost, + int n, // 颜色总数,1 ~ n,固定! + int i, // 来到的房子编号,可变 + int k, // i.... 必须整出k个街区来!,可变 + int c, // 上一个房子的颜色,可变 + int[][][] dp) { + if (k < 0) { + return Integer.MAX_VALUE; + } + if (i == houses.length) { + return k == 0 ? 0 : Integer.MAX_VALUE; + } + // k >= 0, 还有房 + if (dp[i][k][c] != -1) { + return dp[i][k][c]; + } + // 最小花费 + int ans = Integer.MAX_VALUE; + if (houses[i] != 0) { + // 不能涂,已经有颜色了 + // houses[i] = 3 + if (houses[i] != c) { + ans = process1(houses, cost, n, i + 1, k - 1, houses[i], dp); + } else { + ans = process1(houses, cost, n, i + 1, k, houses[i], dp); + } + } else { + // houses[i] == 0 + // 能涂 + for (int fill = 1, next; fill <= n; fill++) { + // 尝试每一种颜色 + if (fill == c) { + next = process1(houses, cost, n, i + 1, k, fill, dp); + } else { + next = process1(houses, cost, n, i + 1, k - 1, fill, dp); + } + if (next != Integer.MAX_VALUE) { + ans = Math.min(ans, cost[i][fill - 1] + next); + } + } + } + dp[i][k][c] = ans; + return ans; + } + + public static int minCost2(int[] houses, int[][] cost, int m, int n, int target) { + int[][] dp = new int[target + 1][n + 1]; + for (int c = 0; c <= n; c++) { + dp[0][c] = 0; + } + for (int k = 1; k <= target; k++) { + for (int c = 0; c <= n; c++) { + dp[k][c] = Integer.MAX_VALUE; + } + } + int[] memo = new int[n + 1]; + for (int i = m - 1; i >= 0; i--) { + if (houses[i] != 0) { + int houseColor = houses[i]; + for (int k = target; k >= 0; k--) { + int memory = dp[k][houseColor]; + for (int c = 0; c <= n; c++) { + if (houseColor != c) { + dp[k][c] = k == 0 ? Integer.MAX_VALUE : dp[k - 1][houseColor]; + } else { + dp[k][c] = memory; + } + } + } + } else { + for (int k = target; k >= 0; k--) { + for (int c = 0; c <= n; c++) { + memo[c] = dp[k][c]; + } + for (int c = 0; c <= n; c++) { + int ans = Integer.MAX_VALUE; + for (int fill = 1, next; fill <= n; fill++) { + if (fill == c) { + next = memo[fill]; + } else { + next = k == 0 ? Integer.MAX_VALUE : dp[k - 1][fill]; + } + if (next != Integer.MAX_VALUE) { + ans = Math.min(ans, cost[i][fill - 1] + next); + } + } + dp[k][c] = ans; + } + } + } + } + return dp[target][0] == Integer.MAX_VALUE ? -1 : dp[target][0]; + } + + public static int minCost3(int[] houses, int[][] cost, int m, int n, int target) { + int[][] dp = new int[target + 1][n + 1]; + for (int c = 0; c <= n; c++) { + dp[0][c] = 0; + } + for (int k = 1; k <= target; k++) { + for (int c = 0; c <= n; c++) { + dp[k][c] = Integer.MAX_VALUE; + } + } + int[] memo = new int[n + 1]; + // 0~0 0~1 0~2 0~i + int[] minl = new int[n + 2]; + // n ~ n n-1 ~n n-2 ~n i ~n + int[] minr = new int[n + 2]; + minl[0] = minr[0] = minl[n + 1] = minr[n + 1] = Integer.MAX_VALUE; + for (int i = m - 1; i >= 0; i--) { + if (houses[i] != 0) { + for (int k = target, memory; k >= 0; k--) { + memory = dp[k][houses[i]]; + for (int c = 0; c <= n; c++) { + if (houses[i] != c) { + dp[k][c] = k == 0 ? Integer.MAX_VALUE : dp[k - 1][houses[i]]; + } else { + dp[k][c] = memory; + } + } + } + } else { + // O(k) + for (int k = target; k >= 0; k--) { + // O(n) + for (int c = 0; c <= n; c++) { + memo[c] = dp[k][c]; + } + // O(n) + for (int fill = 1; fill <= n; fill++) { + if (k == 0 || dp[k - 1][fill] == Integer.MAX_VALUE) { + minl[fill] = minl[fill - 1]; + } else { + minl[fill] = Math.min(minl[fill - 1], cost[i][fill - 1] + dp[k - 1][fill]); + } + } + // O(n) + for (int fill = n; fill >= 1; fill--) { + if (k == 0 || dp[k - 1][fill] == Integer.MAX_VALUE) { + minr[fill] = minr[fill + 1]; + } else { + minr[fill] = Math.min(minr[fill + 1], cost[i][fill - 1] + dp[k - 1][fill]); + } + } + // O(n) + for (int c = 0, ans; c <= n; c++) { + if (c == 0 || memo[c] == Integer.MAX_VALUE) { + ans = Integer.MAX_VALUE; + } else { + ans = cost[i][c - 1] + memo[c]; + } + if (c > 0) { + ans = Math.min(ans, minl[c - 1]); + } + if (c < n) { + ans = Math.min(ans, minr[c + 1]); + } + dp[k][c] = ans; + } + } + } + } + return dp[target][0] != Integer.MAX_VALUE ? dp[target][0] : -1; + } + +} diff --git a/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) b/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) index f4a4c7d..43bbcaf 100644 --- a/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) +++ b/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) @@ -4185,6 +4185,56 @@ int popAtStack(int index) - 返回编号 index 的栈顶部的值,并将其从 +第078节 2023年7月4周流行算法题目解析 + +给你一个正整数数组 nums +每一次操作中,你可以从 nums 中选择 任意 一个数并将它减小到 恰好 一半 +注意,在后续操作中你可以对减半过的数继续执行操作 +请你返回将 nums 数组和 至少 减少一半的 最少 操作数 +测试链接 : https://leetcode.cn/problems/minimum-operations-to-halve-array-sum/ + +自 01背包问世之后,小 A 对此深感兴趣 +一天,小 A 去远游,却发现他的背包不同于 01 背包,他的物品大致可分为 k 组 +每组中的物品只能选择1件,现在他想知道最大的利用价值是多少 +测试链接 : www.luogu.com.cn/problem/P1757 + +一张桌子上总共有 n 个硬币 栈 。每个栈有 正整数 个带面值的硬币 +每一次操作中,你可以从任意一个栈的 顶部 取出 1 个硬币,从栈中移除它,并放入你的钱包里 +给你一个列表 piles ,其中 piles[i] 是一个整数数组 +分别表示第 i 个栈里 从顶到底 的硬币面值。同时给你一个正整数 k +请你返回在 恰好 进行 k 次操作的前提下,你钱包里硬币面值之和 最大为多少 +测试链接 : https://leetcode.cn/problems/maximum-value-of-k-coins-from-piles/ + +给你一个二进制字符串数组 strs 和两个整数 m 和 n +请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 +如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 +测试链接 : https://leetcode.cn/problems/ones-and-zeroes/ + +集团里有 n 名员工,他们可以完成各种各样的工作创造利润 +第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与 +如果成员参与了其中一项工作,就不能参与另一项工作 +工作的任何至少产生 minProfit 利润的子集称为 盈利计划 +并且工作的成员总数最多为 n +有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7 的值。 +测试链接 : https://leetcode.cn/problems/profitable-schemes/ + +在一个小城市里,有 m 个房子排成一排 +你需要给每个房子涂上 n 种颜色之一(颜色编号为 1 到 n ) +有的房子去年夏天已经涂过颜色了,所以这些房子不可以被重新涂色 +我们将连续相同颜色尽可能多的房子称为一个街区 +比方说 houses = [1,2,2,3,3,2,1,1] +它包含 5 个街区 [{1}, {2,2}, {3,3}, {2}, {1,1}] +给你一个数组 houses ,一个 m * n 的矩阵 cost 和一个整数 target,其中: +houses[i]:是第 i 个房子的颜色,0 表示这个房子还没有被涂色 +cost[i][j]:是将第 i 个房子涂成颜色 j+1 的花费 +请你返回房子涂色方案的最小总花费,使得每个房子都被涂色后,恰好组成 target 个街区 +如果没有可用的涂色方案,请返回 -1 +测试链接 : https://leetcode.cn/problems/paint-house-iii/ + + + + +