From e804dbb23bf1aa35b5d7beb985b6296d5542115e Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Mon, 3 Apr 2023 12:56:21 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/hot100/T80_MaxProfit.java | 7 +- .../markilue/leecode/hot100/T81_MaxCoins.java | 7 +- .../leecode/hot100/T82_CoinChange.java | 84 ++++++++++++ .../com/markilue/leecode/hot100/T83_Rob.java | 41 ++++++ .../leecode/hot100/T84_CountBits.java | 124 ++++++++++++++++++ .../leecode/hot100/T85_TopKFrequent.java | 98 ++++++++++++++ 6 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java index 5eb0bb0..4beb134 100644 --- a/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T80_MaxProfit.java @@ -7,7 +7,12 @@ import org.junit.Test; *@BelongsPackage: com.markilue.leecode.hot100 *@Author: markilue *@CreateTime: 2023-03-31 11:13 - *@Description: TODO + *@Description: + * TODO 力扣309 最佳买卖股票时机含冷冻期: + * 给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。​ + * 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): + * 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 *@Version: 1.0 */ public class T80_MaxProfit { diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java index db1eb47..5f096b4 100644 --- a/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T81_MaxCoins.java @@ -7,7 +7,12 @@ import org.junit.Test; *@BelongsPackage: com.markilue.leecode.hot100 *@Author: markilue *@CreateTime: 2023-03-31 11:28 - *@Description: TODO + *@Description: + * TODO 力扣312 戳气球: + * 有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。 + * 现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 + * 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。 + * 求所能获得硬币的最大数量。 *@Version: 1.0 */ public class T81_MaxCoins { diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java new file mode 100644 index 0000000..0a52a50 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T82_CoinChange.java @@ -0,0 +1,84 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 09:49 + *@Description: + * TODO 力扣322 零钱兑换: + * 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 + * 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 + * 你可以认为每种硬币的数量是无限的。 + *@Version: 1.0 + */ +public class T82_CoinChange { + + @Test + public void test() { + int[] coins = {186, 419, 83, 408}; + int amount = 6249; + System.out.println(coinChange(coins, amount)); + } + + + /** + * 思路:硬币可以使用无数次 完全背包 + * 动态DP + * @param coins + * @param amount + * @return + */ + public int coinChange(int[] coins, int amount) { + + int[][] dp = new int[coins.length][amount + 1]; + Arrays.sort(coins); + dp[0][0] = 0; + for (int i = 1; i < dp[0].length; i++) { + if (i >= coins[0] && i % coins[0] == 0) dp[0][i] = dp[0][i - coins[0]] + 1; + else dp[0][i] = Integer.MAX_VALUE; + } + + for (int i = 1; i < dp.length; i++) { + for (int j = 1; j < dp[0].length; j++) { + if (j >= coins[i] && dp[i][j - coins[i]] != Integer.MAX_VALUE) { + dp[i][j] = Math.min(dp[i][j - coins[i]] + 1, dp[i - 1][j]); + } else dp[i][j] = dp[i - 1][j];//使用哪一个 + } + } + return dp[coins.length - 1][amount] == Integer.MAX_VALUE ? -1 : dp[coins.length - 1][amount]; + } + + + /** + * 一维dp优化 + * @param coins + * @param amount + * @return + */ + public int coinChange1(int[] coins, int amount) { + + int[] dp = new int[amount + 1]; +// Arrays.sort(coins); + dp[0] = 0; + for (int i = 1; i < dp.length; i++) { + if (i >= coins[0] && i % coins[0] == 0) dp[i] = dp[i - coins[0]] + 1; + else dp[i] = Integer.MAX_VALUE; + } + + for (int i = 1; i < coins.length; i++) { + for (int j = coins[i]; j < dp.length; j++) { + if (j >= coins[i] && dp[j - coins[i]] != Integer.MAX_VALUE) { + dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]); + } + } + } + return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount]; + + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java new file mode 100644 index 0000000..1332e0c --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T83_Rob.java @@ -0,0 +1,41 @@ +package com.markilue.leecode.hot100; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 10:24 + *@Description: + * TODO 力扣337 打家劫舍III: + * 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。 + * 除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 + * 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。 + * 给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。 + *@Version: 1.0 + */ +public class T83_Rob { + + public int rob(TreeNode root) { + + int[] dp = subRob(root); + return Math.max(dp[0],dp[1]); + + } + + public int[] subRob(TreeNode root) { + if (root == null) { + return new int[]{0, 0}; + } + + int[] left = subRob(root.left); + int[] right = subRob(root.right); + + int steal = left[0] + right[0] + root.val; + int noSteal = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); + + return new int[]{noSteal, steal}; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java new file mode 100644 index 0000000..39a4e5e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T84_CountBits.java @@ -0,0 +1,124 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 10:38 + *@Description: + * TODO 力扣338 比特位计数: + * 给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。 + *@Version: 1.0 + */ +public class T84_CountBits { + + @Test + public void test1() { + int n = 85723; + System.out.println(Arrays.toString(countBits(n))); + } + + /** + *思路:挨个增加,有则进位 + * 速度击败6.9% 内存击败13.58% 59ms + * @param n + * @return + */ + public int[] countBits(int n) { + + int[] nums = new int[n + 1]; + long cur = 0; + for (int i = 0; i < nums.length; i++) { + long[] check = check(cur); + cur = check[0] + 1; + nums[i] = (int)check[1]; + } + + return nums; + + } + + @Test + public void test() { + int num = 1112; + System.out.println(check(num)); + } + + public long[] check(long n) { + //int count =0; + boolean flag = false;//是否进位 + int num = 0; + int count = 0; + StringBuilder sb = new StringBuilder(); + while (n != 0 || flag) { + long cur = n % 10; + if (flag) cur += 1; + if (cur == 1) count++; + if (cur > 1) { + flag = true; + sb.append(0); + } else { + flag = false; + sb.append(cur); + } + n /= 10; + } + if (sb.length() == 0) { + sb.append(0); + } + return new long[]{Long.parseLong(sb.reverse().toString()), count}; + } + + + /** + * 官方题解:Brian Kernighan 算法 + * x=x & (x−1) 这一运算将x的二进制表示的最后一个1变成0 + * 因此重复该操作,直到x变成0,就可以得到x中1的数量 + * 速度击败41.7% 内存击败28.3% 2ms + * 时间复杂度O(nlogn) + * @param n + * @return + */ + public int[] countBits1(int n) { + int[] bits = new int[n + 1]; + for (int i = 0; i <= n; i++) { + bits[i] = countOnes(i); + } + return bits; + } + + public int countOnes(int x) { + int ones = 0; + while (x > 0) { + x &= (x - 1); + ones++; + } + return ones; + } + + + /** + * 官方题解:动态规划法:最低位有效值 + * 即如果x为偶数,bit[x]=bit[x/2] + * 如果x为奇数,bit[x]=bit[x/2]+1 + * 是否加1可以使用对2取余:x 除以 2的余数可以通过 x & 1 得到 + * @param n + * @return + */ + public int[] countBits2(int n) { + int[] bits = new int[n + 1]; + for (int i = 1; i <= n; i++) { + bits[i] = bits[i >> 1] + (i & 1); + } + return bits; + } + + + + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java new file mode 100644 index 0000000..40b3efe --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T85_TopKFrequent.java @@ -0,0 +1,98 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-04-03 11:37 + *@Description: + * TODO 力扣347 前k个高频元素: + * 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 + *@Version: 1.0 + */ +public class T85_TopKFrequent { + + @Test + public void test(){ + int[] nums={4,1,-1,2,-1,2,3}; + System.out.println(topKFrequent(nums,2)); + } + + + /** + * 统计每个单词出现的次数,然后进行堆化 + * 速度击败87.71% 内存击败12.19% 12ms + * @param nums + * @param k + * @return + */ + public int[] topKFrequent(int[] nums, int k) { + + Map map = new HashMap<>();// + for (int num : nums) { + map.put(num, map.getOrDefault(num, 0) + 1); + } + + PriorityQueue queue = new PriorityQueue<>(new Comparator() { + @Override + public int compare(int[] o1, int[] o2) { + return o1[0] != o2[0] ? o2[1] - o1[1] : o2[0] - o1[0]; + } + }); + + for (Map.Entry entry : map.entrySet()) { + queue.add(new int[]{entry.getKey(), entry.getValue()}); + } + + int[] result = new int[k]; + + for (int i = 0; i < k; i++) { + if(!queue.isEmpty()) result[i] = queue.poll()[0]; + } + + return result; + + } + + + /** + * 官方最快:先计算每个数字出现的次数,使用arrayList将相同次数的数字放在一次 + * @param nums + * @param k + * @return + */ + public int[] topKFrequent1(int[] nums, int k) { + int max = Integer.MIN_VALUE,min = Integer.MAX_VALUE; + for(int i : nums){//找出最大最小值 + max = (max < i)?i:max; + min = (min > i)?i:min; + } + if(max==min)return new int[]{nums[0]}; + int times[] = new int[max-min+1];//定义桶大小 + for(int i : nums){ + times[i-min]++;//记录各个数出现的次数 + } + ArrayList count[] = new ArrayList[nums.length];//不同数量对应的数字集合 + for(int i = 0; i < times.length; i++){ + if(times[i] > 0){ + if(count[times[i]] == null){ + count[times[i]] = new ArrayList(); + } + count[times[i]].add(i+min);//相同次数的加在同一个count[i]这种 + } + } + int res[] = new int[k];//答案 + for(int i = count.length-1,j = 0; i >=0 && j < k ; i--){ + if(count[i] != null){ + while(!count[i].isEmpty()){ + res[j++] = count[i].remove(count[i].size()-1); + } + } + } + return res; + } +}