This commit is contained in:
whai 2024-03-22 22:57:40 +08:00
parent 99bda3a447
commit a2d5497bae
27 changed files with 1690 additions and 14 deletions

View File

@ -9,8 +9,8 @@
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
</properties> </properties>

View File

@ -0,0 +1,140 @@
package cn.whaifree.LCR;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/21 11:35
* @注释
*/
public class LCR001 {
@Test
public void test() {
int a = 15;
int b = 2;
int c = new Solution1().divide(a, b);
System.out.println(c);
}
class Solution {
/**
* 位运算
* @param a
* @param b
* @return
*/
public int divide(int a, int b) {
/**
* 17/3
* 3<2 2次 一直到 24-12 之间有2^2=4个3剩下的5再 3<2 只要0次则5中有2^0个3
*/
boolean reverse = false;
if ((a < 0 && b > 0) || (a > 0 && b < 0)) {
reverse = true;
}
if (a < 0) {
a = -a;
}
if (b < 0) {
b = -b;
}
int down = 0;
int sum = 0;
int tmp = a;
while (tmp > 0) {
sum += down;
tmp -= down * b;
down = getDown(tmp, b);
}
return reverse ? -sum : sum;
}
/**
*
* @param beDivide
* @param divide
* @return beDivide包含几个divide
*/
public int getDown(int beDivide, int divide) {
int have = 0;
int tmp = divide;
while (tmp < beDivide) {
have++;
tmp = tmp << 2;
}
return 1 << have;
}
}
class Solution1 {
public int divide(int a, int b) {
//特殊情况1, b=1
if (b == 1){
return a;
}
//特殊情况2, b=-1
if (b == -1){
return a == Integer.MIN_VALUE ? Integer.MAX_VALUE : -a;
}
//特殊情况3, a=0
if (a == 0){
return 0;
}
//确定符号
boolean positive = (a ^ b) >= 0;
//为避免溢出, 转换为负数进行计算
a = a < 0 ? a : -a;
b = b < 0 ? b : -b;
//快速相减
/**
* 17/3
* 3<2 2次 一直到 24-12 之间有2^2=4个3剩下的5再 3<2 只要0次则5中有2^0个3
*/
int quotient = 0;
while (a <= b){
int base = 1;
int divisor = b;
//使用减法, 避免溢出
while (a - divisor <= divisor){
divisor <<= 1; // 被除数*2 b=2时 就是 2 4 8 16 不断扩大直到达到a的一半
base <<= 1; // 表示包含的b 被除数的个数后面给他加到quotient中
}
quotient += base;
a -= divisor; // a减去前面已经找到的部分 17 找到了前面的12就17-12=5
}
return positive ? quotient : -quotient;
}
}
class Solution2 {
public int divide(int a, int b) {
// 不考虑越界的写法
int res = 0;
while (a < b) {
int count = 1;//记住有几个要加入
int copyB = b; // 记录每次的总量
while (a - copyB < copyB) {
copyB <<= 1;
count <<= 1;
}
res += count;
a -= copyB;
}
return res;
}
}
}

View File

@ -0,0 +1,54 @@
package cn.whaifree.LCR;
import cn.whaifree.interview.Meituan.Test02;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/21 20:05
* @注释
*/
public class LCR089 {
@Test
public void test() {
int[] values = {2, 7, 9, 3, 1};
int result = new Solution().rob(values);
System.out.println(result);
// 类似题目
new Test02().sugar(values);
}
/**
*
*/
class Solution {
public int rob(int[] values) {
if (values.length == 1) {
return values[0];
}
// dp[i]表示当前最大价值
// dp[i]=max(dp[i-1],dp[i-2]+values[i])
/**
*
* 2,7,9,3,1
* 2 7 11 11 12
*
*/
// 初始化前3个
int[] dp = new int[values.length];
dp[0] = values[0];
dp[1] = Math.max(values[0], values[1]);
for (int i = 2; i < dp.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + values[i]);
}
return dp[values.length - 1];
}
}
}

View File

@ -0,0 +1,55 @@
package cn.whaifree.LCR;
import org.junit.Test;
import java.util.HashMap;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/21 20:16
* @注释
*/
public class LCR090{
@Test
public void test()
{
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put(null, "");
System.out.println(objectObjectHashMap.get(null));
System.out.println(objectObjectHashMap.get("a"));
int[] nums = {1,2,1,1};
System.out.println(new Solution().rob(nums));
}
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
if (nums.length == 2) {
return Math.max(nums[0], nums[1]);
}
return Math.max(
robRange(nums, 0, nums.length - 2),
robRange(nums, 1, nums.length - 1)
);
}
public int robRange(int[] nums, int start, int end) {
int first = nums[start], second = Math.max(nums[start], nums[start + 1]);
for (int i = start + 2; i <= end; i++) {
int temp = second;
second = Math.max(first + nums[i], second);
first = temp;
}
return second;
}
}
}

View File

@ -0,0 +1,133 @@
package cn.whaifree.interview.Meituan;
import org.junit.Test;
import java.util.Scanner;
/**
*
* <a href="https://www.yuque.com/taxing-qarr6/hxitgt/acebypk1uc68zhi2">...</a>
*
* @version 1.0
* @Author whai文海
* @Date 2024/3/19 11:10
* @注释
*/
public class Test01 {
@Test
public void test() {
String s = "CSDFMTMTDSA";
int k = 2;
System.out.println(mt(k, s));
}
/**
* * MT 是美团的缩写因此小美很喜欢这两个字母
* * 现在小美拿到了一个仅由大写字母组成字符串她可以最多操作k次每次可以修改任意一个字符小美想知道操作结束后最多共有多少个"M'和'T'字符?
* * 输入描述
* * 第一行输入两个正整数n,k代表字符串长度和操作次数第二行输入一个长度为n的仅由大写字母组成的字符串1<=k<=n<=10^5
* * 输出描述
* * 输出操作结束后最多共有多少个'M''T'字符
* * 示例 1
* * 输入
* * C++
* * 5 2
* * M鉀锯撂駙拳顰棛薪廈阗摟粒锟惠拱壢草麦耸蟭骚殝騶乳
* * 输出
* * Plain Text
* * A
* * A
* * 说明
* * 修改第三个和第五个字符形成的字符串为 MTTAM这样共有 4 'M''T'
*
* @param k
* @param s
* @return
*/
public int mt(int k, String s) {
int isMt = 0;
char[] chars = s.toCharArray();
for (char aChar : chars) {
if (aChar == 'M' || aChar == 'T') {
isMt++;
}
}
int isNotMt = chars.length - isMt;
if (isNotMt > k) {
return k + isMt;
}else{
return chars.length;
}
}
public static void main(String[] args) {
new Test01().mt2();
// new Test01().mt4();
}
/**
* 小美拿到了一个由正整数组成的数组但其中有一些元素是未知的( 0 来表示)
* 现在小美想知道如果那些未知的元素在区间[,]范围内随机取值的话数组所有元素之和的最小值和最大值分别是多少?
* 共有q次询问
* 输入描述
* 第一行输入两个正整数n,q代表数组大小和询问次数
* 第二行输入n个整数ai其中如果输入ai的为 0那么说明ai是未知的
* 接下来的q行每行输入两个正整数1r代表一次询问
* Plain Text
* 1<=n,q<=10^5
* 0<=ai<=10^9
* 31<=l<=r<=10^9
* 输出描述
* 输出q行每行输出两个正整数代表所有元素之和的最小值和最大值
*/
public void mt2() {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int query = scanner.nextInt();
int[] nums = new int[n];
int sum = 0;
int isZero = 0;
for (int i = 0; i < nums.length; i++) {
int inputNumber = scanner.nextInt();
if (inputNumber==0) isZero++;
nums[i] = inputNumber;
sum += inputNumber;
}
for (int i = 0; i < query; i++) {
int left = scanner.nextInt();
int right = scanner.nextInt();
System.out.println("=====");
System.out.print(sum + left * isZero + " " + (sum + right * isZero));
}
}
public void mt4(int[] nums, int k) {
int sum = 1;
for (int num : nums) {
sum *= num;
}
int ans = 0;
for (int i = 0; i < nums.length; i++) {
int sub = sum / nums[i];
if (nums.length - String.valueOf(sub).lastIndexOf("0") == k) {
ans++;
}
}
System.out.println(ans);
}
}

View File

@ -0,0 +1,234 @@
package cn.whaifree.interview.Meituan;
import org.junit.Assert;
import org.junit.Test;
import java.util.*;
/**
* <a href="https://www.nowcoder.com/discuss/599738882497736704?sourceSSR=search">...</a>
*
* @version 1.0
* @Author whai文海
* @Date 2024/3/21 19:14
* @注释
*/
public class Test02 {
public static void main(String[] args) {
new Test02().test();
}
public void test() {
Scanner scanner = new Scanner(System.in);
int number = scanner.nextInt();
for (int i = 0; i < number; i++) {
int num = scanner.nextInt();
int[] input = new int[num];
for (int j = 0; j < num; j++) {
input[j] = scanner.nextInt();
}
int[] output = new int[num];
for (int j = 0; j < num; j++) {
output[j] = scanner.nextInt();
}
isSuccess(input, output);
}
}
public void isSuccess(int[] input, int[] output) {
LinkedList<Integer> stack = new LinkedList<>();
int index = 0;
for (int i : input) {
stack.push(i);
while (!stack.isEmpty() && stack.peek() == output[index++]) {
stack.pop();
}
}
if (stack.isEmpty()) {
System.out.println("yes");
} else {
System.out.println("no");
}
}
@Test
public void test1() {
int[] input = {1, 2, 3, 4, 5};
int[] output = {4, 5, 3, 2, 1};
System.out.println(new Solution946().validateStackSequences(input, output));
}
class Solution946 {
public boolean validateStackSequences(int[] pushed, int[] popped) {
return success(pushed, popped);
}
public boolean success(int[] input, int[] output) {
LinkedList<Integer> stack = new LinkedList<>();
int index = 0;
for (int i : input) {
stack.push(i);
while (!stack.isEmpty() && stack.peek() == output[index]) {
index++;
stack.pop();
}
}
return stack.isEmpty();
}
}
@Test
public void test2() {
sugar(new int[]{3, 1, 2, 7, 10, 2, 4});
}
/**
* @param values
*/
public void sugar(int[] values) {
// dp[i]表示当前最大价值
// dp[i]=max(dp[i-1],dp[i-3]+values[i])
/**
*
* 3 1 2 7 10 2 4
*
* 3 3 3 10 13 13 14
*
*/
// 初始化前3个
int[] dp = new int[values.length];
int max = 0;
for (int i = 0; i < 3; i++) {
max = Math.max(max, values[i]);
}
for (int i = 0; i < 3; i++) {
dp[i] = max;
}
for (int i = 3; i < dp.length; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 3] + values[i]);
}
System.out.println(Arrays.toString(dp));
}
/**
* dp[i]表示从商品0-i中的最美味值
* <p>
* 获取最大的k个值遇到最大的这k个值就必吃
* <p>
* dp[i] =
* 1. 如果values[i]不存在于k大个值如果这个不吃 dp[i-1]
* 2. 如果吃 dp[i-2] + values[i]
* 3. 如果存在于最大的k个值 dp[i-1] + values[i]
* <p>
* 1 2 3 4 5 6 7
* <p>
* 0 1 2 3 4 5 6
* 1 2 4 6 9 12 16
*
* @param values 美味值
* @param k 允许打破的次数
*/
public int calculateMaxTaste(int[] values, int k) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k, Comparator.reverseOrder());
for (int value : values) {
priorityQueue.add(value);
}
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < k; i++) {
list.add(priorityQueue.poll());
}
int[] dp = new int[values.length];
dp[0] = values[0];
dp[1] = Math.max(values[0], values[1]);
for (int i = 2; i < dp.length; i++) {
if (list.contains(values[i])) {
System.out.println(i + "打破规则:" + values[i]);
dp[i] = dp[i - 1] + values[i]; //打破规则
} else {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + values[i]);
}
}
return dp[values.length - 1];
}
@Test
public void test3() {
int[] values = {1, 2, 3, 4, 5, 6, 7};
int k = 1;
// sugar(values, k);
}
@Test
public void testCalculateMaxTaste() {
Test02 strategy = new Test02();
// 测试用例1
int n1 = 3, k1 = 1;
int[] delicious1 = {1, 2, 3};
Assert.assertEquals(5, strategy.calculateMaxTaste(delicious1, k1));
// 测试用例2
int n2 = 4, k2 = 2;
int[] delicious2 = {1, 2, 3, 4};
Assert.assertEquals(9, strategy.calculateMaxTaste(delicious2, k2));
// 测试用例3
int n3 = 5, k3 = 1;
int[] delicious3 = {1, 3, 2, 4, 5};
Assert.assertEquals(12, strategy.calculateMaxTaste(delicious3, k3));
// 测试用例4
int n4 = 3, k4 = 0;
int[] delicious4 = {3, 1, 2};
Assert.assertEquals(3, strategy.calculateMaxTaste(delicious4, k4));
// 测试用例5
int n5 = 4, k5 = 1;
int[] delicious5 = {1, 1, 1, 1};
Assert.assertEquals(3, strategy.calculateMaxTaste(delicious5, k5));
// 测试用例6
int n6 = 6, k6 = 2;
int[] delicious6 = {5, 2, 4, 1, 3, 6};
Assert.assertEquals(16, strategy.calculateMaxTaste(delicious6, k6));
// 测试用例7
int n7 = 5, k7 = 2;
int[] delicious7 = {2, 3, 1, 5, 4};
Assert.assertEquals(11, strategy.calculateMaxTaste(delicious7, k7));
// 测试用例8
int n8 = 4, k8 = 0;
int[] delicious8 = {4, 3, 2, 1};
Assert.assertEquals(4, strategy.calculateMaxTaste(delicious8, k8));
// 测试用例9
int n9 = 6, k9 = 3;
int[] delicious9 = {2, 1, 5, 3, 6, 4};
Assert.assertEquals(19, strategy.calculateMaxTaste(delicious9, k9));
// 测试用例10
int n10 = 7, k10 = 1;
int[] delicious10 = {1, 2, 3, 4, 5, 6, 7};
Assert.assertEquals(26, strategy.calculateMaxTaste(delicious10, k10));
}
}

View File

@ -0,0 +1,135 @@
package cn.whaifree.leetCode.Array;
import org.junit.Test;
import java.util.Arrays;
/**
*
* 排序算法有这几种
* 常见的排序算法包括但不限于以下这些
* 冒泡排序从第一个元素开始与右侧元素两两比较并交换直到右侧成为有序部分
* 选择排序有序部分在左侧在剩余元素中找到最小的那个元素并与剩余元素中第一个元素交换
* 插入排序有序部分在左侧将剩余元素中第一个元素不断向左交换直到此元素处于有序部分恰当位置
* 希尔排序取一个间隔值距离为间隔值的元素为一组将整个数组分为若干组每组内进行插入排序缩小间隔值并重复直到间隔值为1即所有元素在同一组
*
* @version 1.0
* @Author whai文海
* @Date 2024/3/20 14:20
* @注释
*/
public class LeetCode912_SortArrays {
@Test
public void test() {
int[] nums = {5, 2, 3, 1,647,24,7,2,8,2,8,1,54,13,6,234,45,234,64,745,32,56,44,32,38};
int[] res = new Solution2().sortArray(nums);
System.out.println(Arrays.toString(res));
int[] ints = Arrays.copyOf(res, res.length);
Arrays.sort(nums);
System.out.println(Arrays.equals(ints, nums));
}
class Solution {
/**
* 冒泡
* @param nums
* @return
*/
public int[] sortArray(int[] nums) {
boolean isSwap = false;
for (int i = 0; i < nums.length; i++) {
for (int j = 1; j < nums.length - i; j++) {
if (nums[j] < nums[j - 1]) {
isSwap = true;
int tmp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = tmp;
}
}
if (!isSwap) {
return nums;
}
isSwap = false;
}
return nums;
}
}
class Solution1 {
/**
* 选择排序
* 选择右边区间的最小值与左边替换
* @param nums
* @return
*/
public int[] sortArray(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int minIndex = i;
for (int j = i+1; j < nums.length; j++) {
if (nums[minIndex] > nums[j]) {
minIndex = j;
}
}
// 交换min与i
int tmp = nums[i];
nums[i] = nums[minIndex];
nums[minIndex] = tmp;
}
return nums;
}
}
class Solution2 {
/**
* 插入排序 j不断往前插入替换到合适位置
* @param nums
* @return
*/
public int[] sortArray(int[] nums) {
for (int i = 1; i < nums.length; i++) {
int j = i;
while (j > 0 && nums[j] < nums[j - 1]) {
// 交换j和j-1
int tmp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = tmp;
j--;
}
}
return nums;
}
}
class SolutionQuickSort {
/**
* 插入排序 j不断往前插入替换到合适位置
*
*
* @param nums
* @return
*/
public int[] sortArray(int[] nums) {
return nums;
}
public void part(int[] nums, int start, int end) {
if (start > end) {
return;
}
}
}
}

View File

@ -0,0 +1,114 @@
package cn.whaifree.leetCode.Dynamic;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/18 14:31
* @注释
*/
public class LeetCode1049 {
@Test
public void test() {
int[] stones = {1,2};
int result = new Solution1().lastStoneWeightII(stones);
System.out.println(result);
}
class Solution {
/**
* 背包容量为half让其尽可能装满除非装不下了到装不下了这一部分已经装入的就是拿来碰撞的剩下就是sum-dp[half]-dp[half]
*
* 目标就是让石头的总价值分为两部分
*
* 转换为背包问题
*
* dp[j] 表示 容量为j的背包最多能够容纳多少价值的物品
* - 物品i的价值 stones[i]
* - 物品i的重量 stones[i]
*
* 1 <= stones.length <= 30
* 1 <= stones[i] <= 100
* 初始化为store[half]
*
*
* 递推公式 dp[j] = Math.max(dp[j],dp[j-weight[i]]+value[i])
* 分成两堆石头一堆石头的总重量是dp[half]另一堆就是sum - dp[half]
*
* @param stones
* @return
*/
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int stone : stones) {
sum += stone;
}
int half = sum / 2;
int[] dp = new int[half + 1];
for (int i = 0; i < stones.length; i++) {
for (int j = half; j >= stones[i]; j--) { // 确保背包能够放下
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
// dp[half] 是要被消灭的那两个部分的消灭就*2
return sum - dp[half] * 2;
}
}
class Solution1 {
/**
* half = sum/2
*
*
* dp[i][j] 表示 放入i后容量为j的背包的最大价值
*
* 1. 放入i dp[i][j] = dp[i-1][j-weight[i]]+value[i]
* 2. 不放入i dp[i][j] = dp[i-1][j]
*
* 2 4 1 1 target=4
*
* 0 1 2 3 4
* 0 0 0 2 2 2
* 1 0 0 2 2 2
* 2 0 1 3 3 3
* 3 0 1 4 4 4
*
* @param stones
* @return
*/
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int stone : stones) {
sum += stone;
}
// 计算所有石头的总重量并将其的一半作为目标重量
int half = sum / 2;
int length = stones.length;
int[][] dp = new int[length][half + 1];
for (int i = stones[0]; i <= half; i++) {
dp[0][i] = stones[0];
}
for (int i = 1; i < length; i++) {
for (int j = 1; j <= half ; j++) {
if (j < stones[i]) {
// 放不下 就不放了价值为i-1物品的最大价值
// 当前石头重量大于目标重量无法放入价值等于前i-1个石头的最大价值
dp[i][j] = dp[i - 1][j];
}else {
// 取放入和不放入当前石头两种情况中的最大价值
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i]);
}
}
}
// 返回石头总重量减去最接近目标重量的那堆石头的两倍重量
return sum - dp[length - 1][half] * 2;
}
}
}

View File

@ -0,0 +1,173 @@
package cn.whaifree.leetCode.Dynamic;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/18 16:17
* @注释
*/
public class LeetCode494 {
@Test
public void test()
{
int[] nums = {1,1,1,1,1};
int target = 3;
System.out.println(new Solution2().findTargetSumWays(nums, target));
}
class Solution {
/**
* 背包容量为3
* left+1的数量-right-1的数量 = target
* left-right = target
* left+right = sum right = sum -left
* left = (target + sum)/2
* 表示正数有多少个是固定的就是我们的背包容量
*
*
* 使用nums[i] 里面全是1 装满容量为left的背包有几种方法
*
* if j> nums[i]
* dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i]]
* 不放
* else
* dp[i][j] = dp[i-1][j]
* 1,1,1,1,1
*
* 0 1 2 3 4
* 0 1 1 0 0 0
* 1 0 0 1 0 0
* 2 0 3
* 3
* 4
*
* @param nums
* @param target
* @return
*/
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for (int num : nums) {
sum += num;
}
// 总和还比不过绝对值1不够用
if(sum < Math.abs(target)){
return 0;
}
// left +1的数量 +1的数量必须是整数
if((sum + target) % 2 != 0) {
return 0;
}
int left = (sum + target) >> 1; // (sum + target) / 2;
int length = nums.length;
int[][] dp = new int[length + 1][left + 1];
// 01背包
// i(1 ~ len)表示遍历不一定选 i 个元素j(0 ~ sum) 表示它们的和
dp[0][0] = 1;
for (int i = 1; i <= length; i++) {
for (int j = 0; j <= left; j++) {
// 装不下不选当前元素
if (j - nums[i - 1] < 0) {
dp[i][j] = dp[i - 1][j];
// 可装可不装当前元素可选可不选
} else {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
}
}
}
/**
* 初始化0个元素和为0情况有1种因为没有元素所以只能不选和为0dp[0][0] = 1
* 不选当前元素"部分和"(即j)与之前相同dp[i][j] = dp[i - 1][j]
* 可选可不选不选的情况是2选当前元素的话则之前的状态应为dp[i - 1][j - num]这里的num指的是当前元素的值即代码中的nums[i - 1]二者相加dp[i][j] = dp[i - 1][j] + dp[i - 1][j - num]
*/
return dp[length][left];
}
}
class Solution1 {
public int findTargetSumWays(int[] nums, int S) {
int sum = 0;
for (int num : nums) {
sum += num;
}
// 背包容量为整数sum + S为奇数的话不满足要求
if (((sum + S) & 1) == 1) {
return 0;
}
// 目标和不可能大于总和
if (S > sum) {
return 0;
}
sum = (sum + S) >> 1;
int len = nums.length;
int[][] dp = new int[len + 1][sum + 1];
dp[0][0] = 1;
// 如果迭代部分 j 的初值赋 1 的话就要先初始化 j = 0 的情况
/* int count = 1;
for (int i = 1; i <= len; i++) {
// ±0 均可
if (nums[i - 1] == 0) {
count *= 2;
}
dp[i][0] = count;
} */
// 01背包
// i(1 ~ len)表示遍历不一定选 i 个元素j(0 ~ sum) 表示它们的和
for (int i = 1; i <= len; i++) {
for (int j = 0; j <= sum; j++) {
// 装不下不选当前元素
if (j - nums[i - 1] < 0) {
dp[i][j] = dp[i - 1][j];
// 可装可不装当前元素可选可不选
} else {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];
}
}
}
return dp[len][sum];
}
}
class Solution2 {
public int findTargetSumWays(int[] nums, int S) {
int sum = 0;
for(int i=0; i<nums.length; i++){
sum += nums[i];
nums[i] += nums[i];
}
if(S>sum) return 0;
S += sum;
int[] dp = new int[S+1];
dp[0] = 1;
for(int num: nums){
for(int i=S; i>=0; i--){
if(i-num>=0){
dp[i] = dp[i] + dp[i-num];
}
}
}
return dp[S];
}
}
}

View File

@ -0,0 +1,98 @@
package cn.whaifree.leetCode.Dynamic;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/22 12:36
* @注释
*/
public class LeetCode647 {
class Solution {
/**
* 判断一个子字符串字符串的下表范围[i,j]是否回文
* 依赖于子字符串下表范围[i + 1, j - 1] 是否是回文
*
* 布尔类型的dp[i][j]表示区间范围[i,j] 注意是左闭右闭的子串是否是回文子串
*
* ij两个循环能够覆盖所有循环
* - dp[i][j] 判断是否回文的时候只需要dp[i+1][j-1]是否回文并且s[i]==s[j]
* 当s[i]=s[j]
* 1. i=j 回文
* 2. i+1=j 回文
* 3. dp[i+1][j-1]==true 回文
*
*
* <img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210121171032473-20230310132134822.jpg" alt="">
* dp[i][j]由dp[i+1][j-1]过来所以必须从下到上左到右
*
* @param s
* @return
*/
public int countSubstrings(String s) {
char[] chars = s.toCharArray();
boolean[][] dp = new boolean[chars.length][chars.length];
int res = 0;
for (int i = s.length() - 1; i >= 0; i--) {
for (int j = i; j < s.length(); j++) {
if (chars[i] == chars[j]) {
if (j - i == 1|| i==j || dp[i + 1][j - 1]) {
dp[i][j] = true;
res++;
}
}
}
}
return res;
}
}
class Solution1 {
public int countSubstrings(String s) {
// 中心点向外扩充
// 1个元素可以作为中心点
// 2个元素也能作为中心点
char[] chars = s.toCharArray();
int res = 0;
for (int i = 0; i < chars.length; i++) {
res += subString(chars, i, i);
res += subString(chars, i, i + 1);
}
return res;
}
/**
*
* @param chars
* @param center1 向左扩展的指针
* @param center2 向右扩展的指针
* @return 有几个子串
*/
public int subString(char[] chars, int center1, int center2) {
int res = 0;
while (center1 >= 0 && center2 < chars.length && chars[center1] == chars[center2]) {
center1--;
center2++;
res++;
}
return res;
}
}
@Test
public void test()
{
Solution1 solution = new Solution1();
String s = "aaa";
int res = solution.countSubstrings(s);
System.out.println(res);
}
}

View File

@ -1,6 +1,6 @@
package cn.whaifree.leetCode.Greedy; package cn.whaifree.leetCode.Greedy;
import jdk.internal.instrumentation.InstrumentationTarget;
import org.junit.Test; import org.junit.Test;
/** /**

View File

@ -2,7 +2,7 @@ package cn.whaifree.leetCode.Greedy;
import cn.whaifree.leetCode.Tree.LeetCode94; import cn.whaifree.leetCode.Tree.LeetCode94;
import org.junit.Test; import org.junit.Test;
import sun.misc.Launcher;
import java.net.URL; import java.net.URL;

View File

@ -0,0 +1,95 @@
package cn.whaifree.leetCode.LeetCode;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/21 16:57
* @注释
*/
public class LeetCode4 {
@Test
public void test()
{
Solution2 solution = new Solution2();
int[] nums1 = {1,3};
int[] nums2 = {2};
double medianSortedArrays = solution.findMedianSortedArrays(nums1, nums2);
System.out.println(medianSortedArrays);
}
class Solution1 {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int length = nums1.length + nums2.length;
int middle = length / 2;
int index1 = 0;
int index2 = 0;
boolean flag = false;
while (index1 + index2 < middle - 1) {
if (nums1[index1] < nums2[index2]) {
flag = false;
index1++;
} else {
flag = true;
index2++;
}
}
if (length % 2 != 0) {
return flag ? nums2[index2] : nums1[index1];
}else {
return (double) (nums1[index1] + nums2[index2]) / 2;
}
}
}
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int[] nums = new int[nums1.length + nums2.length];
int indexA = 0;
int indexB = 0;
int index = 0;
while (indexA < nums1.length && indexB < nums2.length) {
if (nums1[indexA] <= nums2[indexB]) {
nums[index++] = nums1[indexA++];
}else {
nums[index++] = nums2[indexB++];
}
}
while (indexA < nums1.length) {
nums[index++] = nums1[indexA++];
}
while (indexB < nums2.length) {
nums[index++] = nums2[indexB++];
}
int length = nums.length;
return length % 2 == 1 ? (double) nums[length / 2] : (double) (nums[length/2 - 1] + nums[length/2]) / 2;
}
}
class Solution2 {
/**
* 二分查找
* @param nums1
* @param nums2
* @return
*/
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
return 1;
}
}
}

View File

@ -1,7 +1,7 @@
package cn.whaifree.leetCode.LinkedList; package cn.whaifree.leetCode.LinkedList;
import cn.whaifree.leetCode.model.ListNode; import cn.whaifree.leetCode.model.ListNode;
import com.sun.jmx.remote.internal.ArrayQueue;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;

View File

@ -0,0 +1,37 @@
package cn.whaifree.leetCode.Stack;
import org.junit.Test;
import java.util.LinkedList;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/21 19:38
* @注释
*/
public class LeetCode946 {
@Test
public void test() {
new Solution().validateStackSequences(new int[]{1, 2, 3, 4, 5}, new int[]{4, 5, 3, 2, 1});
}
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
return success(pushed, popped);
}
public boolean success(int[] input, int[] output) {
LinkedList<Integer> stack = new LinkedList<>();
int index = 0;
for (int i : input) {
stack.push(i);
while (!stack.isEmpty() && stack.peek() == output[index]) {
index++;
stack.pop();
}
}
return stack.isEmpty();
}
}
}

View File

@ -0,0 +1,102 @@
package cn.whaifree.leetCode.String;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/22 12:16
* @注释
*/
public class LeetCode5 {
@Test
public void test()
{
Solution1 solution = new Solution1();
String s = "cbbd";
String s1 = solution.longestPalindrome(s);
System.out.println(s1);
}
class Solution {
/**
* 动态规划
* dp[i][j] 表示 i-j的串是不是回文串
* 同时记录i和j的最大差值的i和j
*
* s[i] = s[j]
* dp[i][j] =
* 1. i=j true
* 2. i=j+1 true
* 3. if(dp[i+1][j-1]) true
*
*
* @param s
* @return
*/
public String longestPalindrome(String s) {
int length = s.length();
boolean[][] dp = new boolean[length][length];
int maxI = 0;
int maxJ = 0;
// dp[i+1][j-1] 决定了dp[i][j] 所以 要从下往上从左往右遍历
for (int i = length; i >= 0; i--) {
for (int j = i; j < length; j++) {
if (s.charAt(i) == s.charAt(j) && (i == j || i + 1 == j || dp[i + 1][j - 1])) {
if ((maxJ - maxI) <= j - i) {
maxI = i;
maxJ = j;
}
dp[i][j] = true;
}
}
}
return s.substring(maxI, maxJ+1);
}
}
class Solution1 {
public String longestPalindrome(String s) {
char[] chars = s.toCharArray();
// 向外扩展统计回文长度
int length = s.length();
int start = 0;
int end = 0;
for (int i = 0; i < length; i++) {
int a = getHuiWenLengthReturnLength(chars, i, i);
int b = getHuiWenLengthReturnLength(chars, i, i + 1);
int maxLength = Math.max(a, b);
if (maxLength > end - start){
start = i - (maxLength - 1) / 2;
end = i + maxLength / 2;
}
}
return s.substring(start, end + 1);
}
public String getHuiWenLength(char[] chars, int left, int right) {
while (left >= 0 && right < chars.length && chars[left] == chars[right]) {
left--;
right++;
}
return new String(chars, left + 1, right - left - 1);
}
public int getHuiWenLengthReturnLength(char[] chars, int left, int right) {
while (left >= 0 && right < chars.length && chars[left] == chars[right]) {
left--;
right++;
}
return right - left - 1;
}
}
}

View File

@ -1,7 +1,7 @@
package cn.whaifree.leetCode.Tree; package cn.whaifree.leetCode.Tree;
import cn.whaifree.leetCode.model.TreeNode; import cn.whaifree.leetCode.model.TreeNode;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.junit.Test; import org.junit.Test;
import java.util.*; import java.util.*;

View File

@ -1,7 +1,7 @@
package cn.whaifree.leetCode.Tree; package cn.whaifree.leetCode.Tree;
import cn.whaifree.leetCode.model.TreeNode; import cn.whaifree.leetCode.model.TreeNode;
import com.sun.org.apache.regexp.internal.RE;
import org.junit.Test; import org.junit.Test;
import java.util.Deque; import java.util.Deque;

View File

@ -1,12 +1,14 @@
package cn.whaifree.leetCode.Tree; package cn.whaifree.leetCode.Tree;
import cn.whaifree.leetCode.model.TreeNode; import cn.whaifree.leetCode.model.TreeNode;
import javafx.scene.layout.VBox;
import org.junit.Test; import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/** /**
* @version 1.0 * @version 1.0
@ -17,6 +19,16 @@ import java.util.List;
public class LeetCode513 { public class LeetCode513 {
@Test @Test
public void test() { public void test() {
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
return null;
}
});
TreeNode root = TreeNode.constructTree(new Integer[]{1}); TreeNode root = TreeNode.constructTree(new Integer[]{1});
root.printTree(); root.printTree();
System.out.println(new Solution1().findBottomLeftValue(root)); System.out.println(new Solution1().findBottomLeftValue(root));

View File

@ -1,7 +1,7 @@
package cn.whaifree.leetCode.Tree; package cn.whaifree.leetCode.Tree;
import cn.whaifree.leetCode.model.TreeNode; import cn.whaifree.leetCode.model.TreeNode;
import jdk.nashorn.internal.runtime.RewriteException;
import org.junit.Test; import org.junit.Test;
/** /**

View File

@ -0,0 +1,34 @@
package cn.whaifree.redo.redoAll;
import cn.whaifree.leetCode.model.ListNode;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/20 14:01
* @注释
*/
public class LeetCode203 {
@Test
public void main() {
new Solution().removeElements(ListNode.listNodeFromArray(new int[]{1, 2, 6, 3, 4, 5, 6}), 6).printList();
}
class Solution {
public ListNode removeElements(ListNode head, int val) {
if (head == null) {
return null;
}
head.next = removeElements(head.next, val);
if (head.val == val) {
return head.next;
}
return head;
}
}
}

View File

@ -0,0 +1,35 @@
package cn.whaifree.redo.redoAll;
import cn.whaifree.leetCode.model.ListNode;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/20 14:06
* @注释
*/
public class LeetCode206 {
@Test
public void test() {
ListNode listNode = new Solution().reverseList(ListNode.listNodeFromArray(new int[]{1, 2, 3, 4, 5}));
listNode.printList();
}
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
public ListNode reverse(ListNode before, ListNode after) {
if (after == null) {
return before;
}
ListNode tmp = after.next;
after.next = before;
return reverse(after, tmp);
}
}
}

View File

@ -1,12 +1,8 @@
package cn.whaifree.redo.redo_24_2_22; package cn.whaifree.redo.redo_24_2_22;
import cn.whaifree.leetCode.model.ListNode; import cn.whaifree.leetCode.model.ListNode;
import cn.whaifree.leetCode.model.TreeNode;
import com.sun.xml.internal.ws.server.sei.ValueGetter;
import org.junit.Test; import org.junit.Test;
import java.util.List;
/** /**
* @version 1.0 * @version 1.0
* @Author whai文海 * @Author whai文海

View File

@ -2,7 +2,6 @@ package cn.whaifree.redo.redo_24_3_1;
import org.junit.Test; import org.junit.Test;
import javax.annotation.PreDestroy;
/** /**
* @version 1.0 * @version 1.0

View File

@ -0,0 +1,44 @@
package cn.whaifree.redo.redo_24_3_16;
import cn.whaifree.leetCode.model.TreeNode;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/17 15:56
* @注释
*/
public class LeetCode236 {
@Test
public void test() {
new Solution().lowestCommonAncestor(TreeNode.constructTreeByArray(1, 2, 3, 4, 5, 6), new TreeNode(4), new TreeNode(5)).printTree();
}
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
if (root.val == p.val || root.val == q.val) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left != null && right != null) {
return root;
}
if (left == null) {
return right;
}else {
return left;
}
}
}
}

View File

@ -0,0 +1,44 @@
package cn.whaifree.redo.redo_24_3_16;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/17 16:09
* @注释
*/
public class LeetCode376 {
@Test
public void test() {
int[] nums = {0,0,0};
int res = new Solution().wiggleMaxLength(nums);
System.out.println(res);
}
class Solution {
public int wiggleMaxLength(int[] nums) {
if (nums.length < 2) {
return 1;
}
// 记录前一个的正负
// 后一个如果和前一个是相反的 res++ 并且相反值变换
// 不是相反的 不处理
int pre = 0;
int cur = 0;
int res = 1;
for (int i = 1; i < nums.length; i++) {
cur = nums[i] - nums[i - 1];
// pre=0 确保第一次能够进去
if ((cur > 0 && pre <= 0) || (cur < 0 && pre >= 0)) {
res++;
pre = cur;
}
}
return res;
}
}
}

View File

@ -0,0 +1,142 @@
package cn.whaifree.redo.redo_24_3_16;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/3/17 17:04
* @注释
*/
public class LeetCode416 {
@Test
public void test() {
int[] nums = {1, 5, 11, 5};
boolean canPartition = new Solution().canPartition(nums);
System.out.println(canPartition);
}
class Solution {
/**
* 0-1背包问题
*
* dp[i][j] 表示 放入物品i后容量为j的背包的最大价值
*
* 背包容量为sum/2
* 物品重量为nums[i]
* 物品价值为nums[i]
*
* [3,5,11,5]
*
* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1
* 0 0 0 0 3 3
* 1
* 2
*
*
*
* @param nums
* @return
*/
public boolean canPartition(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum % 2 != 0) {
return false;
}
int half = sum / 2;
int length = nums.length;
int[][] dp = new int[length][half+1];
for (int i = nums[0]; i <= half; i++) {
dp[0][i] = nums[0];
}
// dp[i][j] 表示 放入物品i后容量为j的背包的最大价值
for (int i = 1; i < length; i++) {
for (int j = 1; j <= half; j++) {
// 放的下
if (j >= nums[i]) {
dp[i][j] = Math.max(
dp[i - 1][j],
dp[i - 1][j - nums[i]] + nums[i]
);
}else {
dp[i][j] = dp[i - 1][j];
}
// 放不下
if (dp[i][j] == half) {
return true;
}
}
}
return false;
}
}
class Solution1 {
/**
* 将nums的元素放入背包中
* 1. 背包容量 sum/2
* 2. 物品i重量nums[i]价值nums[i]
*
* 0 1 2 3 4 5
* 0
* 1
* 2
*
* dp[j]表示 j背包容量的最大价值
*
*
*
* // 递推公式
* 2. 放下 dp[j] = maxdp[j], dp[j-weight[i]]+nums[i]
*
* 从后往前循环每次取得状态不会和之前取得状态重合这样每种物品就只取一次了
*
* @param nums
* @return
*/
public boolean canPartition(int[] nums) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum % 2 != 0) {
return false;
}
// 包裹最大容量
int packageCapacity = sum / 2;
int[] dp = new int[packageCapacity + 1];
for (int i = 0; i < nums.length; i++) {
// 包的容量必须大于物品i重量才能放进去
/**
* 如果正序遍历
* dp[1] = dp[1 - weight[0]] + value[0] = 15
* 此时容量1的背包已经放入了
* dp[2] = dp[2 - weight[0]] + value[0] = 30
* 此时又放入了一次
*/
for (int j = packageCapacity; j >= nums[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
//剪枝一下每一次完成內層的for-loop立即檢查是否dp[target] == target優化時間複雜度26ms -> 20ms
if(dp[packageCapacity] == packageCapacity)
return true;
}
}
// 包裹容量和目标值一样
return dp[packageCapacity] == packageCapacity;
}
}
}