diff --git a/pom.xml b/pom.xml index edaae99..c159d4f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,8 +9,8 @@ 1.0-SNAPSHOT UTF-8 - 1.8 - 1.8 + 21 + 21 diff --git a/src/main/java/cn/whaifree/LCR/LCR001.java b/src/main/java/cn/whaifree/LCR/LCR001.java new file mode 100644 index 0000000..1909a9c --- /dev/null +++ b/src/main/java/cn/whaifree/LCR/LCR001.java @@ -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; + } + } + +} diff --git a/src/main/java/cn/whaifree/LCR/LCR089.java b/src/main/java/cn/whaifree/LCR/LCR089.java new file mode 100644 index 0000000..094bfb5 --- /dev/null +++ b/src/main/java/cn/whaifree/LCR/LCR089.java @@ -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]; + } + } +} diff --git a/src/main/java/cn/whaifree/LCR/LCR090.java b/src/main/java/cn/whaifree/LCR/LCR090.java new file mode 100644 index 0000000..e30d7e2 --- /dev/null +++ b/src/main/java/cn/whaifree/LCR/LCR090.java @@ -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 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; + } + + + } +} diff --git a/src/main/java/cn/whaifree/interview/Meituan/Test01.java b/src/main/java/cn/whaifree/interview/Meituan/Test01.java new file mode 100644 index 0000000..819ec08 --- /dev/null +++ b/src/main/java/cn/whaifree/interview/Meituan/Test01.java @@ -0,0 +1,133 @@ +package cn.whaifree.interview.Meituan; + +import org.junit.Test; + +import java.util.Scanner; + +/** + * + * ... + + * + * @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); + + } + + + +} diff --git a/src/main/java/cn/whaifree/interview/Meituan/Test02.java b/src/main/java/cn/whaifree/interview/Meituan/Test02.java new file mode 100644 index 0000000..b827ef0 --- /dev/null +++ b/src/main/java/cn/whaifree/interview/Meituan/Test02.java @@ -0,0 +1,234 @@ +package cn.whaifree.interview.Meituan; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.*; + +/** + * ... + * + * @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 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 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中的最美味值 + *

+ * 获取最大的k个值,遇到最大的这k个值就必吃 + *

+ * dp[i] = + * 1. 如果values[i]不存在于k大个值,如果这个不吃 dp[i-1] + * 2. 如果吃 dp[i-2] + values[i] + * 3. 如果存在于最大的k个值 dp[i-1] + values[i] + *

+ * 1 2 3 4 5 6 7 + *

+ * 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 priorityQueue = new PriorityQueue<>(k, Comparator.reverseOrder()); + for (int value : values) { + priorityQueue.add(value); + } + + ArrayList 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)); + } + + +} diff --git a/src/main/java/cn/whaifree/leetCode/Array/LeetCode912_SortArrays.java b/src/main/java/cn/whaifree/leetCode/Array/LeetCode912_SortArrays.java new file mode 100644 index 0000000..435c7e2 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/Array/LeetCode912_SortArrays.java @@ -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; + } + + + + + + } + + } +} diff --git a/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode1049.java b/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode1049.java new file mode 100644 index 0000000..7967f09 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode1049.java @@ -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; + } + } +} diff --git a/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode494.java b/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode494.java new file mode 100644 index 0000000..691cb23 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode494.java @@ -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种(因为没有元素,所以只能不选,和为0):dp[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; isum) 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]; + } + } + + +} diff --git a/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode647.java b/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode647.java new file mode 100644 index 0000000..003bafd --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/Dynamic/LeetCode647.java @@ -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 回文 + * + * + * + * 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); + } +} diff --git a/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode376.java b/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode376.java index 629585f..a0038cf 100644 --- a/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode376.java +++ b/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode376.java @@ -1,6 +1,6 @@ package cn.whaifree.leetCode.Greedy; -import jdk.internal.instrumentation.InstrumentationTarget; + import org.junit.Test; /** diff --git a/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode55.java b/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode55.java index ce8b71f..f2493ed 100644 --- a/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode55.java +++ b/src/main/java/cn/whaifree/leetCode/Greedy/LeetCode55.java @@ -2,7 +2,7 @@ package cn.whaifree.leetCode.Greedy; import cn.whaifree.leetCode.Tree.LeetCode94; import org.junit.Test; -import sun.misc.Launcher; + import java.net.URL; diff --git a/src/main/java/cn/whaifree/leetCode/LeetCode/LeetCode4.java b/src/main/java/cn/whaifree/leetCode/LeetCode/LeetCode4.java new file mode 100644 index 0000000..72d392f --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/LeetCode/LeetCode4.java @@ -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; + } + } + + + + +} diff --git a/src/main/java/cn/whaifree/leetCode/LinkedList/LeetCode206.java b/src/main/java/cn/whaifree/leetCode/LinkedList/LeetCode206.java index 3611672..3f3eeae 100644 --- a/src/main/java/cn/whaifree/leetCode/LinkedList/LeetCode206.java +++ b/src/main/java/cn/whaifree/leetCode/LinkedList/LeetCode206.java @@ -1,7 +1,7 @@ package cn.whaifree.leetCode.LinkedList; import cn.whaifree.leetCode.model.ListNode; -import com.sun.jmx.remote.internal.ArrayQueue; + import org.junit.Test; import java.util.List; diff --git a/src/main/java/cn/whaifree/leetCode/Stack/LeetCode946.java b/src/main/java/cn/whaifree/leetCode/Stack/LeetCode946.java new file mode 100644 index 0000000..ba23bec --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/Stack/LeetCode946.java @@ -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 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(); + } + } +} diff --git a/src/main/java/cn/whaifree/leetCode/String/LeetCode5.java b/src/main/java/cn/whaifree/leetCode/String/LeetCode5.java new file mode 100644 index 0000000..17e3024 --- /dev/null +++ b/src/main/java/cn/whaifree/leetCode/String/LeetCode5.java @@ -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; + } + + } + +} diff --git a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode107.java b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode107.java index ff0354f..22019ca 100644 --- a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode107.java +++ b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode107.java @@ -1,7 +1,7 @@ package cn.whaifree.leetCode.Tree; import cn.whaifree.leetCode.model.TreeNode; -import com.sun.org.apache.bcel.internal.generic.NEW; + import org.junit.Test; import java.util.*; diff --git a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode404.java b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode404.java index e108bbc..f42406f 100644 --- a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode404.java +++ b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode404.java @@ -1,7 +1,7 @@ package cn.whaifree.leetCode.Tree; import cn.whaifree.leetCode.model.TreeNode; -import com.sun.org.apache.regexp.internal.RE; + import org.junit.Test; import java.util.Deque; diff --git a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode513.java b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode513.java index 9b95c14..87307d5 100644 --- a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode513.java +++ b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode513.java @@ -1,12 +1,14 @@ package cn.whaifree.leetCode.Tree; import cn.whaifree.leetCode.model.TreeNode; -import javafx.scene.layout.VBox; import org.junit.Test; import java.util.ArrayList; import java.util.Deque; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * @version 1.0 @@ -17,6 +19,16 @@ import java.util.List; public class LeetCode513 { @Test public void test() { + ExecutorService executor = Executors.newFixedThreadPool(5); + executor.submit(new Callable() { + @Override + public Object call() throws Exception { + return null; + } + + }); + + TreeNode root = TreeNode.constructTree(new Integer[]{1}); root.printTree(); System.out.println(new Solution1().findBottomLeftValue(root)); diff --git a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode654.java b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode654.java index 041c242..ebcb430 100644 --- a/src/main/java/cn/whaifree/leetCode/Tree/LeetCode654.java +++ b/src/main/java/cn/whaifree/leetCode/Tree/LeetCode654.java @@ -1,7 +1,7 @@ package cn.whaifree.leetCode.Tree; import cn.whaifree.leetCode.model.TreeNode; -import jdk.nashorn.internal.runtime.RewriteException; + import org.junit.Test; /** diff --git a/src/main/java/cn/whaifree/redo/redoAll/LeetCode203.java b/src/main/java/cn/whaifree/redo/redoAll/LeetCode203.java new file mode 100644 index 0000000..eaa2cb3 --- /dev/null +++ b/src/main/java/cn/whaifree/redo/redoAll/LeetCode203.java @@ -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; + } + } +} diff --git a/src/main/java/cn/whaifree/redo/redoAll/LeetCode206.java b/src/main/java/cn/whaifree/redo/redoAll/LeetCode206.java new file mode 100644 index 0000000..6ed6a8f --- /dev/null +++ b/src/main/java/cn/whaifree/redo/redoAll/LeetCode206.java @@ -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); + } + + } +} diff --git a/src/main/java/cn/whaifree/redo/redo_24_2_22/LeetCode206.java b/src/main/java/cn/whaifree/redo/redo_24_2_22/LeetCode206.java index 84295bd..cd67daf 100644 --- a/src/main/java/cn/whaifree/redo/redo_24_2_22/LeetCode206.java +++ b/src/main/java/cn/whaifree/redo/redo_24_2_22/LeetCode206.java @@ -1,12 +1,8 @@ package cn.whaifree.redo.redo_24_2_22; 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 java.util.List; - /** * @version 1.0 * @Author whai文海 diff --git a/src/main/java/cn/whaifree/redo/redo_24_3_1/LeetCode45.java b/src/main/java/cn/whaifree/redo/redo_24_3_1/LeetCode45.java index 335544a..3a70444 100644 --- a/src/main/java/cn/whaifree/redo/redo_24_3_1/LeetCode45.java +++ b/src/main/java/cn/whaifree/redo/redo_24_3_1/LeetCode45.java @@ -2,7 +2,6 @@ package cn.whaifree.redo.redo_24_3_1; import org.junit.Test; -import javax.annotation.PreDestroy; /** * @version 1.0 diff --git a/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode236.java b/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode236.java new file mode 100644 index 0000000..1097bf5 --- /dev/null +++ b/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode236.java @@ -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; + } + } + } +} diff --git a/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode376.java b/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode376.java new file mode 100644 index 0000000..f1532c8 --- /dev/null +++ b/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode376.java @@ -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; + } + } +} diff --git a/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode416.java b/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode416.java new file mode 100644 index 0000000..4ea3fab --- /dev/null +++ b/src/main/java/cn/whaifree/redo/redo_24_3_16/LeetCode416.java @@ -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] = max(dp[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; + } + } +}