From 4c8cafa7602a928f31e7fb7e867a5af28897d1c2 Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Thu, 2 Feb 2023 11:35:57 +0800 Subject: [PATCH] modify code --- .../Code01_MinimizeDeviationInArray.java | 36 ++++++ .../Code02_OddEvenJump.java | 61 +++++++++ ...3_MinimumNumberOfKConsecutiveBitFlips.java | 38 ++++++ .../Code04_FourKindsPaperQueryWays.java | 116 ++++++++++++++++++ ...养的大厂算法面试题(正在直播) | 55 +++++++-- 5 files changed, 299 insertions(+), 7 deletions(-) create mode 100644 算法周更班/class_2023_02_1_week/Code01_MinimizeDeviationInArray.java create mode 100644 算法周更班/class_2023_02_1_week/Code02_OddEvenJump.java create mode 100644 算法周更班/class_2023_02_1_week/Code03_MinimumNumberOfKConsecutiveBitFlips.java create mode 100644 算法周更班/class_2023_02_1_week/Code04_FourKindsPaperQueryWays.java diff --git a/算法周更班/class_2023_02_1_week/Code01_MinimizeDeviationInArray.java b/算法周更班/class_2023_02_1_week/Code01_MinimizeDeviationInArray.java new file mode 100644 index 0000000..3b8ad51 --- /dev/null +++ b/算法周更班/class_2023_02_1_week/Code01_MinimizeDeviationInArray.java @@ -0,0 +1,36 @@ +package class_2023_02_1_week; + +import java.util.TreeSet; + +// 给你一个由 n 个正整数组成的数组 nums +// 你可以对数组的任意元素执行任意次数的两类操作 +// 如果元素是 偶数 ,除以 2 +// 例如,如果数组是 [1,2,3,4] +// 那么你可以对最后一个元素执行此操作使其变成 [1,2,3,2] +// 如果元素是 奇数 ,乘上 2 +// 例如,如果数组是 [1,2,3,4] ,那么你可以对第一个元素执行此操作,使其变成 [2,2,3,4] +// 数组的 偏移量 是数组中任意两个元素之间的 最大差值 +// 返回数组在执行某些操作之后可以拥有的 最小偏移量 +// 测试链接 : https://leetcode.cn/problems/minimize-deviation-in-array/ +public class Code01_MinimizeDeviationInArray { + + public int minimumDeviation(int[] nums) { + // 有序表,小 -> 大 组织 + // 最大 set.last() + TreeSet set = new TreeSet<>(); + for (int num : nums) { + set.add(num % 2 == 0 ? num : num * 2); + } + // 答案 + int ans = set.last() - set.first(); + while (ans > 0 && set.last() % 2 == 0) { + // 最大值 + int max = set.last(); + set.remove(max); + set.add(max / 2); + ans = Math.min(ans, set.last() - set.first()); + } + return ans; + } + +} diff --git a/算法周更班/class_2023_02_1_week/Code02_OddEvenJump.java b/算法周更班/class_2023_02_1_week/Code02_OddEvenJump.java new file mode 100644 index 0000000..046f878 --- /dev/null +++ b/算法周更班/class_2023_02_1_week/Code02_OddEvenJump.java @@ -0,0 +1,61 @@ +package class_2023_02_1_week; + +import java.util.TreeMap; + +// 给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 +// 在你跳跃的过程中,第 1、3、5... 次跳跃称为奇数跳跃 +// 而第 2、4、6... 次跳跃称为偶数跳跃 +// 你可以按以下方式从索引 i 向后跳转到索引 j(其中 i < j): +// 在进行奇数跳跃时(如,第 1,3,5... 次跳跃),你将会跳到索引 j +// 使得 A[i] <= A[j],A[j] 是可能的最小值。如果存在多个这样的索引 j +// 你只能跳到满足要求的最小索引 j 上。 +// 在进行偶数跳跃时(如,第 2,4,6... 次跳跃) +// 你将会跳到索引 j,使得 A[i] >= A[j],A[j] 是可能的最大值 +// 如果存在多个这样的索引 j,你只能跳到满足要求的最小索引 j 上。 +//(对于某些索引 i,可能无法进行合乎要求的跳跃。) +// 如果从某一索引开始跳跃一定次数(可能是 0 次或多次) +// 就可以到达数组的末尾(索引 A.length - 1) +// 那么该索引就会被认为是好的起始索引 +// 返回好的起始索引的数量 +// 测试链接 : https://leetcode.cn/problems/odd-even-jump/ +public class Code02_OddEvenJump { + + public static int oddEvenJumps(int[] arr) { + int n = arr.length; + // 来到了i位置,如果要遵循奇数规则,应该去哪?odd[i] + int[] odd = new int[n]; + // 来到了i位置,如果要遵循偶数规则,应该去哪?even[i] + int[] even = new int[n]; + // 有序表, + // key : 某个值 + // value : key这个值,出现的最左位置 + // >= key 且最小 + // <= key 且最大 + TreeMap orderMap = new TreeMap<>(); + for (int i = n - 1; i >= 0; i--) { + // i位置,arr[i],奇数规则,>= arr[i]且最小的! + Integer to = orderMap.ceilingKey(arr[i]); + odd[i] = to == null ? -1 : orderMap.get(to); + // i位置,arr[i],偶数规则,<= arr[i]且最大的! + to = orderMap.floorKey(arr[i]); + even[i] = to == null ? -1 : orderMap.get(to); + orderMap.put(arr[i], i); + } + // dp[i][0] : 当来到i位置,且在奇数规则下,最终能不能到结尾? + // dp[i][1] : 当来到i位置,且在偶数规则下,最终能不能到结尾? + boolean[][] dp = new boolean[n][2]; + dp[n - 1][0] = true; + dp[n - 1][1] = true; + int ans = 1; + for (int i = n - 2; i >= 0; i--) { + // dp[i][0] : 当来到i位置,且在奇数规则下,最终能不能到结尾 + // odd[i] -> 右走! -1 + dp[i][0] = odd[i] != -1 && dp[odd[i]][1]; + // dp[i][1] : 当来到i位置,且在偶数规则下,最终能不能到结尾 + dp[i][1] = even[i] != -1 && dp[even[i]][0]; + ans += dp[i][0] ? 1 : 0; + } + return ans; + } + +} diff --git a/算法周更班/class_2023_02_1_week/Code03_MinimumNumberOfKConsecutiveBitFlips.java b/算法周更班/class_2023_02_1_week/Code03_MinimumNumberOfKConsecutiveBitFlips.java new file mode 100644 index 0000000..9f19625 --- /dev/null +++ b/算法周更班/class_2023_02_1_week/Code03_MinimumNumberOfKConsecutiveBitFlips.java @@ -0,0 +1,38 @@ +package class_2023_02_1_week; + +// 给定一个二进制数组 nums 和一个整数 k +// k位翻转 就是从 nums 中选择一个长度为 k 的 子数组 +// 同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 都改成 0 +// 返回数组中不存在 0 所需的最小 k位翻转 次数。如果不可能,则返回 -1 +// 子数组 是数组的 连续 部分。 +// 测试链接 : https://leetcode.cn/problems/minimum-number-of-k-consecutive-bit-flips/ +public class Code03_MinimumNumberOfKConsecutiveBitFlips { + + public int minKBitFlips(int[] nums, int k) { + int n = nums.length; + int[] queue = new int[n]; + int l = 0; + int r = 0; + int ans = 0; + for (int i = 0; i < n; i++) { + // 双端队列有东西,l、r l i + if (l != r && i - queue[l] == k) { + // 意味着,双端队列大小变了! + l++; + } + // r - l 是双端队列的大小 + // (r - l) & 1 == 1, + // 说明队列大小是奇数(尾部状态为0),那么nums[i] == 1该加入(因为和尾部不同) + // (r - l) & 1 == 0, + // 说明队列大小是偶数(尾部状态为1),那么nums[i] == 0该加入(因为和尾部不同) + // 所以综上,((r - l) & 1) == nums[i],该加入 + if (((r - l) & 1) == nums[i]) { + queue[r++] = i; + ans++; + } + } + // 最后的反转点长度够k,能翻转;否则不能 + return (l != r && queue[r - 1] + k > n) ? -1 : ans; + } + +} diff --git a/算法周更班/class_2023_02_1_week/Code04_FourKindsPaperQueryWays.java b/算法周更班/class_2023_02_1_week/Code04_FourKindsPaperQueryWays.java new file mode 100644 index 0000000..b0d2148 --- /dev/null +++ b/算法周更班/class_2023_02_1_week/Code04_FourKindsPaperQueryWays.java @@ -0,0 +1,116 @@ +package class_2023_02_1_week; + +// 一共有 4 种硬币。面值分别为c1、c2、c3、c4 +// 一开始就给定了,就是这些面值不再改变 +// 某人去商店买东西,去了 n 次, +// 每次都是一次查询: +// 这个人每次代的每种硬币的数量不一样,都记录在d数组中 +// 1) d[i]表示他带了的i种面值的数量 +// 2) 他要购买s价值的东西 +// 返回每次有多少种购买方法 +// 1 <= c1、c2、c3、c4、d[i]、s <= 10^5 +// 1 <= n <= 1000 +// 测试链接 : https://www.luogu.com.cn/problem/P1450 +// 请同学们务必参考如下代码中关于输入、输出的处理 +// 这是输入输出处理效率很高的写法 +// 提交以下的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; + +public class Code04_FourKindsPaperQueryWays { + + public static int limit = 100000; + // 无限制情况下的方法数,得到dp + // 可以用这个dp,去求解,2元 交上 3元的违规方法 + public static long[] dp = new long[limit + 1]; + public static int[] c = new int[4]; + public static int[] d = new int[4]; + public static int n, s; + + public static void init() { + dp[0] = 1; + for (int i = 0; i <= 3; i++) { + for (int j = c[i]; j <= limit; j++) { + dp[j] += dp[j - c[i]]; + } + } + } + + public static long query() { + // 违规方法数! + long minus = 0; + // d c b a + // 0 0 0 1 + // 0 1 1 0 + for (int status = 1; status <= 15; status++) { + // 100元,2元 4张 3元 9张 + // 100 - 2 * 5 - 3 * 10 => 60 + // 60元无限制的情况下,方法数是多少 + // 就是!100元,在2元面值和3元面值同时违规的情况下,违规方法数 + long t = s; + int sign = -1; + for (int j = 0; j <= 3; j++) { + // j 0号货币有没有? + // 1号货币有没有? + // 2号货币有没有? + // 3号货币有没有? + if (((status >> j) & 1) == 1) { + t -= c[j] * (d[j] + 1); + sign = -sign; + } + } + if (t >= 0) { + minus += dp[(int) t] * sign; + } + } + return dp[s] - minus; + } + + 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) { + // 先给每一种面值 + // 存好,可能有多组查询,但是有哪些面值是不变的 + // 面值的种数也不变,4种面值 + c[0] = (int) in.nval; + in.nextToken(); + c[1] = (int) in.nval; + in.nextToken(); + c[2] = (int) in.nval; + in.nextToken(); + c[3] = (int) in.nval; + in.nextToken(); + // 有多少组查询 + n = (int) in.nval; + init(); + for (int i = 0; i < n; i++) { + // 一组查询 + // a 面值 给你多少张 + // b 面值 给你多少张 + // c 面值 给你多少张 + // d 面值 给你多少张 + in.nextToken(); + d[0] = (int) in.nval; + in.nextToken(); + d[1] = (int) in.nval; + in.nextToken(); + d[2] = (int) in.nval; + in.nextToken(); + d[3] = (int) in.nval; + in.nextToken(); + // 花钱总数 + // 不超过10的5次方的 + s = (int) in.nval; + out.println(query()); + out.flush(); + } + } + } + +} diff --git a/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) b/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) index cd58fc4..8b87a4c 100644 --- a/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) +++ b/算法课堂笔记/课堂内容汇总/每周有营养的大厂算法面试题(正在直播) @@ -2860,13 +2860,54 @@ int pop() 删除并返回堆栈中出现频率最高的元素。 - - - - - - - +第056节 2023年2月第1周流行算法题目解析 + +给你一个由 n 个正整数组成的数组 nums +你可以对数组的任意元素执行任意次数的两类操作 +如果元素是 偶数 ,除以 2 +例如,如果数组是 [1,2,3,4] +那么你可以对最后一个元素执行此操作使其变成 [1,2,3,2] +如果元素是 奇数 ,乘上 2 +例如,如果数组是 [1,2,3,4] ,那么你可以对第一个元素执行此操作,使其变成 [2,2,3,4] +数组的 偏移量 是数组中任意两个元素之间的 最大差值 +返回数组在执行某些操作之后可以拥有的 最小偏移量 +测试链接 : https://leetcode.cn/problems/minimize-deviation-in-array/ + +给定一个整数数组 A,你可以从某一起始索引出发,跳跃一定次数 +在你跳跃的过程中,第 1、3、5... 次跳跃称为奇数跳跃 +而第 2、4、6... 次跳跃称为偶数跳跃 +你可以按以下方式从索引 i 向后跳转到索引 j(其中 i < j): +在进行奇数跳跃时(如,第 1,3,5... 次跳跃),你将会跳到索引 j +使得 A[i] <= A[j],A[j] 是可能的最小值。如果存在多个这样的索引 j +你只能跳到满足要求的最小索引 j 上。 +在进行偶数跳跃时(如,第 2,4,6... 次跳跃) +你将会跳到索引 j,使得 A[i] >= A[j],A[j] 是可能的最大值 +如果存在多个这样的索引 j,你只能跳到满足要求的最小索引 j 上。 +对于某些索引 i,可能无法进行合乎要求的跳跃 +如果从某一索引开始跳跃一定次数(可能是 0 次或多次) +就可以到达数组的末尾(索引 A.length - 1) +那么该索引就会被认为是好的起始索引 +返回好的起始索引的数量 +测试链接 : https://leetcode.cn/problems/odd-even-jump/ + +给定一个二进制数组 nums 和一个整数 k +k位翻转 就是从 nums 中选择一个长度为 k 的 子数组 +同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 都改成 0 +返回数组中不存在 0 所需的最小 k位翻转 次数。如果不可能,则返回 -1 +子数组 是数组的 连续 部分。 +测试链接 : https://leetcode.cn/problems/minimum-number-of-k-consecutive-bit-flips/ + +一共有 4 种硬币。面值分别为c1、c2、c3、c4 +一开始就给定了,就是这些面值不再改变 +某人去商店买东西,去了 n 次, +每次都是一次查询: +这个人每次代的每种硬币的数量不一样,都记录在d数组中 +1) d[i]表示他带了的i种面值的数量 +2) 他要购买s价值的东西 +返回每次有多少种购买方法 +1 <= c1、c2、c3、c4、d[i]、s <= 10^5 +1 <= n <= 1000 +测试链接 : https://www.luogu.com.cn/problem/P1450