diff --git "a/src/main/java/algorithm_practice/LeetCode/code000/H051_N\347\232\207\345\220\216.java" "b/src/main/java/algorithm_practice/LeetCode/code000/H051_N\347\232\207\345\220\216.java" new file mode 100644 index 00000000..92e99775 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code000/H051_N\347\232\207\345\220\216.java" @@ -0,0 +1,167 @@ +package algorithm_practice.LeetCode.code000; + +import com.google.common.collect.Lists; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/* +n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + + [".Q..", + "...Q", + "Q...", + "..Q."] + +上图为 8 皇后问题的一种解法。 + +给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + +每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + +  + +示例: + +输入:4 +输出:[ + [".Q..", // 解法 1 + "...Q", + "Q...", + "..Q."], + + ["..Q.", // 解法 2 + "Q...", + "...Q", + ".Q.."] +] +解释: 4 皇后问题存在两个不同的解法。 +  + +提示: + +皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。 + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/n-queens +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class H051_N皇后 { + + @Test + public void testCase() { + int n = 4; + List> excepted = Lists.newArrayList( + Lists.newArrayList(".Q..", "...Q", "Q...", "..Q."), + Lists.newArrayList(".Q..", "...Q", "Q...", "..Q.") + ); + + List> result = solveNQueens(n); + Assert.assertEquals(excepted, result); + } + + public List> solveNQueens(int n) { + List> result = new ArrayList<>(); + List path = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < n; j++) { + sb.append("."); + } + path.add(sb.toString()); + } + + return backTrack(result, path, 0); + } + + // 路径:第 row 行之前,都已经放置好 Q 了 + // 选择列表:row 这一行的所有列 + // 结束条件:row == path.size + private List> backTrack(List> result, List path, int row) { + if (row == path.size()) { + result.add(newArrayList(path.iterator())); + return result; + } + + for (int column = 0; column < path.get(0).length(); column++) { + if (!isValid(path, row, column)) { + continue; + } + + path = putQueen(path, row, column); + + backTrack(result, path, row + 1); + + path = popQueen(path, row, column); + + } + return result; + } + + private List popQueen(List path, int row, int column) { + return changeQ(path, row, column, '.'); + } + + private List putQueen(List path, int row, int column) { + return changeQ(path, row, column, 'Q'); + } + + private List changeQ(List path, int row, int column, char c) { + char[] chars = path.get(row).toCharArray(); + chars[column] = c; + + List result = new ArrayList<>(); + for (int i = 0; i < path.size(); i++) { + if (i == row) { + result.add(String.valueOf(chars)); + continue; + } + result.add(path.get(i)); + } + + return result; + } + + private boolean isValid(List path, int row, int column) { + for (int i = 0; i < path.size(); i++) { // 行 + String rowList = path.get(i); + for (int j = 0; j < rowList.length(); j++) { // 列 + + // 第 column 列有 Q + if (j == column && 'Q' == rowList.charAt(j)) { + return false; + } + + // 左前右下方向 有 Q + if (i != row && column != j + && row - i == column - j + && 'Q' == rowList.charAt(j)) { + return false; + } + + // 右上左下方向 有 Q + if (i != row && column != j + && row - i == j - column + && 'Q' == rowList.charAt(j)) { + return false; + } + } + } + return true; + } + + private List newArrayList(Iterator iterator) { + List result = new ArrayList<>(); + + while (iterator.hasNext()) { + result.add(iterator.next()); + } + + return result; + } +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code000/M046_\345\205\250\346\216\222\345\210\227.java" "b/src/main/java/algorithm_practice/LeetCode/code000/M046_\345\205\250\346\216\222\345\210\227.java" new file mode 100644 index 00000000..7498a4e3 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code000/M046_\345\205\250\346\216\222\345\210\227.java" @@ -0,0 +1,111 @@ +package algorithm_practice.LeetCode.code000; + +import com.google.common.collect.Lists; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/* +给定一个 没有重复 数字的序列,返回其所有可能的全排列。 + +示例: + +输入: [1,2,3] +输出: +[ + [1,2,3], + [1,3,2], + [2,1,3], + [2,3,1], + [3,1,2], + [3,2,1] +] + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/permutations +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class M046_全排列 { + + @Test + public void testCase() { + int[] nums = new int[]{1,2,3}; + List> excepted = Lists.newArrayList( + Lists.newArrayList(1,2,3), + Lists.newArrayList(1,3,2), + Lists.newArrayList(2,1,3), + Lists.newArrayList(2,3,1), + Lists.newArrayList(3,1,2), + Lists.newArrayList(3,2,1)); + List> result = permute(nums); + Assert.assertEquals(excepted, result); + + } + + /* + 回溯框架 + + result = [] + + def backtrack(路径,选择列表) { + if (满足借宿条件) { + result.add(选择); + } + + for 选择 in 选择列表: + if 选择不满足当前选择条件: + continue; + + 做选择; + backtrace(路径, 选择列表); + 撤销选择; + + } + + */ + + public List> permute(int[] nums) { + List> result = new ArrayList<>(); + List path = new ArrayList<>(); + + return backTrack(result, path, nums); + } + + private List> backTrack(List> result, List path, int[]nums) { + if (path.size() == nums.length) { + result.add(newArrayList(path.iterator())); + return result; + } + + for (int i = 0; i < nums.length; i++) { + int num = nums[i]; + if (path.contains(num)) { + continue; + } + + path.add(num); + + backTrack(result, path, nums); + + path.remove(path.size()-1); + } + + return result; + } + + private List newArrayList(Iterator iterator) { + ArrayList list = new ArrayList<>(); + + while(iterator.hasNext()) { + list.add(iterator.next()); + } + + return list; + } + +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code000/M047_\345\205\250\346\216\222\345\210\2272.java" "b/src/main/java/algorithm_practice/LeetCode/code000/M047_\345\205\250\346\216\222\345\210\2272.java" new file mode 100644 index 00000000..b2825fe1 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code000/M047_\345\205\250\346\216\222\345\210\2272.java" @@ -0,0 +1,84 @@ +package algorithm_practice.LeetCode.code000; + +import com.google.common.collect.Lists; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/* +给定一个可包含重复数字的序列,返回所有不重复的全排列。 + +示例: + +输入: [1,1,2] +输出: +[ + [1,1,2], + [1,2,1], + [2,1,1] +] + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/permutations-ii +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class M047_全排列2 { + + @Test + public void testCase() { + int[] nums = new int[]{1,1,2}; + List> excepted = Lists.newArrayList( + Lists.newArrayList(1,1,2), + Lists.newArrayList(1,2,1), + Lists.newArrayList(2,1,1)); + List> result = permuteUnique(nums); + Assert.assertEquals(excepted, result); + + + } + + public List> permuteUnique(int[] nums) { + List> result = new ArrayList<>(); + List path = new ArrayList<>(); + boolean[] used = new boolean[nums.length]; + + return backTrack(result, path, nums, used); + } + + private List> backTrack(List> result, List path, int[] nums, boolean[] used) { + if (path.size() == nums.length) { + if (!result.contains(path)) { + result.add(newArrayList(path.iterator())); + } + return result; + } + + for (int i = 0; i < nums.length; i++) { + if (used[i]) { + continue; + } + + used[i] = true; + path.add(nums[i]); + + backTrack(result, path, nums, used); + + used[i] = false; + path.remove(path.size() - 1); + } + + return result; + } + + private List newArrayList(Iterator iterator) { + List result = new ArrayList<>(); + while (iterator.hasNext()) { + result.add(iterator.next()); + } + return result; + } +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code100/E104_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" "b/src/main/java/algorithm_practice/LeetCode/code100/E104_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" new file mode 100644 index 00000000..32f708af --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code100/E104_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\244\247\346\267\261\345\272\246.java" @@ -0,0 +1,97 @@ +package algorithm_practice.LeetCode.code100; + +import common.datastruct.TreeNode; +import common.util.ConstructBinaryTree; +import org.junit.Assert; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/* +给定一个二叉树,找出其最大深度。 + +二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 + +说明: 叶子节点是指没有子节点的节点。 + +示例: +给定二叉树 [3,9,20,null,null,15,7], + + 3 + / \ + 9 20 + / \ + 15 7 +返回它的最大深度 3 。 + + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class E104_二叉树的最大深度 { + + @Test + public void testCase() { + Integer[] BFSArray = {3,9,20,null,null,15,7}; + TreeNode root = ConstructBinaryTree.constructByBFSArray(BFSArray); + int maxDepth = 3; + Assert.assertEquals(maxDepth, maxDepth(root)); + + BFSArray = new Integer[]{2, null, 3, null, 4, null, 5, null, 6}; + root = ConstructBinaryTree.constructByBFSArray(BFSArray); + maxDepth = 5; + Assert.assertEquals(maxDepth, maxDepth(root)); + + BFSArray = new Integer[]{1,2,3,4,null,null,5}; + root = ConstructBinaryTree.constructByBFSArray(BFSArray); + maxDepth = 3; + Assert.assertEquals(maxDepth, maxDepth(root)); + + } + + public int maxDepth(TreeNode root) { + if (root == null) { + return 0; + } + + Queue queue = new LinkedList<>(); + + queue.offer(root); + int deep = 1; + + while (!queue.isEmpty()) { + int size = queue.size(); + + for (int i = 0; i < size; i++) { + TreeNode cur = queue.poll(); + + if (isLeaf(cur)) { + continue; + } + + if (cur.left != null && cur.left.val != null) { + queue.offer(cur.left); + } + + if (cur.right != null && cur.right.val != null) { + queue.offer(cur.right); + } + } + + if (queue.isEmpty()) { + return deep; + } + deep++; + } + + return deep; + } + + private boolean isLeaf(TreeNode cur) { + return (cur.left == null || cur.left.val == null) + && (cur.right == null || cur.right.val == null); + } +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code100/E111_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" "b/src/main/java/algorithm_practice/LeetCode/code100/E111_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" new file mode 100644 index 00000000..6a10a560 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code100/E111_\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\345\260\217\346\267\261\345\272\246.java" @@ -0,0 +1,120 @@ +package algorithm_practice.LeetCode.code100; + +import common.datastruct.TreeNode; +import common.util.ConstructBinaryTree; +import common.util.PrintBinaryTree; +import org.junit.Assert; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/* +给定一个二叉树,找出其最小深度。 + +最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 + +说明:叶子节点是指没有子节点的节点。 + +示例 1: + 3 + / \ + 9 20 + / \ + 15 7 + +输入:root = [3,9,20,null,null,15,7] +输出:2 +示例 2: + +输入:root = [2,null,3,null,4,null,5,null,6] +输出:5 +  + +提示: + +树中节点数的范围在 [0, 105] 内 +-1000 <= Node.val <= 1000 + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/minimum-depth-of-binary-tree +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class E111_二叉树的最小深度 { + + @Test + public void testCase() { + Integer[] BFSArray = {3, 9, 20, null, null, 15, 7}; + TreeNode root = ConstructBinaryTree.constructByBFSArray(BFSArray); + int minDepth = 2; + Assert.assertEquals(minDepth, minDepth(root)); + + BFSArray = new Integer[]{2, null, 3, null, 4, null, 5, null, 6}; + root = ConstructBinaryTree.constructByBFSArray(BFSArray); +// PrintBinaryTree.print(root); + minDepth = 5; + Assert.assertEquals(minDepth, minDepth(root)); + + BFSArray = new Integer[]{1,2,3,4,5}; + root = ConstructBinaryTree.constructByBFSArray(BFSArray); +// PrintBinaryTree.print(root); + minDepth = 2; + Assert.assertEquals(minDepth, minDepth(root)); + + BFSArray = new Integer[]{1,2,3,4,null,null,5}; + root = ConstructBinaryTree.constructByBFSArray(BFSArray); +// PrintBinaryTree.print(root); + minDepth = 3; + Assert.assertEquals(minDepth, minDepth(root)); + + } + + public int minDepth(TreeNode root) { + if (root == null) { + return 0; + } + + Queue queue = new LinkedList<>(); + + queue.offer(root); + int deep = 1; + + while (!queue.isEmpty()) { + int size = queue.size(); + + int currentDeep = deep; + + // 将队列中所有节点想四周扩散 + for (int i = 0; i < size; i++) { + TreeNode cur = queue.poll(); + + if (isLeaf(cur)) { + return Math.min(deep, currentDeep); + } + + // 将相邻节点加入队列 + if (cur.left != null && cur.left.val != null) { + queue.offer(cur.left); + } + if (cur.right != null && cur.right.val != null) { + queue.offer(cur.right); + } + } + + // 更新步数 + currentDeep++; + deep = currentDeep; + } + + return deep; + } + + private boolean isLeaf(TreeNode cur) { + return (null == cur.left || null == cur.left.val) + && (null == cur.right || null == cur.right.val); + } + +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code300/M322_\351\233\266\351\222\261\345\205\221\346\215\242.java" "b/src/main/java/algorithm_practice/LeetCode/code300/M322_\351\233\266\351\222\261\345\205\221\346\215\242.java" new file mode 100644 index 00000000..974a6cfd --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code300/M322_\351\233\266\351\222\261\345\205\221\346\215\242.java" @@ -0,0 +1,103 @@ +package algorithm_practice.LeetCode.code300; + +import com.alibaba.fastjson.JSON; +import junit.framework.TestCase; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/* +给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。 + +你可以认为每种硬币的数量是无限的。 + +  + +示例 1: + +输入:coins = [1, 2, 5], amount = 11 +输出:3 +解释:11 = 5 + 5 + 1 +示例 2: + +输入:coins = [2], amount = 3 +输出:-1 +示例 3: + +输入:coins = [1], amount = 0 +输出:0 +示例 4: + +输入:coins = [1], amount = 1 +输出:1 +示例 5: + +输入:coins = [1], amount = 2 +输出:2 +  + +提示: + +1 <= coins.length <= 12 +1 <= coins[i] <= 231 - 1 +0 <= amount <= 104 + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/coin-change +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class M322_零钱兑换 extends TestCase { + + @Test + public void testCase() { + int[] coins = new int[]{1, 2, 5}; + int amount = 11; + int coinChange = coinChange(coins, amount); + Assert.assertEquals(3, coinChange); + + coins = new int[]{2}; + amount = 3; + coinChange = coinChange(coins, amount); + Assert.assertEquals(-1, coinChange); + + coins = new int[]{1}; + amount = 1; + coinChange = coinChange(coins, amount); + Assert.assertEquals(1, coinChange); + + coins = new int[]{1}; + amount = 2; + coinChange = coinChange(coins, amount); + Assert.assertEquals(2, coinChange); + + } + + public int coinChange(int[] coins, int amount) { + int[] dp = new int[amount+1]; + + // 组成金额0,最少需要0枚硬币。 + dp[0] = 0; + + for (int i = 1; i < dp.length; i++) { + dp[i] = amount + 1; + } + + for (int i = 0; i <= amount; i++) { + + for (int j = 0; j < coins.length; j++) { + int coin = coins[j]; + if (i - coin < 0) { + continue; + } + + dp[i] = Math.min(dp[i], 1 + dp[i-coin]); + } + } + + return dp[amount] == amount + 1 ? -1 : dp[amount]; + } + +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code400/M416_\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" "b/src/main/java/algorithm_practice/LeetCode/code400/M416_\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" new file mode 100644 index 00000000..91238644 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code400/M416_\345\210\206\345\211\262\347\255\211\345\222\214\345\255\220\351\233\206.java" @@ -0,0 +1,161 @@ +package algorithm_practice.LeetCode.code400; + +import junit.framework.TestCase; +import org.junit.Assert; +import org.junit.Test; + +/* +给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 + +注意: + +每个数组中的元素不会超过 100 +数组的大小不会超过 200 +示例 1: + +输入: [1, 5, 11, 5] + +输出: true + +解释: 数组可以分割成 [1, 5, 5] 和 [11]. +  + +示例 2: + +输入: [1, 2, 3, 5] + +输出: false + +解释: 数组不能分割成两个元素和相等的子集. + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/partition-equal-subset-sum +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class M416_分割等和子集 extends TestCase { + + @Test + public void testCase() { + int[] nums = new int[]{1, 5, 11, 5}; + boolean canPartition = canPartition(nums); + Assert.assertEquals(true, canPartition); + + nums = new int[]{1, 2, 3, 5}; + canPartition = canPartition(nums); + Assert.assertEquals(false, canPartition); + + nums = new int[]{2, 2, 1, 1}; + canPartition = canPartition(nums); + Assert.assertEquals(true, canPartition); + + nums = new int[]{2, 2, 3, 5}; + canPartition = canPartition(nums); + Assert.assertEquals(false, canPartition); + + nums = new int[]{1, 1, 1, 1}; + canPartition = canPartition(nums); + Assert.assertEquals(true, canPartition); + + + } + + /** + * 一维数组 + */ + public boolean canPartition(int[] nums) { + if (nums == null || nums.length < 2) { + return false; + } + + if (nums.length == 2) { + return nums[0] == nums[1]; + } + + int sum = nums[0]; + int maxNum = nums[0]; + for (int i = 1; i < nums.length; i++) { + maxNum = Math.max(nums[i], maxNum); + sum += nums[i]; + } + + if (sum % 2 == 1) { + return false; + } + + int target = sum / 2; + if (maxNum > target) { + return false; + } + + boolean[] dp = new boolean[target + 1]; + dp[0] = true; + + for (int j = 1; j <= target; j++) { + dp[j] = j == nums[0]; + } + + int num; + for (int i = 1; i < nums.length; i++) { + num = nums[i]; + for (int j = target; j >= num; j--) { + + dp[j] = dp[j] || dp[j - num]; + } + } + + return dp[target]; + } + + public boolean canPartition_二维数据(int[] nums) { + if (nums == null || nums.length < 2) { + return false; + } + + if (nums.length == 2) { + return nums[0] == nums[1]; + } + + int sum = nums[0]; + int maxNum = nums[0]; + for (int i = 1; i < nums.length; i++) { + maxNum = Math.max(nums[i], maxNum); + sum += nums[i]; + } + + if (sum % 2 == 1) { + return false; + } + + int target = sum / 2; + if (maxNum > target) { + return false; + } + + boolean[][] dp = new boolean[nums.length][target + 1]; + + for (int i = 0; i < dp.length; i++) { + dp[i][0] = true; + } + + for (int j = 1; j <= target; j++) { + dp[0][j] = j == nums[0]; + } + + int num; + for (int i = 1; i < dp.length; i++) { + num = nums[i]; + for (int j = 1; j <= target; j++) { + if (dp[i - 1][j] || j == num) { + dp[i][j] = true; + continue; + } + if (j > num) { + dp[i][j] = dp[i - 1][j - num]; + } + } + } + + return dp[nums.length - 1][target]; + } +} diff --git "a/src/main/java/algorithm_practice/LeetCode/code800/H887_\351\270\241\350\233\213\346\216\211\350\220\275.java" "b/src/main/java/algorithm_practice/LeetCode/code800/H887_\351\270\241\350\233\213\346\216\211\350\220\275.java" new file mode 100644 index 00000000..bcaf85c9 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/code800/H887_\351\270\241\350\233\213\346\216\211\350\220\275.java" @@ -0,0 +1,98 @@ +package algorithm_practice.LeetCode.code800; + +/* +你将获得 K 个鸡蛋,并可以使用一栋从 1 到 N  共有 N 层楼的建筑。 + +每个蛋的功能都是一样的,如果一个蛋碎了,你就不能再把它掉下去。 + +你知道存在楼层 F ,满足 0 <= F <= N 任何从高于 F 的楼层落下的鸡蛋都会碎,从 F 楼层或比它低的楼层落下的鸡蛋都不会破。 + +每次移动,你可以取一个鸡蛋(如果你有完整的鸡蛋)并把它从任一楼层 X 扔下(满足 1 <= X <= N)。 + +你的目标是确切地知道 F 的值是多少。 + +无论 F 的初始值如何,你确定 F 的值的最小移动次数是多少? + +  + +示例 1: + +输入:K = 1, N = 2 +输出:2 +解释: +鸡蛋从 1 楼掉落。如果它碎了,我们肯定知道 F = 0 。 +否则,鸡蛋从 2 楼掉落。如果它碎了,我们肯定知道 F = 1 。 +如果它没碎,那么我们肯定知道 F = 2 。 +因此,在最坏的情况下我们需要移动 2 次以确定 F 是多少。 +示例 2: + +输入:K = 2, N = 6 +输出:3 +示例 3: + +输入:K = 3, N = 14 +输出:4 +  + +提示: + +1 <= K <= 100 +1 <= N <= 10000 + + +来源:力扣(LeetCode) +链接:https://leetcode-cn.com/problems/super-egg-drop +著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +public class H887_鸡蛋掉落 { + + /* + 最小的移动次数: + 考察 二分+线性查找的算法思想 + 并使用动态规划 来最终实验出第一次扔鸡蛋的楼层 + 使结果无限接近最小移动楼层次数 + 最坏情况: + 当只剩下1个鸡蛋时,就不能从中间开始扔了,只能从当前的楼层(1楼)开始一步一步往上扔。 + + */ + public int superEggDrop(int K, int N) { + int[][] dp = new int[101][10001]; + + for (int i = 0; i < 101; i++) { + for (int j = 0; j < 10001; j++) { + dp[i][j] = -1; + } + } + + return eggDrop(dp, K, N); + + } + + private int eggDrop(int[][] dp, int K, int N) { + if (K == 1) { + return N; + } + + if (N <= 0) { + return 0; + } + + if (dp[K][N] != 0) { + return dp[K][N]; + } + + int res = 0; + for (int i = 1; i <= N; i++) { + res = Math.min(res, + Math.max( + superEggDrop(K - 1, i - 1), // 碎了 + superEggDrop(K, N - i) // 没碎 + ) + 1); + } + + dp[K][N] = res; + + return res; + } + +} diff --git "a/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/README.md" "b/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/README.md" new file mode 100644 index 00000000..4dbc9412 --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/README.md" @@ -0,0 +1,3 @@ + +## 动态规划入门 +[M322_零钱兑换.java](../code300/M322_零钱兑换.java) diff --git "a/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/\350\202\241\347\245\250\344\271\260\345\215\226\351\227\256\351\242\230.md" "b/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/\350\202\241\347\245\250\344\271\260\345\215\226\351\227\256\351\242\230.md" new file mode 100644 index 00000000..e69de29b diff --git "a/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/\350\203\214\345\214\205\351\227\256\351\242\230.md" "b/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/\350\203\214\345\214\205\351\227\256\351\242\230.md" new file mode 100644 index 00000000..d82a9beb --- /dev/null +++ "b/src/main/java/algorithm_practice/LeetCode/\345\212\250\346\200\201\350\247\204\345\210\222/\350\203\214\345\214\205\351\227\256\351\242\230.md" @@ -0,0 +1,6 @@ + +## 01背包 +[M416_分割等和子集](../code400/M416_分割等和子集.java) + +## 完全背包 +[M322_零钱兑换](../code300/M322_零钱兑换.java) \ No newline at end of file diff --git a/src/main/java/algorithm_practice/README.md b/src/main/java/algorithm_practice/README.md index e3027d29..6c3c58bb 100644 --- a/src/main/java/algorithm_practice/README.md +++ b/src/main/java/algorithm_practice/README.md @@ -47,11 +47,18 @@ split、正则匹配、 ## 动态规划 - [M096_不同的二叉搜索树的数量](./LeetCode/code000/M096_不同的二叉搜索树的数量.java) - + - [H887_鸡蛋掉落](./LeetCode/code800/H887_鸡蛋掉落.java) + ## 回溯(递归+剪枝) - [M093_复原IP地址](./LeetCode/code000/M093_复原IP地址.java) - [M695_岛屿的最大面积](./LeetCode/code600/M695_岛屿的最大面积.java) - + - **[M046_全排列](./LeetCode/code000/M046_全排列.java)** + - [M047_全排列2](./LeetCode/code000/M047_全排列2.java) + - [H051_N皇后](./LeetCode/code000/H051_N皇后.java) + +## BFS + - [E104_二叉树的最大深度](./LeetCode/code100/E104_二叉树的最大深度.java) + - [E111_二叉树的最小深度](./LeetCode/code100/E111_二叉树的最小深度.java) ## 用HashSet / hash表 - [H128_最长连续序列](./LeetCode/code100/H128_最长连续序列.java) diff --git a/src/main/java/common/datastruct/TreeNode.java b/src/main/java/common/datastruct/TreeNode.java index 55d74757..22ac5427 100644 --- a/src/main/java/common/datastruct/TreeNode.java +++ b/src/main/java/common/datastruct/TreeNode.java @@ -11,4 +11,10 @@ public class TreeNode { public TreeNode(Integer val) { this.val = val; } + + public TreeNode(Integer val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } } diff --git a/src/main/java/common/util/ConstructBinaryTree.java b/src/main/java/common/util/ConstructBinaryTree.java index 66059480..bbf57015 100644 --- a/src/main/java/common/util/ConstructBinaryTree.java +++ b/src/main/java/common/util/ConstructBinaryTree.java @@ -44,6 +44,9 @@ public static TreeNode constructByBFSArray(Integer[] bfsArray) { queue.add(head); while (!queue.isEmpty() && count < bfsArray.length) { TreeNode pop = queue.pop(); + if (pop.val == null) { + continue; + } Integer leftValue = bfsArray[count++]; pop.left = new TreeNode(leftValue); queue.add(pop.left); diff --git a/src/main/test/Main.java b/src/main/test/Main.java index 794e2cb1..2eef98aa 100644 --- a/src/main/test/Main.java +++ b/src/main/test/Main.java @@ -1,3 +1,4 @@ +import com.alibaba.fastjson.JSON; import junit.framework.TestCase; import org.junit.Test; @@ -8,10 +9,31 @@ */ public class Main extends TestCase { + + @Test public void testCase() { - + Object left = null; + String s = JSON.toJSONString(left); + System.out.println(s); } + public String reverseWords(String s) { + String[] split = s.split(" "); + StringBuilder sb = new StringBuilder(); + for (int i=0; i=0; i--) { + sb.append(s.charAt(i)); + } + return sb.toString(); + } } \ No newline at end of file diff --git a/src/main/test/localtest/simpleTest/BooleanTest.java b/src/main/test/localtest/simpleTest/BooleanTest.java new file mode 100644 index 00000000..bfd5eef0 --- /dev/null +++ b/src/main/test/localtest/simpleTest/BooleanTest.java @@ -0,0 +1,13 @@ +package localtest.simpleTest; + +import junit.framework.TestCase; +import org.junit.Test; + +public class BooleanTest extends TestCase { + + @Test + public void testParseBoolean() { + boolean b = Boolean.parseBoolean("1"); + System.out.println(b); + } +} diff --git a/src/main/test/localtest/simpleTest/StringTest.java b/src/main/test/localtest/simpleTest/StringTest.java index 35a9f3e8..1bf3f83e 100644 --- a/src/main/test/localtest/simpleTest/StringTest.java +++ b/src/main/test/localtest/simpleTest/StringTest.java @@ -1,5 +1,7 @@ package localtest.simpleTest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import junit.framework.TestCase; import org.junit.Test; @@ -10,6 +12,14 @@ */ public class StringTest extends TestCase { + @Test + public void testGetLong() { + String str = "{\"bizNo\":\"111\"}"; + JSONObject result = JSON.parseObject(str); + Long bizNo = result.getLong("bizNo"); + System.out.println(bizNo); + } + @Test public void testCase() { String str = "asdf";