leecode更新

This commit is contained in:
markilue 2023-04-03 12:56:21 +08:00
parent ebbaae5e7f
commit e804dbb23b
6 changed files with 359 additions and 2 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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];
}
}

View File

@ -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};
}
}

View File

@ -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 & (x1) 这一运算将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;
}
}

View File

@ -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<Integer, Integer> map = new HashMap<>();//<nums,count>
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);
}
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[0] != o2[0] ? o2[1] - o1[1] : o2[0] - o1[0];
}
});
for (Map.Entry<Integer, Integer> 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<Integer> 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;
}
}