From 7ca46e81d2485bece04350081369bee87a21aae4 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Sun, 25 Oct 2020 00:31:13 +0800 Subject: [PATCH 01/63] =?UTF-8?q?znn=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/chen/algorithm/znn/array/Test.java | 9 + .../znn/array/offer/test29/Solution.java | 87 ++++++++ .../algorithm/znn/array/test1/Solution.java | 47 +++++ .../algorithm/znn/array/test238/Solution.java | 110 ++++++++++ .../algorithm/znn/array/test240/Solution.java | 59 ++++++ .../algorithm/znn/array/test26/Solution.java | 36 ++++ .../algorithm/znn/array/test27/Solution.java | 32 +++ .../znn/array/test283/Solution2.java | 48 +++++ .../algorithm/znn/array/test34/Solution.java | 83 ++++++++ .../algorithm/znn/array/test448/Solution.java | 61 ++++++ .../algorithm/znn/array/test56/Solution.java | 69 ++++++ .../algorithm/znn/array/test581/Solution.java | 48 +++++ .../algorithm/znn/array/test69/Solution.java | 41 ++++ .../algorithm/znn/array/test704/Solution.java | 197 ++++++++++++++++++ .../algorithm/znn/array/test88/Solution.java | 40 ++++ .../chen/algorithm/znn/backtrack/Test.java | 9 + .../java/com/chen/algorithm/znn/bfs/Test.java | 9 + .../com/chen/algorithm/znn/bitmap/Test.java | 9 + .../java/com/chen/algorithm/znn/dfs/Test.java | 9 + .../com/chen/algorithm/znn/divide/Test.java | 9 + .../com/chen/algorithm/znn/dynamic/Test.java | 9 + .../chen/algorithm/znn/frequency/Test.java | 9 + .../znn/frequency/test48/Solution.java | 56 +++++ .../znn/frequency/test7/Solution.java | 25 +++ .../znn/frequency/test9/Solution.java | 34 +++ .../com/chen/algorithm/znn/greedy/Test.java | 9 + .../com/chen/algorithm/znn/hash/Test.java | 9 + .../algorithm/znn/hash/test242/Solution.java | 40 ++++ .../com/chen/algorithm/znn/heap/Test.java | 9 + .../algorithm/znn/linkedlist/ListNode.java | 26 +++ .../chen/algorithm/znn/linkedlist/Test.java | 9 + .../znn/linkedlist/test141/Solution.java | 79 +++++++ .../znn/linkedlist/test142/Solution.java | 67 ++++++ .../znn/linkedlist/test160/Solution.java | 57 +++++ .../znn/linkedlist/test19/Solution.java | 126 +++++++++++ .../znn/linkedlist/test2/Solution.java | 69 ++++++ .../znn/linkedlist/test206/Solution.java | 55 +++++ .../znn/linkedlist/test21/Solution.java | 69 ++++++ .../znn/linkedlist/test24/Solution.java | 105 ++++++++++ .../znn/linkedlist/test25/Solution.java | 94 +++++++++ .../znn/linkedlist/test83/Solution.java | 39 ++++ .../znn/linkedlist/test92/Solution.java | 112 ++++++++++ .../chen/algorithm/znn/recursion/Test.java | 9 + .../com/chen/algorithm/znn/sort/Test.java | 9 + .../com/chen/algorithm/znn/stack/Test.java | 9 + .../com/chen/algorithm/znn/string/Test.java | 9 + .../com/chen/algorithm/znn/tree/Test.java | 9 + 47 files changed, 2164 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/array/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test1/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test238/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test240/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test26/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test27/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test283/Solution2.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test34/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test448/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test56/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test581/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test69/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test704/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test88/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/bfs/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/bitmap/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/dfs/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/divide/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/greedy/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/hash/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/heap/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/ListNode.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/recursion/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/sort/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/string/Test.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/Test.java diff --git a/src/main/java/com/chen/algorithm/znn/array/Test.java b/src/main/java/com/chen/algorithm/znn/array/Test.java new file mode 100644 index 0000000..f73d528 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.array; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 数组相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java new file mode 100644 index 0000000..6cc9963 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java @@ -0,0 +1,87 @@ +package com.chen.algorithm.znn.array.offer.test29; + +import java.util.Arrays; + +/** + * @Auther: zhunn + * @Date: 2020/10/10 13:58 + * @Description: 顺时针从外往里打印矩阵(螺旋矩阵,力扣第54题) + */ +public class Solution { + + public static int[] spiralOrder(int[][] matrix) { + if (matrix.length == 0) { + return new int[0]; + } + int[] res = new int[matrix.length * matrix[0].length]; + int u = 0, d = matrix.length - 1, l = 0, r = matrix[0].length - 1; + int idx = 0; + while (true) { + for (int i = l; i <= r; i++) { + res[idx++] = matrix[u][i]; + } + if (++u > d) { + break; + } + for (int i = u; i <= d; i++) { + res[idx++] = matrix[i][r]; + } + if (--r < l) { + break; + } + for (int i = r; i >= l; i--) { + res[idx++] = matrix[d][i]; + } + if (--d < u) { + break; + } + for (int i = d; i >= u; i--) { + res[idx++] = matrix[i][l]; + } + if (++l > r) { + break; + } + } + return res; + } + + private static int[] spiralOrder1(int[][] matrix) { + if (matrix == null || matrix.length == 0) return new int[0]; + + int numEle = matrix.length * matrix[0].length; + int[] result = new int[numEle]; + int idx = 0; + int left = 0, right = matrix[0].length - 1, top = 0, bottom = matrix.length - 1; + + while (numEle >= 1) { + for (int i = left; i <= right && numEle >= 1; i++) { + result[idx++] = matrix[top][i]; + numEle--; + } + top++; + for (int i = top; i <= bottom && numEle >= 1; i++) { + result[idx++] = matrix[i][right]; + numEle--; + } + right--; + for (int i = right; i >= left && numEle >= 1; i--) { + result[idx++] = matrix[bottom][i]; + numEle--; + } + bottom--; + for (int i = bottom; i >= top && numEle >= 1; i--) { + result[idx++] = matrix[i][left]; + numEle--; + } + left++; + } + return result; + } + + public static void main(String[] args) { + int[][] matrix = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; + int[] res = spiralOrder1(matrix); + System.out.println(Arrays.toString(res)); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java new file mode 100644 index 0000000..181ae76 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java @@ -0,0 +1,47 @@ +package com.chen.algorithm.znn.array.test1; + +import com.alibaba.fastjson.JSON; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Auther: zhunn + * @Date: 2020/10/22 19:00 + * @Description: 两数之和 + */ +public class Solution { + + public int[] twoSum1(int[] nums, int target) { + int n = nums.length; + for (int i = 0; i < n; ++i) { + for (int j = i + 1; j < n; ++j) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return new int[0]; + } + + public int[] twoSum2(int[] nums, int target) { + Map hashtable = new HashMap<>(); + for (int i = 0; i < nums.length; ++i) { + if (hashtable.containsKey(target - nums[i])) { + return new int[]{hashtable.get(target - nums[i]), i}; + } + hashtable.put(nums[i], i); + } + return new int[0]; + } + + @Test + public void testCase() { + int[] array = {4, 5, 6, 7, 2}; + + int[] result = twoSum1(array, 9); + System.out.println(JSON.toJSONString(result)); + + } +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java new file mode 100644 index 0000000..7776136 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java @@ -0,0 +1,110 @@ +package com.chen.algorithm.znn.array.test238; + +import com.alibaba.fastjson.JSON; + +/** + * @Auther: zhunn + * @Date: 2020/10/16 14:30 + * @Description: 除自身以外数组的乘积 + */ +public class Solution { + + /** + * 时间复杂度O(N),空间复杂度O(N) + * + * @param nums + * @return + */ + public static int[] productExceptSelf(int[] nums) { + if (nums == null || nums.length == 0) { + return new int[0]; + } + + int length = nums.length; + + // left和right 分别表示左右两侧的乘积列表 + int[] left = new int[length]; + int[] right = new int[length]; + + int[] answer = new int[length]; + + // left[i] 为索引 i 左侧所有元素的乘积 + // 对于索引为 ‘0’ 的元素,因为左侧没有元素,所以left[0]=1 + left[0] = 1; + for (int i = 1; i < length; i++) { + left[i] = left[i - 1] * nums[i - 1]; + } + + // right[i] 为索引 i 右侧所有元素的乘积 + // 对于索引为 ‘length-1’ 的元素,因为右侧没有元素,所以right[length - 1] = 1 + right[length - 1] = 1; + for (int i = length - 2; i >= 0; i--) { + right[i] = right[i + 1] * nums[i + 1]; + } + + // 对于索引i,除nums[i]之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积 + for (int i = 0; i < length; i++) { + answer[i] = left[i] * right[i]; + } + return answer; + } + + /** + * 时间复杂度O(N),空间复杂度O(1) + * + * @param nums + * @return + */ + //public static int[] productExceptSelf1(int[] nums) { + // if (nums == null || nums.length == 0) { + // return new int[0]; + // } + // + // int length = nums.length; + // int[] answer = new int[length]; + // + // // answer[i] 为索引 i 左侧所有元素的乘积 + // // 对于索引为 ‘0’ 的元素,因为左侧没有元素,answer[0]=1 + // answer[0] = 1; + // for (int i = 1; i < length; i++) { + // answer[i] = answer[i - 1] * nums[i - 1]; + // } + // + // // right 为右侧所有元素的乘积 + // // 刚开始右侧没有元素,所以right = 1 + // int right = 1; + // for (int i = length - 1; i >= 0; i--) { + // // 对于索引 i,左边的乘积为answer[i],右边的乘积为right + // answer[i] = right * answer[i]; + // // right 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 right 上 + // right = right * nums[i]; + // } + // return answer; + //} + public static int[] productExceptSelfTest(int[] nums) { + if (nums == null || nums.length == 0) { + return new int[0]; + } + + int length = nums.length; + int[] answer = new int[length]; + + answer[0] = 1; + for (int i = 1; i < length; i++) { + answer[i] = answer[i - 1] * nums[i - 1]; + } + + int right = 1; + for (int i = length - 1; i >= 0; i--) { + answer[i] = right * answer[i]; + right = right * nums[i]; + } + return answer; + } + + public static void main(String[] args) { + int[] nums = {1, 2, 3, 4, 2}; + System.out.println(JSON.toJSONString(productExceptSelf(nums))); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java new file mode 100644 index 0000000..01ff129 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java @@ -0,0 +1,59 @@ +package com.chen.algorithm.znn.array.test240; + +/** + * https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/er-fen-fa-pai-chu-fa-python-dai-ma-java-dai-ma-by-/ + * + * @Author: zhunn + * @Date: 2020-10-22 14:26 + * @Description: 搜索二维矩阵 + */ +public class Solution { + + + /** + * 从左下角开始 + *

+ * 如果当前数比目标元素小,当前列就不可能存在目标值,“指针”就向右移一格(纵坐标加 11); + * 如果当前数比目标元素大,当前行就不可能存在目标值,“指针”就向上移一格(横坐标减 11)。 + * + * @param matrix + * @param target + * @return + */ + public boolean searchMatrix(int[][] matrix, int target) { + + if (matrix == null) { + return false; + } + + int rows = matrix.length; + if (rows == 0) { + return false; + } + + int col = matrix[0].length; + + if (col == 0) { + return false; + } + + int x = rows - 1; + int y = 0; + int value; + + while (x >= 0 && y < col) { + value = matrix[x][y]; + if (value > target) { + x--; + } else if (value < target) { + y++; + } else { + return true; + } + } + + return false; + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java new file mode 100644 index 0000000..336627f --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java @@ -0,0 +1,36 @@ +package com.chen.algorithm.znn.array.test26; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/10 16:23 + * @Description: 删除排序数组中的重复项,返回新数组长度。双指针法 + */ +public class Solution { + + /** + * 双指针法 ,数组是一个引用 + * + * @param nums + * @return + */ + public int removeDuplicates(int[] nums) { + if (nums == null || nums.length == 0) return 0; + + int i = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + //System.out.println(Arrays.toString(nums)); + return i + 1; + } + + @Test + public void test() { + System.out.println(removeDuplicates(new int[]{0, 0, 1, 1, 2, 3, 4, 5, 5, 6})); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java new file mode 100644 index 0000000..e06ce69 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java @@ -0,0 +1,32 @@ +package com.chen.algorithm.znn.array.test27; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @Auther: zhunn + * @Date: 2020/10/10 16:40 + * @Description: 移除元素,双指针法 + */ +public class Solution { + + public int removeElement(int[] nums, int val) { + if (nums == null || nums.length == 0) return 0; + + int i = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] != val) { + nums[i] = nums[j]; + i++; + } + } + System.out.println(Arrays.toString(nums)); + return i; + } + + @Test + public void test() { + System.out.println(removeElement(new int[]{1, 1, 2, 2, 3, 5, 6, 7, 8}, 2)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test283/Solution2.java b/src/main/java/com/chen/algorithm/znn/array/test283/Solution2.java new file mode 100644 index 0000000..38cca62 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test283/Solution2.java @@ -0,0 +1,48 @@ +package com.chen.algorithm.znn.array.test283; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * 移动0 + * @author: zhunn + * @Date: 2019-11-03 18:44 + * @Description: 移动0至末尾 + */ +public class Solution2 { + + /** + * @param nums + * @return + */ + public int[] moveZeroes(int[] nums) { + if (nums == null || nums.length == 0) { + return nums; + } + + int i = 0; + for (int j = 0; j < nums.length; j++) { + if (nums[j] != 0) { + nums[i] = nums[j]; + i++; + } + } + + for (int k = i; k < nums.length; k++) { + nums[k] = 0; + } + return nums; + } + + @Test + public void testCase() { + + int[] n = {0, 1, 0, 3, 12}; + moveZeroes(n); + System.out.println(Arrays.toString(n)); + + + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java new file mode 100644 index 0000000..db762a5 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java @@ -0,0 +1,83 @@ +package com.chen.algorithm.znn.array.test34; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @Auther: zhunn + * @Date: 2020/10/10 17:04 + * @Description: 在排序数组中查找元素的第一个和最后一个位置 + * (可使用二分查找到第一个与target相等元素和最后一个与target相等元素 方式,返回下标) + */ +public class Solution { + + /** + * 当key=array[mid]时, 往左边一个一个逼近,right = mid -1; 返回left + * + * @param nums + * @param target + * @return + */ + private int leftIndex(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = (right - left) / 2 + left; + if (nums[mid] >= target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + if (left <= nums.length - 1 && nums[left] == target) { + return left; + } + return -1; + } + + /** + * 当key=array[mid]时, 往右边一个一个逼近,left = mid + 1; 返回right + * + * @param nums + * @param target + * @return + */ + private int rightIndex(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return -1; + } + int left = 0, right = nums.length - 1; + while (left <= right) { + int mid = (right - left) / 2 + left; + if (nums[mid] <= target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + if (right >= 0 && nums[right] == target) { + return right; + } + return -1; + } + + public int[] find(int[] nums, int target) { + int[] res = new int[2]; + res[0] = leftIndex(nums, target); + res[1] = rightIndex(nums, target); + return res; + } + + @Test + public void test() { + int[] nums = new int[]{5, 7, 7, 8, 8, 8, 10}; + int[] res = find(nums, 8); + System.out.println(Arrays.toString(res)); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java new file mode 100644 index 0000000..5d541ad --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java @@ -0,0 +1,61 @@ +package com.chen.algorithm.znn.array.test448; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/solution/e-wai-liang-ge-intkong-jian-shi-jian-fu-za-du-jin-/ + * + * @author: zhunn + * @Date: 2020-10-04 00:06 + * @@Description: zhunn 找到所有数组中消失的数字 + */ +public class Solution { + + + public List findDisappearedNumbers(int[] nums) { + + int temp = 0; + int nextIndex = 0; + + for (int i = 0; i < nums.length; i++) { + + if (nums[i] > 0) { + temp = nums[i]; + while (temp > 0) { + nums[i] = 0; + nextIndex = nums[temp - 1]; + nums[temp - 1] = -1; + temp = nextIndex; + } + } + + } + + + List result = new ArrayList<>(); + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == 0) { + result.add(i + 1); + } + } + + return result; + } + + + @Test + public void testCase() { + + int[] nums = {4, 3, 2, 7, 8, 2, 3, 1}; + + List list = findDisappearedNumbers(nums); + list.forEach(System.out::println); + + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java new file mode 100644 index 0000000..0dfd005 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java @@ -0,0 +1,69 @@ +package com.chen.algorithm.znn.array.test56; + +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/merge-intervals/solution/pai-xu-by-powcai/ + * + * @author: zhunn + * @Date: 2020-10-14 00:22 + * @Description: 合并区间 + */ +public class Solution { + + + /** + * 先按首位置进行排序; + *

+ * 接下来,如何判断两个区间是否重叠呢?比如 a = [1,4],b = [2,3] + * 当 a[1] >= b[0] 说明两个区间有重叠. + * 但是如何把这个区间找出来呢? + * 左边位置一定是确定,就是 a[0],而右边位置是 max(a[1], b[1]) + * 所以,我们就能找出整个区间为:[1,4] + * + * @param intervals + * @return + */ + + public int[][] merge(int[][] intervals) { + + List inner = Arrays.asList(intervals); + List newInner = new ArrayList<>(inner); + newInner.sort((o1,o2)-> o1[0]-o2[0]); + + List res = new ArrayList<>(); + + for (int i = 0; i < newInner.size(); ) { + int t = newInner.get(i)[1]; + int j = i + 1; + while (j < newInner.size() && newInner.get(j)[0] <= t) { + t = Math.max(t, newInner.get(j)[1]); + j++; + } + res.add(new int[]{newInner.get(i)[0], t}); + i = j; + } + + int[][] array = new int[res.size()][2]; + + for (int i = 0; i < res.size(); i++) { + array[i][0] = res.get(i)[0]; + array[i][1] = res.get(i)[1]; + } + return array; + } + + + @Test + public void testCase() { + + int[][] n = {{1, 3}, {2, 6}, {15, 18}, {8, 10}}; + System.out.println(JSONObject.toJSONString(merge(n))); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java new file mode 100644 index 0000000..39428c0 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java @@ -0,0 +1,48 @@ +package com.chen.algorithm.znn.array.test581; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * + * https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/solution/zui-duan-wu-xu-lian-xu-zi-shu-zu-by-leetcode/ + * + * @author: zhunn + * @Date: 2020-10-07 23:34 + * @Description: 最短无序连续子数组 + */ +public class Solution { + + + public int findUnsortedSubarray(int[] nums) { + if(nums == null || nums.length == 0){ + return 0; + } + + int[] snums = nums.clone(); + Arrays.sort(snums); + int start = snums.length, end = 0; + for (int i = 0; i < snums.length; i++) { + if (snums[i] != nums[i]) { + start = Math.min(start, i); + end = Math.max(end, i); + } + } + return (end - start >= 0 ? end - start + 1 : 0); + } + + + @Test + public void testCase() { + + + int[] n = {2, 6, 4, 8, 10, 9, 15}; + + System.out.println(findUnsortedSubarray(n)); + + + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java new file mode 100644 index 0000000..964bf1c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java @@ -0,0 +1,41 @@ +package com.chen.algorithm.znn.array.test69; + +import org.junit.Test; + +/** + * @author: zhunn + * @Date: 2020-10-03 09:39 + * @Description: x的平方根,舍弃小数 + */ +public class Solution { + + + public int mySqrt(int x) { + + if (x < 2) { + return x; + } + + int left = 1, right = x / 2, mid; + long result; + + while (right >= left) { + mid = (right - left) / 2 + left; + result = (long) mid * mid; + if (result > x) { + right = mid - 1; + } else if (result < x) { + left = mid + 1; + } else { + return mid; + } + } + return right; + } + + @Test + public void test() { + System.out.println(mySqrt(2147395599)); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java new file mode 100644 index 0000000..3aa10a5 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java @@ -0,0 +1,197 @@ +package com.chen.algorithm.znn.array.test704; + +/** + * @Auther: zhunn + * @Date: 2020/10/9 15:31 + * @Description: 二分查找及其变种 https://blog.csdn.net/Lngxling/article/details/78217619 + */ +public class Solution { + + /** + * 适用于升序数组,可做相应调整适用降序数组 + */ + public static int bsearch(int[] array, int target) { + if (array == null || array.length == 0 + /*|| target < array[0] || target > array[array.length - 1]*/) { + return -1; + } + + int left = 0; + int right = array.length - 1; + //这里必须是 >=,切记勿遗漏 = + while (right >= left) { + // 当start=Integer.MAX_VALUE时,给它加个1都会溢出。安全的写法是:mid = start + (end-start)/2,但是会造成死循环,弃用 + //int mid = min + (max - min) >> 1; + int mid = (left + right) >> 1; + if (target == array[mid]) { + return mid; + } + if (target < array[mid]) { + right = mid - 1; + } + if (target > array[mid]) { + left = mid + 1; + } + } + return -1; + } + + /** + * 查找第一个与target相等的元素 + * 当key=array[mid]时, 往左边一个一个逼近,right = mid -1; 返回left + */ + public static int bsearch1(int[] array, int target) { + if (array == null || array.length == 0 + /*|| target < array[0] || target > array[array.length - 1]*/) { + return -1; + } + int left = 0; + int right = array.length - 1; + while (right >= left) { + int mid = (left + right) >> 1; + if (array[mid] >= target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + if (left < array.length && array[left] == target) { + return left; + } + return -1; + + } + + /** + * 查找最后一个与target相等的元素 + * 当key=array[mid]时, 往右边一个一个逼近,left = mid + 1; 返回right + * + * @return + */ + public static int bsearch2(int[] array, int target) { + if (array == null || array.length == 0 /*|| target < array[0] || target > array[array.length - 1]*/) { + return -1; + } + int left = 0; + int right = array.length - 1; + while (right >= left) { + int mid = (left + right) >> 1; + if (array[mid] <= target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + if (right >= 0 && array[right] == target) { + return right; + } + return -1; + } + + // 二分查找变种说明 + //public void test(int[] array, int target){ + // + // int left = 0; + // int right = array.length - 1; + // // 这里必须是 <= + // while (left <= right) { + // int mid = (left + right) / 2; + // if (array[mid] ? key) { + // //... right = mid - 1; + // } + // else { + // // ... left = mid + 1; + // } + // } + // return xxx; + //} + + + /** + * 查找第一个等于或者大于key的元素 + */ + public static int bsearch3(int[] array, int target) { + if (array == null || array.length == 0) { + return -1; + } + int left = 0; + int right = array.length - 1; + while (right >= left) { + int mid = (left + right) >> 1; + if (array[mid] >= target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } + + /** + * 查找第一个大于key的元素 + */ + public static int bsearch4(int[] array, int target) { + if (array == null || array.length == 0) { + return -1; + } + int left = 0; + int right = array.length - 1; + while (right >= left) { + int mid = (left + right) >> 1; + if (array[mid] > target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + return left; + } + + /** + * 查找最后一个等于或者小于key的元素 + */ + public static int bsearch5(int[] array, int target) { + if (array == null || array.length == 0) { + return -1; + } + int left = 0; + int right = array.length - 1; + while (right >= left) { + int mid = (left + right) >> 1; + if (array[mid] <= target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return right; + } + + /** + * 查找最后一个小于key的元素 + */ + public static int bsearch6(int[] array, int target) { + if (array == null || array.length == 0) { + return -1; + } + int left = 0; + int right = array.length - 1; + while (right >= left) { + int mid = (left + right) >> 1; + if (array[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return right; + } + + public static void main(String[] args) { + int[] array = {1, 1, 3, 6, 6, 6, 7, 9, 17, 17}; + int index = bsearch6(array, 0); + System.out.println(index); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java new file mode 100644 index 0000000..d5de67f --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java @@ -0,0 +1,40 @@ +package com.chen.algorithm.znn.array.test88; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/merge-sorted-array/solution/leetcode88-he-bing-liang-ge-you-xu-shu-zu-by-ma-xi/ + * + * @author: zhunn + * @Date: 2020-10-20 11:33 + * @Description: 合并两个有序数组 + */ +public class Solution { + + public void merge(int[] nums1, int m, int[] nums2, int n) { + + int p1 = m - 1, p2 = n - 1, p3 = m + n - 1; + while (p2 >= 0) { + if (p1 >= 0 && nums1[p1] > nums2[p2]) { + nums1[p3--] = nums1[p1--]; + } else { + nums1[p3--] = nums2[p2--]; + } + } + } + + + @Test + public void testCase() { + //int[] m = {1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0}; + //int[] n = {0, 2, 5, 6, 8, 9, 25}; + //merge(m, 4, n, n.length); + int[] m = {1,2,3,0,0,0}; + int[] n = {2,5,6}; + merge(m, 3, n, n.length); + System.out.println(Arrays.toString(m)); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/Test.java b/src/main/java/com/chen/algorithm/znn/backtrack/Test.java new file mode 100644 index 0000000..a6e91ec --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.backtrack; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 回溯相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/bfs/Test.java b/src/main/java/com/chen/algorithm/znn/bfs/Test.java new file mode 100644 index 0000000..ac049c0 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bfs/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.bfs; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 广度优先搜索相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/Test.java b/src/main/java/com/chen/algorithm/znn/bitmap/Test.java new file mode 100644 index 0000000..8c71c49 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bitmap/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.bitmap; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 位运算相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/dfs/Test.java b/src/main/java/com/chen/algorithm/znn/dfs/Test.java new file mode 100644 index 0000000..1463404 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dfs/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dfs; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 深度优先搜索相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/divide/Test.java b/src/main/java/com/chen/algorithm/znn/divide/Test.java new file mode 100644 index 0000000..d734a6b --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/divide/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.divide; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 分治法相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/Test.java b/src/main/java/com/chen/algorithm/znn/dynamic/Test.java new file mode 100644 index 0000000..000ada8 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: DP动态规划相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/Test.java b/src/main/java/com/chen/algorithm/znn/frequency/Test.java new file mode 100644 index 0000000..998236c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.frequency; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 高频常考算法 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java new file mode 100644 index 0000000..425dee0 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java @@ -0,0 +1,56 @@ +package com.chen.algorithm.znn.frequency.test48; + +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/9/16 18:22 + * @Description: 顺时针旋转图像90° + */ +public class Solution { + + + public void rotate(int[][] matrix) { + + int n = matrix.length; + int m = matrix[0].length; + + //先转置 + for (int i = 0; i < n; i++) { + for (int j = i; j < m; j++) { + int temp = matrix[j][i]; + matrix[j][i] = matrix[i][j]; + matrix[i][j] = temp; + System.out.println("=====" + JSONObject.toJSONString(matrix)); + } + } + + // 反转每一行 + for (int i = 0; i < n; i++) { + for (int j = 0; j < m / 2; j++) { + int temp = matrix[i][j]; + matrix[i][j] = matrix[i][m - j - 1]; + matrix[i][m - j - 1] = temp; + } + } + } + + + @Test + public void testCase() { + + int[][] matrix = new int[3][3]; + + matrix[0] = new int[]{1, 2, 3}; + matrix[1] = new int[]{4, 5, 6}; + matrix[2] = new int[]{7, 8, 9}; + + rotate(matrix); + + System.out.println("last:" + JSONObject.toJSONString(matrix)); + + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java new file mode 100644 index 0000000..23e0c73 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java @@ -0,0 +1,25 @@ +package com.chen.algorithm.znn.frequency.test7; + +/** + * @Auther: zhunn + * @Date: 2020/9/16 18:20 + * @Description: 整数反转 + */ +public class Solution { + + public static int reverse1(int x) { + int res = 0; + while (x != 0) { + res = res * 10 + x % 10; + x /= 10; + } + if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) { + return 0; + } + return res; + } + + public static void main(String[] args) { + System.out.println(reverse1(123)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java new file mode 100644 index 0000000..74b609c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java @@ -0,0 +1,34 @@ +package com.chen.algorithm.znn.frequency.test9; + +/** + * @Auther: zhunn + * @Date: 2020/9/16 18:22 + * @Description: 回文数 + */ +public class Solution { + + public static boolean isPalindrome1(int x) { + // 特殊情况: + // 当 x < 0 时,x 不是回文数。 + // 同样地,如果数字的最后一位是 0,为了使该数字为回文, + // 则其第一位数字也应该是 0 + // 只有 0 满足这一属性 + if (x < 0 || (x != 0 && x % 10 == 0)) return false; + int rev = 0; + while (x > rev) { + rev = rev * 10 + x % 10; + x /= 10; + } + // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。 + return rev == x || rev / 10 == x; + } + + public static void main(String[] args) { + System.out.println(isPalindrome1(-121)); + System.out.println(isPalindrome1(0)); + System.out.println(isPalindrome1(1000)); + System.out.println(isPalindrome1(12321)); + System.out.println(isPalindrome1(1221)); + System.out.println(isPalindrome1(1231)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/greedy/Test.java b/src/main/java/com/chen/algorithm/znn/greedy/Test.java new file mode 100644 index 0000000..7309c26 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/greedy/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.greedy; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 贪心算法相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/hash/Test.java b/src/main/java/com/chen/algorithm/znn/hash/Test.java new file mode 100644 index 0000000..9c44d57 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/hash/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.hash; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: hash相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java new file mode 100644 index 0000000..d596714 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java @@ -0,0 +1,40 @@ +package com.chen.algorithm.znn.hash.test242; + +import org.junit.Test; + +/** + * @Author: zhunn + * @Date: 2020-10-22 22:12 + * @Description: 有效的字母异位词。哈希表 + */ +public class Solution { + + public boolean isAnagram(String s, String t) { + + if (s == null || t == null || s.length() != t.length()) { + return false; + } + + int[] counter = new int[26]; + for (int i = 0; i < s.length(); i++) { + counter[s.charAt(i) - 'a']++; + counter[t.charAt(i) - 'a']--; + } + + for (int n : counter) { + if (n != 0) { + return false; + } + } + return true; + } + + + @Test + public void testCase() { + + System.out.println(isAnagram("anagram", "nagaram")); + + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/heap/Test.java b/src/main/java/com/chen/algorithm/znn/heap/Test.java new file mode 100644 index 0000000..58655f0 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/heap/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.heap; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 堆相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/ListNode.java b/src/main/java/com/chen/algorithm/znn/linkedlist/ListNode.java new file mode 100644 index 0000000..01ab163 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/ListNode.java @@ -0,0 +1,26 @@ +package com.chen.algorithm.znn.linkedlist; + +/** + * @Auther: zhunn + * @Date: 2020/10/9 15:31 + * @Description: + */ +public class ListNode { + + public int val; + + public ListNode next; + + public ListNode() { + } + + public ListNode(int val) { + this.val = val; + } + + public ListNode(int val, ListNode next) { + this.val = val; + this.next = next; + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/Test.java b/src/main/java/com/chen/algorithm/znn/linkedlist/Test.java new file mode 100644 index 0000000..a4367d8 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/Test.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.linkedlist; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 链表相关 + */ +public class Test { +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java new file mode 100644 index 0000000..057e6fc --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java @@ -0,0 +1,79 @@ +package com.chen.algorithm.znn.linkedlist.test141; + +import com.chen.algorithm.znn.linkedlist.ListNode; + +import java.util.HashSet; +import java.util.Set; + +/** + * @Auther: zhunn + * @Date: 2020/10/23 16:26 + * @Description: 环形链表一:判断链表是否有环 + * 方法:1-哈希表,2-快慢指针 + */ +public class Solution { + + /** + * 2-快慢指针 + * @param head + * @return + */ + public boolean hasCycle1(ListNode head) { + if (head == null || head.next == null) { + return false; + } + + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + + if (slow == fast) { + return true; + } + } + return false; + } + + /** + * 1-哈希表 + * @param head + * @return + */ + public boolean hasCycle2(ListNode head) { + if (head == null || head.next == null) { + return false; + } + + ListNode dummy = head; + Set visited = new HashSet<>(); + while (dummy != null) { + if (visited.contains(dummy)) { + return true; + } else { + visited.add(dummy); + } + dummy = dummy.next; + } + return false; + } + + /** + * 1-哈希表简易版 + * @param head + * @return + */ + public boolean hasCycle3(ListNode head) { + Set seen = new HashSet<>(); + while (head != null) { + if (!seen.add(head)) { + return true; + } + head = head.next; + } + return false; + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java new file mode 100644 index 0000000..0964ccd --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java @@ -0,0 +1,67 @@ +package com.chen.algorithm.znn.linkedlist.test142; + + +import com.chen.algorithm.znn.linkedlist.ListNode; + +import java.util.HashSet; +import java.util.Set; + +/** + * @Auther: zhunn + * @Date: 2020/10/23 16:10 + * @Description: 环形链表二,找出入环点 + * 方法:1-哈希表,2-快慢指针 + */ +public class Solution { + + /** + * 1-哈希表 + * @param head + * @return + */ + public ListNode detectCycle1(ListNode head) { + if (head == null || head.next == null) { + return null; + } + ListNode dummy = head; + Set visited = new HashSet<>(); + while (dummy != null) { + if (visited.contains(dummy)) { + return dummy; + } else { + visited.add(dummy); + } + dummy = dummy.next; + } + return null; + } + + /** + * 2-快慢指针 + * @param head + * @return + */ + public ListNode detectCycle2(ListNode head) { + if (head == null || head.next == null) { + return null; + } + + ListNode slow = head; + ListNode fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) { + break; + } + } + + ListNode ptr = head; + while (slow != ptr) { + slow = slow.next; + ptr = ptr.next; + } + return slow; + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java new file mode 100644 index 0000000..41aa679 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java @@ -0,0 +1,57 @@ +package com.chen.algorithm.znn.linkedlist.test160; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +/** + * @Author: zhunn + * @Date: 2020-10-22 17:40 + * @Description: 相交链表 + */ +public class Solution { + + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { + + if (headA == null || headB == null) { + return null; + } + ListNode a = headA; + ListNode b = headB; + + while (a != b) { + a = a == null ? headB : a.next; + b = b == null ? headA : b.next; + } + return b; + } + + @Test + public void test() { + ListNode l1_1 = new ListNode(4); + ListNode l1_2 = new ListNode(1); + ListNode l1_3 = new ListNode(8); + ListNode l1_4 = new ListNode(7); + ListNode l1_5 = new ListNode(5); + + ListNode l2_1 = new ListNode(5); + ListNode l2_2 = new ListNode(0); + ListNode l2_3 = new ListNode(1); + + l1_1.next = l1_2; + l1_2.next = l1_3; + l1_3.next = l1_4; + l1_4.next = l1_5; + + l2_1.next = l2_2; + l2_2.next = l2_3; + l2_3.next = l1_3; + + ListNode result = getIntersectionNode(l1_1, l2_1); + + while (result != null) { + System.out.println(result.val); + result = result.next; + } + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java new file mode 100644 index 0000000..0cf1d22 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java @@ -0,0 +1,126 @@ +package com.chen.algorithm.znn.linkedlist.test19; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +import java.util.Deque; +import java.util.LinkedList; + +/** + * @Auther: zhunn + * @Date: 2020/10/22 14:51 + * @Description: 1、遍历length-n+1;2、栈、3、双指针法 + */ +public class Solution { + + /** + * 计算链表长度并遍历 + * + * @param head 头结点 + * @param n 删除倒数第几个 + * @return + */ + public ListNode removeNthFromEnd1(ListNode head, int n) { + if (head == null) { + return head; + } + + ListNode dummy = new ListNode(-1, head); + ListNode curr = dummy; + int len = getLength(head); + for (int i = 1; i < len - n + 1; i++) { + curr = curr.next; + } + curr.next = curr.next.next; + + return dummy.next; + } + + /** + * 用stack + * + * @param head 头结点 + * @param n 删除倒数第几个 + * @return + */ + public ListNode removeNthFromEnd2(ListNode head, int n) { + if (head == null) { + return head; + } + ListNode dummy = new ListNode(-1, head); + Deque stack = new LinkedList<>(); + ListNode curr = dummy; + while (curr != null) { + stack.push(curr); + curr = curr.next; + } + + for (int i = 0; i < n; i++) { + stack.pop(); + } + ListNode pre = stack.peek(); + pre.next = pre.next.next; + return dummy.next; + } + + /** + * 双指针法 + * + * @param head 头结点 + * @param n 删除倒数第几个 + * @return + */ + public ListNode removeNthFromEnd3(ListNode head, int n) { + if (head == null) { + return head; + } + + ListNode dummy = new ListNode(-1, head); + ListNode fast = dummy; + ListNode slow = dummy; + + for (int i = 0; i < n; i++) { + fast = fast.next; + } + + while (fast.next != null) { + fast = fast.next; + slow = slow.next; + } + + slow.next = slow.next.next; + + return dummy.next; + } + + private int getLength(ListNode head) { + if (head == null) { + return 0; + } + ListNode lenNode = head; + int len = 0; + while (lenNode != null) { + len++; + lenNode = lenNode.next; + } + return len; + } + + @Test + public void test() { + ListNode five = new ListNode(5); + ListNode four = new ListNode(4, five); + ListNode three = new ListNode(3, four); + ListNode two = new ListNode(2, three); + ListNode head = new ListNode(1, two); + + ListNode result = removeNthFromEnd3(head, 2); + + ListNode a = result; + while (a != null) { + System.out.println(a.val); + a = a.next; + } + //System.out.println(result); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java new file mode 100644 index 0000000..a6d850c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java @@ -0,0 +1,69 @@ +package com.chen.algorithm.znn.linkedlist.test2; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +/** + * @Author: zhunn + * @Date: 2020-10-20 17:43 + * @Description: 两数相加 + */ +public class Solution { + + + public ListNode addTwo(ListNode a, ListNode b) { + + ListNode result = new ListNode(-1); + ListNode curr = result; + + + int carry = 0; + + while (a != null || b != null || carry != 0) { + + if (a != null) { + carry += a.val; + a = a.next; + } + + if (b != null) { + carry += b.val; + b = b.next; + } + curr.next = new ListNode(carry % 10); + carry = carry / 10; + curr = curr.next; + } + return result.next; + } + + @Test + public void testCase() { + + ListNode l1_1 = new ListNode(2); + ListNode l1_2 = new ListNode(4); + ListNode l1_3 = new ListNode(3); + + l1_1.next = l1_2; + l1_2.next = l1_3; + + + ListNode l2_1 = new ListNode(5); + ListNode l2_2 = new ListNode(6); + ListNode l2_3 = new ListNode(4); + + l2_1.next = l2_2; + l2_2.next = l2_3; + + + ListNode result = addTwo(l1_1, l2_1); + + System.out.println(result.val); + System.out.println(result.next.val); + System.out.println(result.next.next.val); + + + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java new file mode 100644 index 0000000..2e61794 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java @@ -0,0 +1,55 @@ +package com.chen.algorithm.znn.linkedlist.test206; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/22 17:23 + * @Description: 反转链表:1-迭代法,2-递归 + */ +public class Solution { + + public ListNode reverseList1(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode pre = null; + ListNode curr = head; + while (curr != null) { + ListNode nextTemp = curr.next; + curr.next = pre; + pre = curr; + curr = nextTemp; + } + + return pre; + } + + public ListNode reverseList2(ListNode head){ + if(head == null || head.next == null){ + return head; + } + ListNode p = reverseList2(head.next); + head.next.next = head; + head.next = null; + return p; + } + + @Test + public void test() { + ListNode l1_4 = new ListNode(18); + ListNode l1_3 = new ListNode(9, l1_4); + ListNode l1_2 = new ListNode(6, l1_3); + ListNode l1_1 = new ListNode(7, l1_2); + + ListNode result = reverseList2(l1_1); + System.out.println(result.val); + System.out.println(result.next.val); + System.out.println(result.next.next.val); + System.out.println(result.next.next.next.val); + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java new file mode 100644 index 0000000..6e170b2 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java @@ -0,0 +1,69 @@ +package com.chen.algorithm.znn.linkedlist.test21; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +/** + * @Author: zhunn + * @Date: 2020-09-06 01:43 + * @Description: 并两个有序链表 + */ +public class Solution { + + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + + + ListNode prehead = new ListNode(0); + + ListNode prev = prehead; + + while (l1 != null && l2 != null) { + + if (l1.val <= l2.val) { + prev.next = l1; + l1 = l1.next; + } else { + prev.next = l2; + l2 = l2.next; + } + + prev = prev.next; + } + + prev.next = l1 == null ? l2 : l1; + + return prehead.next; + } + + @Test + public void testCase(){ + + ListNode l1_1 = new ListNode(3); + ListNode l1_2 = new ListNode(6); + ListNode l1_3 = new ListNode(9); + + l1_1.next = l1_2; + l1_2.next = l1_3; + + + ListNode l2_1 = new ListNode(2); + ListNode l2_2 = new ListNode(6); + ListNode l2_3 = new ListNode(8); + + l2_1.next = l2_2; + l2_2.next = l2_3; + + + ListNode result = mergeTwoLists(l1_1, l2_1); + + System.out.println(result.val); + System.out.println(result.next.val); + System.out.println(result.next.next.val); + System.out.println(result.next.next.next.val); + System.out.println(result.next.next.next.next.val); + System.out.println(result.next.next.next.next.next.val); + + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java new file mode 100644 index 0000000..af398d4 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java @@ -0,0 +1,105 @@ +package com.chen.algorithm.znn.linkedlist.test24; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/23 10:48 + * @Description: 两两交换链表中结点:1-递归,2-迭代 + */ +public class Solution { + + + /** + * 1-递归 + * @param head + * @return + */ + public ListNode swapPairs1(ListNode head) { + if (head == null || head.next == null) { + return head; + } + ListNode newHead = head.next; + head.next = swapPairs1(newHead.next); + newHead.next = head; + return newHead; + } + + /** + * 2-迭代 + * @param head + * @return + */ + public ListNode swapPairs2(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode dummyHead = new ListNode(-1); + dummyHead.next = head; + ListNode temp = dummyHead; + + while (temp.next != null && temp.next.next != null) { + ListNode node1 = temp.next; + ListNode node2 = temp.next.next; + + temp.next = node2; + node1.next = node2.next; + node2.next = node1; + + temp = node1; + } + return dummyHead.next; + } + + /** + * 2-迭代(操作head) + * @param head + * @return + */ + public ListNode swapPairs3(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode dummyHead = new ListNode(-1); + dummyHead.next = head; + ListNode temp = dummyHead; + + while (head != null && head.next != null) { + ListNode node1 = head; + ListNode node2 = head.next; + + temp.next = node2; + node1.next = node2.next; + node2.next = node1; + + temp = node1; + head = node1.next; + } + return dummyHead.next; + } + + @Test + public void test() { + ListNode l1_1 = new ListNode(1); + ListNode l1_2 = new ListNode(2); + ListNode l1_3 = new ListNode(3); + ListNode l1_4 = new ListNode(4); + ListNode l1_5 = new ListNode(5); + + l1_1.next = l1_2; + l1_2.next = l1_3; + l1_3.next = l1_4; + l1_4.next = l1_5; + + ListNode result = swapPairs3(l1_1); + + System.out.println(result.val); + System.out.println(result.next.val); + System.out.println(result.next.next.val); + System.out.println(result.next.next.next.val); + System.out.println(result.next.next.next.next.val); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java new file mode 100644 index 0000000..4ea6f68 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java @@ -0,0 +1,94 @@ +package com.chen.algorithm.znn.linkedlist.test25; + +import com.chen.algorithm.znn.linkedlist.ListNode; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: K个一组翻转链表 + */ +public class Solution { + + /** + * 官网解法 + * @param head + * @param k + * @return + */ + public ListNode reverseKGroup(ListNode head, int k) { + ListNode hair = new ListNode(0); + hair.next = head; + ListNode pre = hair; + + while (head != null) { + ListNode tail = pre; + // 查看剩余部分长度是否大于等于 k + for (int i = 0; i < k; ++i) { + tail = tail.next; + if (tail == null) { + return hair.next; + } + } + ListNode nextTemp = tail.next; + ListNode[] reverse = myReverse(head, tail); + head = reverse[0]; + tail = reverse[1]; + // 把子链表重新接回原链表 + pre.next = head; + tail.next = nextTemp; + pre = tail; + head = tail.next; + } + + return hair.next; + } + + private ListNode[] myReverse(ListNode head, ListNode tail) { + ListNode prev = tail.next; + ListNode p = head; + while (prev != tail) { + ListNode nex = p.next; + p.next = prev; + prev = p; + p = nex; + } + return new ListNode[]{tail, head}; + } + + + public ListNode reverseKGroup1(ListNode head, int k) { + ListNode dummy = new ListNode(0); + dummy.next = head; + + ListNode pre = dummy; + ListNode end = dummy; + + while (end.next != null) { + for (int i = 0; i < k && end != null; i++){end = end.next;} + if (end == null) {break;} + ListNode start = pre.next; + ListNode next = end.next; + end.next = null; + pre.next = reverse(start); + start.next = next; + pre = start; + + end = pre; + } + return dummy.next; + } + + private ListNode reverse(ListNode head) { + ListNode pre = null; + ListNode curr = head; + while (curr != null) { + ListNode next = curr.next; + curr.next = pre; + pre = curr; + curr = next; + } + return pre; + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java new file mode 100644 index 0000000..9ea3411 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java @@ -0,0 +1,39 @@ +package com.chen.algorithm.znn.linkedlist.test83; + +import com.chen.algorithm.znn.linkedlist.ListNode; + +/** + * @Author: zhunn + * @Date: 2020-10-08 02:19 + * @Description: 删除排序链表中的重复元素 + */ +public class Solution { + + + /** + * 需要注意的点, + * 1、应该是后面节点和前面节点比较; + * 2、如果后面节点和前面节点的值一致,则只是修改前节点的指针,遍历指针不前进 + * + * @param head + * @return + */ + public ListNode deleteDuplicates(ListNode head) { + + if (head == null || head.next == null) { + return head; + } + + ListNode temp = head; + while (temp.next != null) { + if (temp.next.val == temp.val) { + temp.next = temp.next.next; + } else { + temp = temp.next; + } + } + return head; + } + + +} diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java new file mode 100644 index 0000000..867ab33 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java @@ -0,0 +1,112 @@ +package com.chen.algorithm.znn.linkedlist.test92; + +import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 反转链表二:1-双指针,2-删除结点递推 + */ +public class Solution { + + // 翻转n个节点,返回新链表的头部 + private ListNode reverseN(ListNode head, int n) { + ListNode prev = null; + ListNode curr = head; + for (int i = 0; i < n; i++) { + ListNode oldNext = curr.next; + curr.next = prev; + prev = curr; + curr = oldNext; + } + return prev; + } + + /** + * 1-双指针 + * @param head + * @param m + * @param n + * @return + */ + public ListNode reverseBetween1(ListNode head, int m, int n) { + ListNode dummy = new ListNode(42); + dummy.next = head; + ListNode ptr1 = dummy; + ListNode ptr2 = dummy; + // 找到左右两段的端点 + for (int i = 0; i < m - 1; i++) { + ptr2 = ptr2.next; + } + for (int i = 0; i < n + 1; i++) { + ptr1 = ptr1.next; + } + // 找到中段的尾端点 + ListNode t = ptr2.next; + // 翻转中段,得到中段的头端点 + ListNode h = reverseN(t, n - m + 1); + // 中端的头端点和左段端点相连 + ptr2.next = h; + // 中段的尾端点和右段端点相连 + t.next = ptr1; + return dummy.next; + } + + /** + * 2-删除结点递推 + * @param head + * @param m + * @param n + * @return + */ + public ListNode reverseBetween2(ListNode head, int m, int n){ + if(head == null || head.next == null){ + return head; + } + + ListNode dummy = new ListNode(-1); + dummy.next = head; + ListNode pre = dummy; + for(int i =0;i Date: Mon, 26 Oct 2020 11:00:48 +0800 Subject: [PATCH 02/63] =?UTF-8?q?=E6=A2=B3=E7=90=86=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/offer/test29/Solution.java | 146 +++++----- .../algorithm/study/test141/Solution3.java | 87 ------ .../algorithm/study/test142/Solution4.java | 65 ----- .../algorithm/study/test19/Solution4.java | 142 --------- .../algorithm/study/test206/Solution5.java | 72 ----- .../algorithm/study/test238/Solution1.java | 110 ------- .../algorithm/study/test24/Solution3.java | 104 ------- .../algorithm/study/test25/Solution5.java | 92 ------ .../algorithm/study/test27/Solution2.java | 32 --- .../algorithm/study/test283/Solution2.java | 24 -- .../algorithm/study/test34/Solution4.java | 83 ------ .../algorithm/study/test704/Solution.java | 272 +++++++++--------- .../algorithm/study/test92/Solution3.java | 120 -------- .../test283/{Solution2.java => Solution.java} | 2 +- .../znn/frequency/test48/Solution.java | 2 +- 15 files changed, 211 insertions(+), 1142 deletions(-) delete mode 100644 src/main/java/com/chen/algorithm/study/test141/Solution3.java delete mode 100644 src/main/java/com/chen/algorithm/study/test142/Solution4.java delete mode 100644 src/main/java/com/chen/algorithm/study/test19/Solution4.java delete mode 100644 src/main/java/com/chen/algorithm/study/test206/Solution5.java delete mode 100644 src/main/java/com/chen/algorithm/study/test238/Solution1.java delete mode 100644 src/main/java/com/chen/algorithm/study/test24/Solution3.java delete mode 100644 src/main/java/com/chen/algorithm/study/test25/Solution5.java delete mode 100644 src/main/java/com/chen/algorithm/study/test27/Solution2.java delete mode 100644 src/main/java/com/chen/algorithm/study/test34/Solution4.java delete mode 100644 src/main/java/com/chen/algorithm/study/test92/Solution3.java rename src/main/java/com/chen/algorithm/znn/array/test283/{Solution2.java => Solution.java} (97%) diff --git a/src/main/java/com/chen/algorithm/study/offer/test29/Solution.java b/src/main/java/com/chen/algorithm/study/offer/test29/Solution.java index bda3fd1..1c3a01a 100644 --- a/src/main/java/com/chen/algorithm/study/offer/test29/Solution.java +++ b/src/main/java/com/chen/algorithm/study/offer/test29/Solution.java @@ -9,79 +9,79 @@ */ public class Solution { - public static int[] spiralOrder(int[][] matrix) { - if (matrix.length == 0) { - return new int[0]; - } - int[] res = new int[matrix.length * matrix[0].length]; - int u = 0, d = matrix.length - 1, l = 0, r = matrix[0].length - 1; - int idx = 0; - while (true) { - for (int i = l; i <= r; i++) { - res[idx++] = matrix[u][i]; - } - if (++u > d) { - break; - } - for (int i = u; i <= d; i++) { - res[idx++] = matrix[i][r]; - } - if (--r < l) { - break; - } - for (int i = r; i >= l; i--) { - res[idx++] = matrix[d][i]; - } - if (--d < u) { - break; - } - for (int i = d; i >= u; i--) { - res[idx++] = matrix[i][l]; - } - if (++l > r) { - break; - } - } - return res; - } + //public static int[] spiralOrder(int[][] matrix) { + // if (matrix.length == 0) { + // return new int[0]; + // } + // int[] res = new int[matrix.length * matrix[0].length]; + // int u = 0, d = matrix.length - 1, l = 0, r = matrix[0].length - 1; + // int idx = 0; + // while (true) { + // for (int i = l; i <= r; i++) { + // res[idx++] = matrix[u][i]; + // } + // if (++u > d) { + // break; + // } + // for (int i = u; i <= d; i++) { + // res[idx++] = matrix[i][r]; + // } + // if (--r < l) { + // break; + // } + // for (int i = r; i >= l; i--) { + // res[idx++] = matrix[d][i]; + // } + // if (--d < u) { + // break; + // } + // for (int i = d; i >= u; i--) { + // res[idx++] = matrix[i][l]; + // } + // if (++l > r) { + // break; + // } + // } + // return res; + //} + // + //private static int[] spiralOrder1(int[][] matrix) { + // if (matrix == null || matrix.length == 0) return new int[0]; + // + // int numEle = matrix.length * matrix[0].length; + // int[] result = new int[numEle]; + // int idx = 0; + // int left = 0, right = matrix[0].length - 1, top = 0, bottom = matrix.length - 1; + // + // while (numEle >= 1) { + // for (int i = left; i <= right && numEle >= 1; i++) { + // result[idx++] = matrix[top][i]; + // numEle--; + // } + // top++; + // for (int i = top; i <= bottom && numEle >= 1; i++) { + // result[idx++] = matrix[i][right]; + // numEle--; + // } + // right--; + // for (int i = right; i >= left && numEle >= 1; i--) { + // result[idx++] = matrix[bottom][i]; + // numEle--; + // } + // bottom--; + // for (int i = bottom; i >= top && numEle >= 1; i--) { + // result[idx++] = matrix[i][left]; + // numEle--; + // } + // left++; + // } + // return result; + //} - private static int[] spiralOrder1(int[][] matrix) { - if (matrix == null || matrix.length == 0) return new int[0]; - - int numEle = matrix.length * matrix[0].length; - int[] result = new int[numEle]; - int idx = 0; - int left = 0, right = matrix[0].length - 1, top = 0, bottom = matrix.length - 1; - - while (numEle >= 1) { - for (int i = left; i <= right && numEle >= 1; i++) { - result[idx++] = matrix[top][i]; - numEle--; - } - top++; - for (int i = top; i <= bottom && numEle >= 1; i++) { - result[idx++] = matrix[i][right]; - numEle--; - } - right--; - for (int i = right; i >= left && numEle >= 1; i--) { - result[idx++] = matrix[bottom][i]; - numEle--; - } - bottom--; - for (int i = bottom; i >= top && numEle >= 1; i--) { - result[idx++] = matrix[i][left]; - numEle--; - } - left++; - } - return result; - } - - public static void main(String[] args) { - int[][] matrix = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; - int[] res = spiralOrder1(matrix); - System.out.println(Arrays.toString(res)); - } + //public static void main(String[] args) { + // int[][] matrix = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; + // int[] res = spiralOrder1(matrix); + // System.out.println(Arrays.toString(res)); + //} } diff --git a/src/main/java/com/chen/algorithm/study/test141/Solution3.java b/src/main/java/com/chen/algorithm/study/test141/Solution3.java deleted file mode 100644 index 75c18d8..0000000 --- a/src/main/java/com/chen/algorithm/study/test141/Solution3.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.chen.algorithm.study.test141; - -import java.util.HashSet; -import java.util.Set; - -/** - * @Auther: zhunn - * @Date: 2020/10/23 16:26 - * @Description: 环形链表一:判断链表是否有环 - * 方法:1-哈希表,2-快慢指针 - */ -public class Solution3 { - class ListNode { - int val; - ListNode next; - - ListNode(int x) { - val = x; - next = null; - } - } - - - /** - * 2-快慢指针 - * @param head - * @return - */ - public boolean hasCycle1(ListNode head) { - if (head == null || head.next == null) { - return false; - } - - ListNode slow = head; - ListNode fast = head; - - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - - if (slow == fast) { - return true; - } - } - return false; - } - - /** - * 1-哈希表 - * @param head - * @return - */ - public boolean hasCycle2(ListNode head) { - if (head == null || head.next == null) { - return false; - } - - ListNode dummy = head; - Set visited = new HashSet<>(); - while (dummy != null) { - if (visited.contains(dummy)) { - return true; - } else { - visited.add(dummy); - } - dummy = dummy.next; - } - return false; - } - - /** - * 1-哈希表简易版 - * @param head - * @return - */ - public boolean hasCycle3(ListNode head) { - Set seen = new HashSet<>(); - while (head != null) { - if (!seen.add(head)) { - return true; - } - head = head.next; - } - return false; - } - -} diff --git a/src/main/java/com/chen/algorithm/study/test142/Solution4.java b/src/main/java/com/chen/algorithm/study/test142/Solution4.java deleted file mode 100644 index 5d283c5..0000000 --- a/src/main/java/com/chen/algorithm/study/test142/Solution4.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.chen.algorithm.study.test142; - - -import java.util.HashSet; -import java.util.Set; - -/** - * @Auther: zhunn - * @Date: 2020/10/23 16:10 - * @Description: 环形链表二,找出入环点 - * 方法:1-哈希表,2-快慢指针 - */ -public class Solution4 { - - /** - * 1-哈希表 - * @param head - * @return - */ - public ListNode detectCycle1(ListNode head) { - if (head == null || head.next == null) { - return null; - } - ListNode dummy = head; - Set visited = new HashSet<>(); - while (dummy != null) { - if (visited.contains(dummy)) { - return dummy; - } else { - visited.add(dummy); - } - dummy = dummy.next; - } - return null; - } - - /** - * 2-快慢指针 - * @param head - * @return - */ - public ListNode detectCycle2(ListNode head) { - if (head == null || head.next == null) { - return null; - } - - ListNode slow = head; - ListNode fast = head; - while (fast != null && fast.next != null) { - slow = slow.next; - fast = fast.next.next; - if (slow == fast) { - break; - } - } - - ListNode ptr = head; - while (slow != ptr) { - slow = slow.next; - ptr = ptr.next; - } - return slow; - } - -} diff --git a/src/main/java/com/chen/algorithm/study/test19/Solution4.java b/src/main/java/com/chen/algorithm/study/test19/Solution4.java deleted file mode 100644 index 0f7b416..0000000 --- a/src/main/java/com/chen/algorithm/study/test19/Solution4.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.chen.algorithm.study.test19; - -import org.junit.Test; - -import java.util.Deque; -import java.util.LinkedList; - -/** - * @Auther: zhunn - * @Date: 2020/10/22 14:51 - * @Description: 1、遍历length-n+1;2、栈、3、双指针法 - */ -public class Solution4 { - - class ListNode { - int val; - ListNode next; - - public ListNode() { - } - - public ListNode(int val) { - this.val = val; - } - - public ListNode(int val, ListNode next) { - this.val = val; - this.next = next; - } - } - - /** - * 计算链表长度并遍历 - * - * @param head 头结点 - * @param n 删除倒数第几个 - * @return - */ - public ListNode removeNthFromEnd1(ListNode head, int n) { - if (head == null) { - return head; - } - - ListNode dummy = new ListNode(-1, head); - ListNode curr = dummy; - int len = getLength(head); - for (int i = 1; i < len - n + 1; i++) { - curr = curr.next; - } - curr.next = curr.next.next; - - return dummy.next; - } - - /** - * 用stack - * - * @param head 头结点 - * @param n 删除倒数第几个 - * @return - */ - public ListNode removeNthFromEnd2(ListNode head, int n) { - if (head == null) { - return head; - } - ListNode dummy = new ListNode(-1, head); - Deque stack = new LinkedList<>(); - ListNode curr = dummy; - while (curr != null) { - stack.push(curr); - curr = curr.next; - } - - for (int i = 0; i < n; i++) { - stack.pop(); - } - ListNode pre = stack.peek(); - pre.next = pre.next.next; - return dummy.next; - } - - /** - * 双指针法 - * - * @param head 头结点 - * @param n 删除倒数第几个 - * @return - */ - public ListNode removeNthFromEnd3(ListNode head, int n) { - if (head == null) { - return head; - } - - ListNode dummy = new ListNode(-1, head); - ListNode fast = dummy; - ListNode slow = dummy; - - for (int i = 0; i < n; i++) { - fast = fast.next; - } - - while (fast.next != null) { - fast = fast.next; - slow = slow.next; - } - - slow.next = slow.next.next; - - return dummy.next; - } - - private int getLength(ListNode head) { - if (head == null) { - return 0; - } - ListNode lenNode = head; - int len = 0; - while (lenNode != null) { - len++; - lenNode = lenNode.next; - } - return len; - } - - @Test - public void test() { - ListNode five = new ListNode(5); - ListNode four = new ListNode(4, five); - ListNode three = new ListNode(3, four); - ListNode two = new ListNode(2, three); - ListNode head = new ListNode(1, two); - - ListNode result = removeNthFromEnd3(head, 2); - - ListNode a = result; - while (a != null) { - System.out.println(a.val); - a = a.next; - } - //System.out.println(result); - } -} diff --git a/src/main/java/com/chen/algorithm/study/test206/Solution5.java b/src/main/java/com/chen/algorithm/study/test206/Solution5.java deleted file mode 100644 index 3e4e9de..0000000 --- a/src/main/java/com/chen/algorithm/study/test206/Solution5.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.chen.algorithm.study.test206; - -import org.junit.Test; - -/** - * @Auther: zhunn - * @Date: 2020/10/22 17:23 - * @Description: 反转链表:1-迭代法,2-递归 - */ -public class Solution5 { - - class ListNode { - int val; - ListNode next; - - public ListNode() { - } - - public ListNode(int val) { - this.val = val; - } - - public ListNode(int val, ListNode next) { - this.val = val; - this.next = next; - } - - } - - public ListNode reverseList1(ListNode head) { - if (head == null || head.next == null) { - return head; - } - - ListNode pre = null; - ListNode curr = head; - while (curr != null) { - ListNode nextTemp = curr.next; - curr.next = pre; - pre = curr; - curr = nextTemp; - } - - return pre; - } - - public ListNode reverseList2(ListNode head){ - if(head == null || head.next == null){ - return head; - } - ListNode p = reverseList2(head.next); - head.next.next = head; - head.next = null; - return p; - } - - @Test - public void test() { - ListNode l1_4 = new ListNode(18); - ListNode l1_3 = new ListNode(9, l1_4); - ListNode l1_2 = new ListNode(6, l1_3); - ListNode l1_1 = new ListNode(7, l1_2); - - ListNode result = reverseList2(l1_1); - System.out.println(result.val); - System.out.println(result.next.val); - System.out.println(result.next.next.val); - System.out.println(result.next.next.next.val); - } - - -} diff --git a/src/main/java/com/chen/algorithm/study/test238/Solution1.java b/src/main/java/com/chen/algorithm/study/test238/Solution1.java deleted file mode 100644 index c2028f2..0000000 --- a/src/main/java/com/chen/algorithm/study/test238/Solution1.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.chen.algorithm.study.test238; - -import com.alibaba.fastjson.JSON; - -/** - * @Auther: zhunn - * @Date: 2020/10/16 14:30 - * @Description: 除自身以外数组的乘积 - */ -public class Solution1 { - - /** - * 时间复杂度O(N),空间复杂度O(N) - * - * @param nums - * @return - */ - public static int[] productExceptSelf(int[] nums) { - if (nums == null || nums.length == 0) { - return new int[0]; - } - - int length = nums.length; - - // left和right 分别表示左右两侧的乘积列表 - int[] left = new int[length]; - int[] right = new int[length]; - - int[] answer = new int[length]; - - // left[i] 为索引 i 左侧所有元素的乘积 - // 对于索引为 ‘0’ 的元素,因为左侧没有元素,所以left[0]=1 - left[0] = 1; - for (int i = 1; i < length; i++) { - left[i] = left[i - 1] * nums[i - 1]; - } - - // right[i] 为索引 i 右侧所有元素的乘积 - // 对于索引为 ‘length-1’ 的元素,因为右侧没有元素,所以right[length - 1] = 1 - right[length - 1] = 1; - for (int i = length - 2; i >= 0; i--) { - right[i] = right[i + 1] * nums[i + 1]; - } - - // 对于索引i,除nums[i]之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积 - for (int i = 0; i < length; i++) { - answer[i] = left[i] * right[i]; - } - return answer; - } - - /** - * 时间复杂度O(N),空间复杂度O(1) - * - * @param nums - * @return - */ - //public static int[] productExceptSelf1(int[] nums) { - // if (nums == null || nums.length == 0) { - // return new int[0]; - // } - // - // int length = nums.length; - // int[] answer = new int[length]; - // - // // answer[i] 为索引 i 左侧所有元素的乘积 - // // 对于索引为 ‘0’ 的元素,因为左侧没有元素,answer[0]=1 - // answer[0] = 1; - // for (int i = 1; i < length; i++) { - // answer[i] = answer[i - 1] * nums[i - 1]; - // } - // - // // right 为右侧所有元素的乘积 - // // 刚开始右侧没有元素,所以right = 1 - // int right = 1; - // for (int i = length - 1; i >= 0; i--) { - // // 对于索引 i,左边的乘积为answer[i],右边的乘积为right - // answer[i] = right * answer[i]; - // // right 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 right 上 - // right = right * nums[i]; - // } - // return answer; - //} - public static int[] productExceptSelfTest(int[] nums) { - if (nums == null || nums.length == 0) { - return new int[0]; - } - - int length = nums.length; - int[] answer = new int[length]; - - answer[0] = 1; - for (int i = 1; i < length; i++) { - answer[i] = answer[i - 1] * nums[i - 1]; - } - - int right = 1; - for (int i = length - 1; i >= 0; i--) { - answer[i] = right * answer[i]; - right = right * nums[i]; - } - return answer; - } - - public static void main(String[] args) { - int[] nums = {1, 2, 3, 4, 2}; - System.out.println(JSON.toJSONString(productExceptSelf(nums))); - } - -} diff --git a/src/main/java/com/chen/algorithm/study/test24/Solution3.java b/src/main/java/com/chen/algorithm/study/test24/Solution3.java deleted file mode 100644 index 46f6bbc..0000000 --- a/src/main/java/com/chen/algorithm/study/test24/Solution3.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.chen.algorithm.study.test24; - -import org.junit.Test; - -/** - * @Auther: zhunn - * @Date: 2020/10/23 10:48 - * @Description: 两两交换链表中结点:1-递归,2-迭代 - */ -public class Solution3 { - - - /** - * 1-递归 - * @param head - * @return - */ - public ListNode swapPairs1(ListNode head) { - if (head == null || head.next == null) { - return head; - } - ListNode newHead = head.next; - head.next = swapPairs1(newHead.next); - newHead.next = head; - return newHead; - } - - /** - * 2-迭代 - * @param head - * @return - */ - public ListNode swapPairs2(ListNode head) { - if (head == null || head.next == null) { - return head; - } - - ListNode dummyHead = new ListNode(-1); - dummyHead.next = head; - ListNode temp = dummyHead; - - while (temp.next != null && temp.next.next != null) { - ListNode node1 = temp.next; - ListNode node2 = temp.next.next; - - temp.next = node2; - node1.next = node2.next; - node2.next = node1; - - temp = node1; - } - return dummyHead.next; - } - - /** - * 2-迭代(操作head) - * @param head - * @return - */ - public ListNode swapPairs3(ListNode head) { - if (head == null || head.next == null) { - return head; - } - - ListNode dummyHead = new ListNode(-1); - dummyHead.next = head; - ListNode temp = dummyHead; - - while (head != null && head.next != null) { - ListNode node1 = head; - ListNode node2 = head.next; - - temp.next = node2; - node1.next = node2.next; - node2.next = node1; - - temp = node1; - head = node1.next; - } - return dummyHead.next; - } - - @Test - public void test() { - ListNode l1_1 = new ListNode(1); - ListNode l1_2 = new ListNode(2); - ListNode l1_3 = new ListNode(3); - ListNode l1_4 = new ListNode(4); - ListNode l1_5 = new ListNode(5); - - l1_1.next = l1_2; - l1_2.next = l1_3; - l1_3.next = l1_4; - l1_4.next = l1_5; - - ListNode result = swapPairs3(l1_1); - - System.out.println(result.val); - System.out.println(result.next.val); - System.out.println(result.next.next.val); - System.out.println(result.next.next.next.val); - System.out.println(result.next.next.next.next.val); - } -} diff --git a/src/main/java/com/chen/algorithm/study/test25/Solution5.java b/src/main/java/com/chen/algorithm/study/test25/Solution5.java deleted file mode 100644 index 7f02d9d..0000000 --- a/src/main/java/com/chen/algorithm/study/test25/Solution5.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.chen.algorithm.study.test25; - -/** - * @Auther: zhunn - * @Date: 2020/10/24 17:23 - * @Description: K个一组翻转链表 - */ -public class Solution5 { - - /** - * 官网解法 - * @param head - * @param k - * @return - */ - public ListNode reverseKGroup(ListNode head, int k) { - ListNode hair = new ListNode(0); - hair.next = head; - ListNode pre = hair; - - while (head != null) { - ListNode tail = pre; - // 查看剩余部分长度是否大于等于 k - for (int i = 0; i < k; ++i) { - tail = tail.next; - if (tail == null) { - return hair.next; - } - } - ListNode nextTemp = tail.next; - ListNode[] reverse = myReverse(head, tail); - head = reverse[0]; - tail = reverse[1]; - // 把子链表重新接回原链表 - pre.next = head; - tail.next = nextTemp; - pre = tail; - head = tail.next; - } - - return hair.next; - } - - private ListNode[] myReverse(ListNode head, ListNode tail) { - ListNode prev = tail.next; - ListNode p = head; - while (prev != tail) { - ListNode nex = p.next; - p.next = prev; - prev = p; - p = nex; - } - return new ListNode[]{tail, head}; - } - - - public ListNode reverseKGroup1(ListNode head, int k) { - ListNode dummy = new ListNode(0); - dummy.next = head; - - ListNode pre = dummy; - ListNode end = dummy; - - while (end.next != null) { - for (int i = 0; i < k && end != null; i++){end = end.next;} - if (end == null) {break;} - ListNode start = pre.next; - ListNode next = end.next; - end.next = null; - pre.next = reverse(start); - start.next = next; - pre = start; - - end = pre; - } - return dummy.next; - } - - private ListNode reverse(ListNode head) { - ListNode pre = null; - ListNode curr = head; - while (curr != null) { - ListNode next = curr.next; - curr.next = pre; - pre = curr; - curr = next; - } - return pre; - } - - -} diff --git a/src/main/java/com/chen/algorithm/study/test27/Solution2.java b/src/main/java/com/chen/algorithm/study/test27/Solution2.java deleted file mode 100644 index 24cbd15..0000000 --- a/src/main/java/com/chen/algorithm/study/test27/Solution2.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.chen.algorithm.study.test27; - -import org.junit.Test; - -import java.util.Arrays; - -/** - * @Auther: zhunn - * @Date: 2020/10/10 16:40 - * @Description: 移除元素,双指针法 - */ -public class Solution2 { - - public int removeElement(int[] nums, int val) { - if (nums == null || nums.length == 0) return 0; - - int i = 0; - for (int j = 0; j < nums.length; j++) { - if (nums[j] != val) { - nums[i] = nums[j]; - i++; - } - } - System.out.println(Arrays.toString(nums)); - return i; - } - - @Test - public void test() { - System.out.println(removeElement(new int[]{1, 1, 2, 2, 3, 5, 6, 7, 8}, 2)); - } -} diff --git a/src/main/java/com/chen/algorithm/study/test283/Solution2.java b/src/main/java/com/chen/algorithm/study/test283/Solution2.java index e066b48..84c34f4 100644 --- a/src/main/java/com/chen/algorithm/study/test283/Solution2.java +++ b/src/main/java/com/chen/algorithm/study/test283/Solution2.java @@ -43,28 +43,4 @@ public void testCase() { } - - /** - * @author: zhunn - * @param nums - * @return - */ - public int[] moveZeroes1(int[] nums) { - if (nums == null || nums.length == 0) { - return nums; - } - - int i = 0; - for (int j = 0; j < nums.length; j++) { - if (nums[j] != 0) { - nums[i] = nums[j]; - i++; - } - } - - for (int k = i; k < nums.length; k++) { - nums[k] = 0; - } - return nums; - } } diff --git a/src/main/java/com/chen/algorithm/study/test34/Solution4.java b/src/main/java/com/chen/algorithm/study/test34/Solution4.java deleted file mode 100644 index bf8ea9c..0000000 --- a/src/main/java/com/chen/algorithm/study/test34/Solution4.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.chen.algorithm.study.test34; - -import org.junit.Test; - -import java.util.Arrays; - -/** - * @Auther: zhunn - * @Date: 2020/10/10 17:04 - * @Description: 在排序数组中查找元素的第一个和最后一个位置 - * (可使用二分查找到第一个与target相等元素和最后一个与target相等元素 方式,返回下标) - */ -public class Solution4 { - - /** - * 当key=array[mid]时, 往左边一个一个逼近,right = mid -1; 返回left - * - * @param nums - * @param target - * @return - */ - private int leftIndex(int[] nums, int target) { - if (nums == null || nums.length == 0) { - return -1; - } - - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = (right - left) / 2 + left; - if (nums[mid] >= target) { - right = mid - 1; - } else { - left = mid + 1; - } - } - - if (left <= nums.length - 1 && nums[left] == target) { - return left; - } - return -1; - } - - /** - * 当key=array[mid]时, 往右边一个一个逼近,left = mid + 1; 返回right - * - * @param nums - * @param target - * @return - */ - private int rightIndex(int[] nums, int target) { - if (nums == null || nums.length == 0) { - return -1; - } - int left = 0, right = nums.length - 1; - while (left <= right) { - int mid = (right - left) / 2 + left; - if (nums[mid] <= target) { - left = mid + 1; - } else { - right = mid - 1; - } - } - if (right >= 0 && nums[right] == target) { - return right; - } - return -1; - } - - public int[] find(int[] nums, int target) { - int[] res = new int[2]; - res[0] = leftIndex(nums, target); - res[1] = rightIndex(nums, target); - return res; - } - - @Test - public void test() { - int[] nums = new int[]{5, 7, 7, 8, 8, 8, 10}; - int[] res = find(nums, 8); - System.out.println(Arrays.toString(res)); - } - -} diff --git a/src/main/java/com/chen/algorithm/study/test704/Solution.java b/src/main/java/com/chen/algorithm/study/test704/Solution.java index 8dda25c..143871f 100644 --- a/src/main/java/com/chen/algorithm/study/test704/Solution.java +++ b/src/main/java/com/chen/algorithm/study/test704/Solution.java @@ -10,58 +10,58 @@ public class Solution { /** * 适用于升序数组,可做相应调整适用降序数组 */ - public static int bsearch(int[] array, int target) { - if (array == null || array.length == 0 - /*|| target < array[0] || target > array[array.length - 1]*/) { - return -1; - } - - int left = 0; - int right = array.length - 1; - //这里必须是 >=,切记勿遗漏 = - while (right >= left) { - // 当start=Integer.MAX_VALUE时,给它加个1都会溢出。安全的写法是:mid = start + (end-start)/2,但是会造成死循环,弃用 - //int mid = min + (max - min) >> 1; - int mid = (left + right) >> 1; - if (target == array[mid]) { - return mid; - } - if (target < array[mid]) { - right = mid - 1; - } - if (target > array[mid]) { - left = mid + 1; - } - } - return -1; - } + //public static int bsearch(int[] array, int target) { + // if (array == null || array.length == 0 + // /*|| target < array[0] || target > array[array.length - 1]*/) { + // return -1; + // } + // + // int left = 0; + // int right = array.length - 1; + // //这里必须是 >=,切记勿遗漏 = + // while (right >= left) { + // // 当start=Integer.MAX_VALUE时,给它加个1都会溢出。安全的写法是:mid = start + (end-start)/2,但是会造成死循环,弃用 + // //int mid = min + (max - min) >> 1; + // int mid = (left + right) >> 1; + // if (target == array[mid]) { + // return mid; + // } + // if (target < array[mid]) { + // right = mid - 1; + // } + // if (target > array[mid]) { + // left = mid + 1; + // } + // } + // return -1; + //} /** * 查找第一个与target相等的元素 * 当key=array[mid]时, 往左边一个一个逼近,right = mid -1; 返回left */ - public static int bsearch1(int[] array, int target) { - if (array == null || array.length == 0 - /*|| target < array[0] || target > array[array.length - 1]*/) { - return -1; - } - int left = 0; - int right = array.length - 1; - while (right >= left) { - int mid = (left + right) >> 1; - if (array[mid] >= target) { - right = mid - 1; - } else { - left = mid + 1; - } - } - - if (left < array.length && array[left] == target) { - return left; - } - return -1; - - } + //public static int bsearch1(int[] array, int target) { + // if (array == null || array.length == 0 + // /*|| target < array[0] || target > array[array.length - 1]*/) { + // return -1; + // } + // int left = 0; + // int right = array.length - 1; + // while (right >= left) { + // int mid = (left + right) >> 1; + // if (array[mid] >= target) { + // right = mid - 1; + // } else { + // left = mid + 1; + // } + // } + // + // if (left < array.length && array[left] == target) { + // return left; + // } + // return -1; + // + //} /** * 查找最后一个与target相等的元素 @@ -69,26 +69,26 @@ public static int bsearch1(int[] array, int target) { * * @return */ - public static int bsearch2(int[] array, int target) { - if (array == null || array.length == 0 /*|| target < array[0] || target > array[array.length - 1]*/) { - return -1; - } - int left = 0; - int right = array.length - 1; - while (right >= left) { - int mid = (left + right) >> 1; - if (array[mid] <= target) { - left = mid + 1; - } else { - right = mid - 1; - } - } - - if (right >= 0 && array[right] == target) { - return right; - } - return -1; - } + //public static int bsearch2(int[] array, int target) { + // if (array == null || array.length == 0 /*|| target < array[0] || target > array[array.length - 1]*/) { + // return -1; + // } + // int left = 0; + // int right = array.length - 1; + // while (right >= left) { + // int mid = (left + right) >> 1; + // if (array[mid] <= target) { + // left = mid + 1; + // } else { + // right = mid - 1; + // } + // } + // + // if (right >= 0 && array[right] == target) { + // return right; + // } + // return -1; + //} // 二分查找变种说明 //public void test(int[] array, int target){ @@ -112,86 +112,86 @@ public static int bsearch2(int[] array, int target) { /** * 查找第一个等于或者大于key的元素 */ - public static int bsearch3(int[] array, int target) { - if (array == null || array.length == 0) { - return -1; - } - int left = 0; - int right = array.length - 1; - while (right >= left) { - int mid = (left + right) >> 1; - if (array[mid] >= target) { - right = mid - 1; - } else { - left = mid + 1; - } - } - return left; - } + //public static int bsearch3(int[] array, int target) { + // if (array == null || array.length == 0) { + // return -1; + // } + // int left = 0; + // int right = array.length - 1; + // while (right >= left) { + // int mid = (left + right) >> 1; + // if (array[mid] >= target) { + // right = mid - 1; + // } else { + // left = mid + 1; + // } + // } + // return left; + //} /** * 查找第一个大于key的元素 */ - public static int bsearch4(int[] array, int target) { - if (array == null || array.length == 0) { - return -1; - } - int left = 0; - int right = array.length - 1; - while (right >= left) { - int mid = (left + right) >> 1; - if (array[mid] > target) { - right = mid - 1; - } else { - left = mid + 1; - } - } - return left; - } + //public static int bsearch4(int[] array, int target) { + // if (array == null || array.length == 0) { + // return -1; + // } + // int left = 0; + // int right = array.length - 1; + // while (right >= left) { + // int mid = (left + right) >> 1; + // if (array[mid] > target) { + // right = mid - 1; + // } else { + // left = mid + 1; + // } + // } + // return left; + //} /** * 查找最后一个等于或者小于key的元素 */ - public static int bsearch5(int[] array, int target) { - if (array == null || array.length == 0) { - return -1; - } - int left = 0; - int right = array.length - 1; - while (right >= left) { - int mid = (left + right) >> 1; - if (array[mid] <= target) { - left = mid + 1; - } else { - right = mid - 1; - } - } - return right; - } + //public static int bsearch5(int[] array, int target) { + // if (array == null || array.length == 0) { + // return -1; + // } + // int left = 0; + // int right = array.length - 1; + // while (right >= left) { + // int mid = (left + right) >> 1; + // if (array[mid] <= target) { + // left = mid + 1; + // } else { + // right = mid - 1; + // } + // } + // return right; + //} /** * 查找最后一个小于key的元素 */ - public static int bsearch6(int[] array, int target) { - if (array == null || array.length == 0) { - return -1; - } - int left = 0; - int right = array.length - 1; - while (right >= left) { - int mid = (left + right) >> 1; - if (array[mid] < target) { - left = mid + 1; - } else { - right = mid - 1; - } - } - return right; - } + //public static int bsearch6(int[] array, int target) { + // if (array == null || array.length == 0) { + // return -1; + // } + // int left = 0; + // int right = array.length - 1; + // while (right >= left) { + // int mid = (left + right) >> 1; + // if (array[mid] < target) { + // left = mid + 1; + // } else { + // right = mid - 1; + // } + // } + // return right; + //} - public static void main(String[] args) { - int[] array = {1, 1, 3, 6, 6, 6, 7, 9, 17, 17}; - int index = bsearch6(array, 0); - System.out.println(index); - } + //public static void main(String[] args) { + // int[] array = {1, 1, 3, 6, 6, 6, 7, 9, 17, 17}; + // int index = bsearch6(array, 0); + // System.out.println(index); + //} } diff --git a/src/main/java/com/chen/algorithm/study/test92/Solution3.java b/src/main/java/com/chen/algorithm/study/test92/Solution3.java deleted file mode 100644 index de47efd..0000000 --- a/src/main/java/com/chen/algorithm/study/test92/Solution3.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.chen.algorithm.study.test92; - -import org.junit.Test; - -/** - * @Auther: zhunn - * @Date: 2020/10/24 17:23 - * @Description: 反转链表二:1-双指针,2-删除结点递推 - */ -public class Solution3 { - - class ListNode { - int val; - ListNode next; - - ListNode(int x) { - val = x; - } - } - - // 翻转n个节点,返回新链表的头部 - private ListNode reverseN(ListNode head, int n) { - ListNode prev = null; - ListNode curr = head; - for (int i = 0; i < n; i++) { - ListNode oldNext = curr.next; - curr.next = prev; - prev = curr; - curr = oldNext; - } - return prev; - } - - /** - * 1-双指针 - * @param head - * @param m - * @param n - * @return - */ - public ListNode reverseBetween1(ListNode head, int m, int n) { - ListNode dummy = new ListNode(42); - dummy.next = head; - ListNode ptr1 = dummy; - ListNode ptr2 = dummy; - // 找到左右两段的端点 - for (int i = 0; i < m - 1; i++) { - ptr2 = ptr2.next; - } - for (int i = 0; i < n + 1; i++) { - ptr1 = ptr1.next; - } - // 找到中段的尾端点 - ListNode t = ptr2.next; - // 翻转中段,得到中段的头端点 - ListNode h = reverseN(t, n - m + 1); - // 中端的头端点和左段端点相连 - ptr2.next = h; - // 中段的尾端点和右段端点相连 - t.next = ptr1; - return dummy.next; - } - - /** - * 2-删除结点递推 - * @param head - * @param m - * @param n - * @return - */ - public ListNode reverseBetween2(ListNode head, int m, int n){ - if(head == null || head.next == null){ - return head; - } - - ListNode dummy = new ListNode(-1); - dummy.next = head; - ListNode pre = dummy; - for(int i =0;i Date: Mon, 26 Oct 2020 19:02:13 +0800 Subject: [PATCH 03/63] hash heap --- .../algorithm/znn/hash/test15/Solution.java | 145 ++++++++++++++++++ .../algorithm/znn/hash/test18/Solution.java | 64 ++++++++ .../algorithm/znn/hash/test242/Solution.java | 4 +- .../algorithm/znn/hash/test49/Solution.java | 41 +++++ .../com/chen/algorithm/znn/heap/Test.java | 4 + .../algorithm/znn/heap/test215/Solution.java | 52 +++++++ .../algorithm/znn/stack/test155/Solution.java | 36 +++++ .../algorithm/znn/stack/test232/Solution.java | 49 ++++++ 8 files changed, 393 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java new file mode 100644 index 0000000..4d94f7e --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java @@ -0,0 +1,145 @@ +package com.chen.algorithm.znn.hash.test15; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 14:35 + * @Description: 三数之和:排序+双指针 + */ +public class Solution { + + /** + * 官方解法 + * + * @param nums + * @return + */ + public List> threeSum1(int[] nums) { + int n = nums.length; + Arrays.sort(nums); + List> ans = new ArrayList<>(); + // 枚举 a + for (int first = 0; first < n; ++first) { + // 需要和上一次枚举的数不相同 + if (first > 0 && nums[first] == nums[first - 1]) { + continue; + } + // c 对应的指针初始指向数组的最右端 + int third = n - 1; + int target = -nums[first]; + // 枚举 b + for (int second = first + 1; second < n; ++second) { + // 需要和上一次枚举的数不相同 + if (second > first + 1 && nums[second] == nums[second - 1]) { + continue; + } + // 需要保证 b 的指针在 c 的指针的左侧 + while (second < third && nums[second] + nums[third] > target) { + --third; + } + // 如果指针重合,随着 b 后续的增加 + // 就不会有满足 a+b+c=0 并且 b list = new ArrayList<>(); + list.add(nums[first]); + list.add(nums[second]); + list.add(nums[third]); + ans.add(list); + } + } + } + return ans; + } + + //public List> threeSum(int[] nums) { + // int n = nums.length; + // Arrays.sort(nums); + // List> ans = new ArrayList<>(); + // for (int first = 0; first < n; ++first) { + // if (first > 0 && nums[first] == nums[first - 1]) { + // continue; + // } + // int third = n - 1; + // int target = -nums[first]; + // for (int second = first + 1; second < n; ++second) { + // if (second > first + 1 && nums[second] == nums[second - 1]) { + // continue; + // } + // while (second < third && nums[second] + nums[third] > target) { + // --third; + // } + // if (second == third) { + // break; + // } + // if (nums[second] + nums[third] == target) { + // List list = new ArrayList<>(); + // list.add(nums[first]); + // list.add(nums[second]); + // list.add(nums[third]); + // ans.add(list); + // } + // } + // } + // return ans; + //} + + /** + * 推荐此方法,方便记忆 + * + * @param nums + * @return + */ + public List> threeSum2(int[] nums) { + if (nums == null || nums.length < 3) { + return null; + } + + List> ans = new ArrayList<>(); + Arrays.sort(nums); + int len = nums.length; + for (int i = 0; i < len; i++) { + if (nums[i] > 0) { // 第一个数大于0,后面的数是递增的,不会有等于0的组合,直接返回结果 + return ans; + } + if (i > 0 && nums[i] == nums[i - 1]) { // 去重 + continue; + } + int L = i + 1; + int R = len - 1; + while (L < R) { + int sum = nums[i] + nums[L] + nums[R]; + if (sum == 0) { + ans.add(Arrays.asList(nums[i], nums[L], nums[R])); + while (L < R && nums[L] == nums[L + 1]) { // 去重 + L++; + } + while (L < R && nums[R] == nums[R - 1]) { // 去重 + R--; + } + L++; + R--; + } else if (sum < 0) { + L++; + } else { + R--; + } + } + } + return ans; + } + + @Test + public void test() { + int[] arrayNum = {-1, 0, 1, 4, 2, -1, -4}; + List> result = threeSum2(arrayNum); + System.out.println(result); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java new file mode 100644 index 0000000..956be63 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java @@ -0,0 +1,64 @@ +package com.chen.algorithm.znn.hash.test18; + +import com.alibaba.fastjson.JSON; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 15:09 + * @Description: 四数之和:类比三数之和方法 + */ +public class Solution { + + public List> fourSum(int[] nums, int target) { + if (nums == null || nums.length < 4) { + return null; + } + + List> ans = new ArrayList<>(); + Arrays.sort(nums); + + for (int i = 0; i < nums.length; i++) { + if (i > 0 && nums[i] == nums[i - 1]) { + continue; + } + for (int j = i + 1; j < nums.length; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) { + continue; + } + int L = j + 1; + int R = nums.length - 1; + while (L < R) { + int sum = nums[i] + nums[j] + nums[L] + nums[R]; + if (sum == target) { + ans.add(Arrays.asList(nums[i], nums[j], nums[L], nums[R])); + while (L < R && nums[L] == nums[L + 1]) { + L++; + } + while (L < R && nums[R] == nums[R - 1]) { + R--; + } + L++; + R--; + } else if (sum < target) { + L++; + } else { + R--; + } + } + } + } + return ans; + } + + @Test + public void test() { + int[] nums = {1, 0, -1, 0, -2, 2}; + List> ans = fourSum(nums, 0); + System.out.println(JSON.toJSONString(ans)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java index d596714..e5c3ccd 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java @@ -21,8 +21,8 @@ public boolean isAnagram(String s, String t) { counter[t.charAt(i) - 'a']--; } - for (int n : counter) { - if (n != 0) { + for (int i = 0; i < counter.length; i++) { + if (counter[i] != 0) { return false; } } diff --git a/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java new file mode 100644 index 0000000..5c618c8 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java @@ -0,0 +1,41 @@ +package com.chen.algorithm.znn.hash.test49; + +import org.junit.Test; + +import java.util.*; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 11:19 + * @Description: 字母异位词分组 + */ +public class Solution { + + public List> groupAnagrams(String[] strs) { + if (strs == null || strs.length == 0) { + return null; + } + + Map> resuMap = new HashMap<>(); + + for (int i = 0; i < strs.length; i++) { + + char[] chars = strs[i].toCharArray(); + Arrays.sort(chars); + String key = new String(chars); + + if (!resuMap.containsKey(key)) { + resuMap.put(key, new ArrayList<>()); + } + resuMap.get(key).add(strs[i]); + } + return new ArrayList<>(resuMap.values()); + } + + @Test + public void test() { + String[] words = {"eat", "tea", "tan", "ate", "nat", "bat"}; + List> result = groupAnagrams(words); + System.out.println(result); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/heap/Test.java b/src/main/java/com/chen/algorithm/znn/heap/Test.java index 58655f0..3e3fcb0 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/Test.java +++ b/src/main/java/com/chen/algorithm/znn/heap/Test.java @@ -4,6 +4,10 @@ * @Auther: zhunn * @Date: 2020/10/24 17:23 * @Description: 堆相关 + * 1、堆的基本操作 heap/Heap + * + * 2、堆化,大根堆,小根堆,堆排序,堆的应用(优先级队列,topK,中位数) + * java的priorityQueue 用小根堆实现的优先级队列 */ public class Test { } diff --git a/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java new file mode 100644 index 0000000..cbc3430 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java @@ -0,0 +1,52 @@ +package com.chen.algorithm.znn.heap.test215; + +import org.junit.Test; + +import java.util.PriorityQueue; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 16:55 + * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 + */ +public class Solution { + + public int findKthLargest1(int[] nums, int k) { + //if (nums == null || k > nums.length) { + // return -1; + //} + + for (int i = 0; i < nums.length - 1; i++) { + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] > nums[i]) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } + } + + return nums[k - 1]; + } + + public int findKthLargest(int[] nums, int k) { + PriorityQueue queue = new PriorityQueue<>(k); + for (int i = 0; i < nums.length; i++) { + if (queue.size() < k) { + queue.add(nums[i]); + } else if (nums[i] > queue.peek()) { + queue.poll(); + queue.add(nums[i]); + } + } + return queue.peek(); + } + + + @Test + public void testCase() { + int[] n = {3, 2, 3, 1, 2, 4, 5, 5, 6}; + System.out.println(findKthLargest(n, 2)); + + } +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java new file mode 100644 index 0000000..209d335 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java @@ -0,0 +1,36 @@ +package com.chen.algorithm.znn.stack.test155; + +import java.util.Stack; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 18:20 + * @Description: 最小栈 + */ +public class Solution { + + public Stack stack = new Stack<>(); + public Stack minStack = new Stack<>(); + + public void push(Integer value) { + stack.push(value); + + if (minStack.isEmpty() || value < minStack.peek()) { + minStack.push(value); + } + } + + public void pop() { + if (stack.pop().equals(minStack.peek())) { + minStack.pop(); + } + } + + public int top() { + return stack.peek(); + } + + public int getMin() { + return minStack.peek(); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java new file mode 100644 index 0000000..6815a3f --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java @@ -0,0 +1,49 @@ +package com.chen.algorithm.znn.stack.test232; + +import java.util.Stack; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 17:36 + * @Description: 用栈实现队列 + */ +public class Solution { + + private Stack stack1 = new Stack<>(); + private Stack stack2 = new Stack<>(); + + public void push(Integer value) { + stack1.push(value); + } + + public Integer pop() { + if (stack1.isEmpty() && stack2.isEmpty()) { + return null; + } + + if (stack2.isEmpty()) { + while (!stack1.isEmpty()) { + stack2.push(stack1.pop()); + } + } + return stack2.pop(); + } + + public Integer peek() { + if (stack1.isEmpty() && stack2.isEmpty()) { + return null; + } + + if (stack2.isEmpty()) { + while (!stack1.isEmpty()) { + stack2.push(stack1.pop()); + } + } + return stack2.peek(); + } + + public boolean empty() { + return stack1.isEmpty() && stack2.isEmpty(); + } + +} From 6dda9c690aa101276247832120cf161a12b4492a Mon Sep 17 00:00:00 2001 From: chenweijie Date: Mon, 26 Oct 2020 23:28:07 +0800 Subject: [PATCH 04/63] stack --- .../study/test703/ObjectPriorityQueue.java | 2 +- .../algorithm/znn/stack/test225/MyStack.java | 43 +++++++++++++++++ .../algorithm/znn/stack/test225/Solution.java | 41 ++++++++++++++++ .../algorithm/znn/stack/test703/Solution.java | 47 +++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test225/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java diff --git a/src/main/java/com/chen/algorithm/study/test703/ObjectPriorityQueue.java b/src/main/java/com/chen/algorithm/study/test703/ObjectPriorityQueue.java index da4640e..16c3f60 100644 --- a/src/main/java/com/chen/algorithm/study/test703/ObjectPriorityQueue.java +++ b/src/main/java/com/chen/algorithm/study/test703/ObjectPriorityQueue.java @@ -26,7 +26,7 @@ public int add(int num) { if (queue.size() < limit) { queue.offer(num); - } else if (queue.peek() > num) { + } else if (queue.peek() < num) { queue.poll(); queue.offer(num); } diff --git a/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java b/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java new file mode 100644 index 0000000..91311e4 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java @@ -0,0 +1,43 @@ +package com.chen.algorithm.znn.stack.test225; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 22:20 + * @Description: 用两个队列实现一个栈, 官方解法 + */ +public class MyStack { + + private Queue q1; + private Queue q2; + + public MyStack() { + q1 = new LinkedList<>(); + q2 = new LinkedList<>(); + } + + public void push(int value) { + q2.offer(value); + while (!q1.isEmpty()) { + q2.offer(q1.poll()); + } + + Queue temp = q1; + q1 = q2; + q2 = temp; + } + + public int pop() { + return q1.poll(); + } + + public int top() { + return q1.peek(); + } + + public boolean empty() { + return q1.isEmpty(); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test225/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test225/Solution.java new file mode 100644 index 0000000..becb090 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test225/Solution.java @@ -0,0 +1,41 @@ +package com.chen.algorithm.znn.stack.test225; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 21:20 + * @Description: 用两个队列实现一个栈 + */ +public class Solution { + + private Queue q1 = new LinkedList<>(); + private Queue q2 = new LinkedList<>(); + private int top; + + public void push(Integer value) { + q1.add(value); + top = value; + } + + public int pop() { + while (q1.size() > 1) { + q2.add(q1.peek()); + top = q1.remove(); + } + int result = q1.remove(); + Queue temp = q1; + q1 = q2; + q2 = temp; + return result; + } + + public int top() { + return top; + } + + public boolean empty() { + return q1.isEmpty() && q2.isEmpty(); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java new file mode 100644 index 0000000..73556ca --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java @@ -0,0 +1,47 @@ +package com.chen.algorithm.znn.stack.test703; + +import org.junit.Test; + +import java.util.PriorityQueue; + +/** + * @Auther: zhunn + * @Date: 2020/10/26 16:55 + * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 + */ +public class Solution { + + class KthLargest { + private PriorityQueue queue; + private int limit; + + public KthLargest(int size, int[] nums) { + this.limit = size; + queue = new PriorityQueue<>(limit); + for (int num : nums) { + add(num); + } + } + + public int add(int num) { + + if (queue.size() < limit) { + queue.offer(num); + } else if (queue.peek() < num) { + queue.poll(); + queue.offer(num); + } + + return queue.peek(); + } + } + + + @Test + public void testCase() { + int[] n = {3, 2, 3, 1, 2, 4, 5, 5, 6}; + KthLargest kthLargest = new KthLargest(2, n); + System.out.println(kthLargest.add(3)); + + } +} From e3a38c639c4120d937258597fd3f3457876de949 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 27 Oct 2020 18:34:12 +0800 Subject: [PATCH 05/63] string --- .../algorithm/znn/stack/test20/Solution.java | 50 ++++++++ .../algorithm/znn/stack/test227/Solution.java | 67 ++++++++++ .../algorithm/znn/stack/test239/Solution.java | 118 ++++++++++++++++++ .../algorithm/znn/string/test14/Solution.java | 36 ++++++ .../algorithm/znn/string/test3/Solution.java | 42 +++++++ .../znn/string/test415/Solution.java | 40 ++++++ .../algorithm/znn/string/test5/Solution.java | 87 +++++++++++++ 7 files changed, 440 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/string/test14/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/string/test3/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/string/test415/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/string/test5/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java new file mode 100644 index 0000000..be03ebe --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java @@ -0,0 +1,50 @@ +package com.chen.algorithm.znn.stack.test20; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 14:18 + * @Description: 有效的括号 + */ +public class Solution { + + public boolean isValid(String s) { + if (s == null) { + return false; + } + Map signMap = new HashMap<>(3); + signMap.put('(', ')'); + signMap.put('[', ']'); + signMap.put('{', '}'); + + Stack stack = new Stack<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (signMap.containsKey(c)) { + stack.push(c); + } else { + if (stack.isEmpty() || signMap.get(stack.pop()) != c) { + return false; + } + } + } + return stack.isEmpty(); + } + + @Test + public void test() { + System.out.println(isValid("")); + System.out.println(isValid(" ")); + System.out.println(isValid("( ")); + System.out.println(isValid("()")); + System.out.println(isValid("(]")); + System.out.println(isValid("()[]{}")); + System.out.println(isValid("([)]")); + System.out.println(isValid("{[]}")); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java new file mode 100644 index 0000000..831ee36 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java @@ -0,0 +1,67 @@ +package com.chen.algorithm.znn.stack.test227; + +import org.junit.Test; + +import java.util.Stack; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 11:11 + * @Description: 基本计算II + */ +public class Solution { + + public void vert() { + String a = "796"; + int num = 0; + for (char c : a.toCharArray()) { + num = num * 10 + (c - '0'); + } + System.out.println(num); + } + + public int calculate(String s) { + if (s == null || s.trim().equals("")) { + return 0; + } + + Stack stack = new Stack<>(); + char sign = '+'; + int num = 0; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (Character.isDigit(c)) { + num = num * 10 + (c - '0'); + } + + if ((!Character.isDigit(c) && c != ' ') || i == s.length() - 1) { + int pre; + if (sign == '+') { + stack.push(num); + } else if (sign == '-') { + stack.push(-num); + } else if (sign == '*') { + pre = stack.pop(); + stack.push(pre * num); + } else if (sign == '/') { + pre = stack.pop(); + stack.push(pre / num); + } + sign = c; + num = 0; + } + } + int res = 0; + while (!stack.isEmpty()) { + res += stack.pop(); + } + return res; + } + + @Test + public void test() { + vert(); + System.out.println(calculate("60+20-30+5/2 ")); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java new file mode 100644 index 0000000..9b35dc3 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java @@ -0,0 +1,118 @@ +package com.chen.algorithm.znn.stack.test239; + +import org.junit.Test; + +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.LinkedList; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 14:32 + * @Description: 滑动窗口最大值 + */ +public class Solution { + + + /** + * 采用双端队列存储数组值 + * + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow(int[] nums, int k) { + int n = nums.length; + if (n * k == 0) return new int[0]; + if (k == 1) return nums; + + int[] res = new int[nums.length - k + 1]; + // 递减队列 + ArrayDeque queue = new ArrayDeque<>(); + + for (int i = 0; i < nums.length; i++) { + + // 添加滑入的数 nums[i] ,构造递减队列 + while (!queue.isEmpty() && queue.peekLast() < nums[i]) { + queue.pollLast(); + } + queue.addLast(nums[i]); + + // 删除滑出的数 nums[i - k],如果删除的数等于队头,删除队头 + if (i >= k && nums[i - k] == queue.peekFirst()) { + queue.pollFirst(); + } + + // 写入当前最大值 + if (i >= k - 1) { + res[i - k + 1] = queue.peekFirst(); + } + } + return res; + } + + /** + * 采用双端队列存储数组下标 + * https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-2/ + * + * @param nums + * @param k + * @return + */ + public int[] maxSlidingWindow1(int[] nums, int k) { + if (nums == null || nums.length < 2) return nums; + // 双向队列 保存当前窗口最大值的数组位置 保证队列中数组位置的数值按从大到小排序 + LinkedList queue = new LinkedList(); + // 结果数组 + int[] result = new int[nums.length - k + 1]; + // 遍历nums数组 + for (int i = 0; i < nums.length; i++) { + // 保证从大到小 如果前面数小则需要依次弹出,直至满足要求 + while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { + queue.pollLast(); + } + // 添加当前值对应的数组下标 + queue.addLast(i); + // 判断当前队列中队首的值是否有效 + if (queue.peek() <= i - k) { + queue.poll(); + } + // 当窗口长度为k时 保存当前窗口中最大值 + if (i + 1 >= k) { + result[i + 1 - k] = nums[queue.peek()]; + } + } + return result; + } + + public int[] maxSlidingWindow2(int[] nums, int k) { + if (nums == null || nums.length < 2) { + return nums; + } + + LinkedList queue = new LinkedList<>(); + int[] res = new int[nums.length - k + 1]; + for (int i = 0; i < nums.length; i++) { + while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { + queue.pollLast(); + } + queue.addLast(i); + if (queue.peekFirst() <= i - k) { + queue.pollFirst(); + } + + if (i + 1 >= k) { + res[i + 1 - k] = nums[queue.peekFirst()]; + } + } + return res; + } + + @Test + public void testCase() { + + int[] nums = {1, 3, -1, -3, 5, 3, 2, 6, 7}; + int k = 3; + System.out.println(Arrays.toString(maxSlidingWindow2(nums, k))); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java new file mode 100644 index 0000000..a8a64f4 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java @@ -0,0 +1,36 @@ +package com.chen.algorithm.znn.string.test14; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 15:51 + * @Description: 最长公共前缀 + */ +public class Solution { + + public String longestCommonPrefix(String[] strs) { + if (strs == null || strs.length == 0) { + return ""; + } + + String prefix = strs[0]; + + for (int i = 1; i < strs.length; i++) { + while (!strs[i].startsWith(prefix)) { + if (prefix.length() == 0) { + return ""; + } + prefix = prefix.substring(0, prefix.length() - 1); + } + } + return prefix; + } + + @Test + public void test() { + String[] strs = {"flower", "flow", "flight"}; + String prefix = longestCommonPrefix(strs); + System.out.println(prefix); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java new file mode 100644 index 0000000..bcecef0 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java @@ -0,0 +1,42 @@ +package com.chen.algorithm.znn.string.test3; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 16:02 + * @Description: 无重复字符的最长子串 + */ +public class Solution { + + public int lengthOfLongestSubstring(String s) { + if (s == null || s.length() == 0) { + return 0; + } + + Map map = new HashMap<>(); + int ans = 0; + int n = s.length(); + + for (int start = 0, end = 0; end < n; end++) { + char c = s.charAt(end); + if (map.containsKey(c)) { + start = Math.max(start, map.get(c)); + } + + ans = Math.max(ans, end - start + 1); + map.put(c, end + 1); + } + return ans; + } + + @Test + public void test() { + System.out.println(lengthOfLongestSubstring("abcabcbb")); + System.out.println(lengthOfLongestSubstring("bbbbb")); + System.out.println(lengthOfLongestSubstring("pwwkew")); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java new file mode 100644 index 0000000..92ed699 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java @@ -0,0 +1,40 @@ +package com.chen.algorithm.znn.string.test415; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 16:03 + * @Description: 字符串相加 + */ +public class Solution { + + public String addStrings(String num1, String num2) { + if (num1 == null) { + return num2; + } + if (num2 == null) { + return num1; + } + + int i = num1.length() - 1, j = num2.length() - 1, carry = 0; + StringBuilder ans = new StringBuilder(); + + while (i >= 0 || j >= 0 || carry != 0) { + int n1 = i >= 0 ? num1.charAt(i) - '0' : 0; + int n2 = j >= 0 ? num2.charAt(j) - '0' : 0; + int temp = n1 + n2 + carry; + ans.append(temp % 10); + carry = temp / 10; + i--; + j--; + } + + return ans.reverse().toString(); + } + + @Test + public void test() { + System.out.println(addStrings("623", "401")); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java new file mode 100644 index 0000000..e0f1162 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java @@ -0,0 +1,87 @@ +package com.chen.algorithm.znn.string.test5; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/27 16:02 + * @Description: 最长回文子串: + * 1-动态规划;时间复杂度:O(n2),空间复杂度:O(n2) + * 2-中心扩展算法;时间复杂度:O(n2),空间复杂度:O(1) + */ +public class Solution { + + /** + * 1-动态规划 + * + * @param s + * @return x 表示增量,子串长度, + * 状态转移方程:dp[i][j]表示从i到j的字符串 表示字符串 s 的第 i 到 j 个字母组成的串 + */ + public String longestPalindrome1(String s) { + if (s == null || s.length() < 2) { + return s; + } + + int n = s.length(); + String ans = ""; + boolean[][] dp = new boolean[n][n]; + for (int x = 0; x < n; x++) { + for (int i = 0; i + x < n; i++) { + int j = i + x; + if (x == 0) { + dp[i][j] = true; + } else if (x == 1) { + dp[i][j] = (s.charAt(i) == s.charAt(j)); + } else { + dp[i][j] = (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j)); + } + + if (dp[i][j] && x + 1 > ans.length()) { + ans = s.substring(i, i + x + 1); + } + } + } + return ans; + } + + /** + * 2-中心扩展算法 + * + * @param s + * @return + */ + public String longestPalindrome2(String s) { + if (s == null || s.length() < 1) { + return ""; + } + int start = 0, end = 0; + for (int i = 0; i < s.length(); i++) { + int len1 = expandAroundCenter(s, i, i); + int len2 = expandAroundCenter(s, i, i + 1); + int len = Math.max(len1, len2); + if (len > end - start) { + start = i - (len - 1) / 2; + end = i + len / 2; + } + } + return s.substring(start, end + 1); + } + + private int expandAroundCenter(String s, int left, int right) { + while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) { + --left; + ++right; + } + return right - left - 1; + } + + @Test + public void test() { + System.out.println("123456".substring(0, 3)); + System.out.println(longestPalindrome1("dcacdefd")); + System.out.println(longestPalindrome1("babad")); + System.out.println(longestPalindrome1("cbbd")); + } + +} From d7493485b63bf3a9ed5eba1f2b4e84cbd3c6ba15 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 27 Oct 2020 19:07:16 +0800 Subject: [PATCH 06/63] note --- src/main/java/com/chen/algorithm/znn/note | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/note diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note new file mode 100644 index 0000000..981bb0c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/note @@ -0,0 +1,27 @@ +文档上没有,代码有的题: +test4 +test10 +test11 +test13 +test17 +test31 +test33 +test75 +test90 +test139 +test234 +test287 +test343 +test347 +test437 +test496 +test674 +offer.test57 + +文档上有,代码上没有的题: +test36 +test199 +test474 +test494 +test213 +test337 \ No newline at end of file From e05b29c91459d0720bb42494739566458f34c7c5 Mon Sep 17 00:00:00 2001 From: zhunn Date: Wed, 28 Oct 2020 18:20:41 +0800 Subject: [PATCH 07/63] tree-1 --- src/main/java/com/chen/algorithm/znn/note | 7 +- .../com/chen/algorithm/znn/tree/TreeNode.java | 25 ++++ .../znn/tree/offer/test34/Solution.java | 10 ++ .../algorithm/znn/tree/test102/Solution.java | 61 +++++++++ .../algorithm/znn/tree/test103/Solution.java | 128 ++++++++++++++++++ .../algorithm/znn/tree/test107/Solution.java | 101 ++++++++++++++ .../algorithm/znn/tree/test144/Solution.java | 76 +++++++++++ .../algorithm/znn/tree/test145/Solution.java | 112 +++++++++++++++ .../algorithm/znn/tree/test199/Solution.java | 9 ++ .../algorithm/znn/tree/test226/Solution.java | 105 ++++++++++++++ .../algorithm/znn/tree/test94/Solution.java | 96 +++++++++++++ 11 files changed, 729 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/chen/algorithm/znn/tree/TreeNode.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 981bb0c..42dafff 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -24,4 +24,9 @@ test199 test474 test494 test213 -test337 \ No newline at end of file +test337 + +剑指offer第2版:共75题 +简单:共41题 +中等:共29题 +难:共5题 \ No newline at end of file diff --git a/src/main/java/com/chen/algorithm/znn/tree/TreeNode.java b/src/main/java/com/chen/algorithm/znn/tree/TreeNode.java new file mode 100644 index 0000000..0ea49dd --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/TreeNode.java @@ -0,0 +1,25 @@ +package com.chen.algorithm.znn.tree; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 10:25 + * @Description: 二叉树节点 + */ +public class TreeNode { + + public int val; + public TreeNode left; + public TreeNode right; + + public TreeNode(){} + + public TreeNode(int val){ + this.val = val; + } + + public TreeNode(int val, TreeNode left, TreeNode right){ + this.val = val; + this.left = left; + this.right = right; + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java new file mode 100644 index 0000000..e04cc0a --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java @@ -0,0 +1,10 @@ +package com.chen.algorithm.znn.tree.offer.test34; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 10:11 + * @Description: 二叉树中和为某一值的路径 + */ +public class Solution { + +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java new file mode 100644 index 0000000..56c1f8c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java @@ -0,0 +1,61 @@ +package com.chen.algorithm.znn.tree.test102; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 13:52 + * @Description: 二叉树的层序遍历:1-BFS实现 + */ +public class Solution { + + /** + * 1-BFS + * + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + if (root == null) { + return null; + } + + List> res = new ArrayList<>(); + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + int size = queue.size(); + List levelList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + levelList.add(node.val); + + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + } + res.add(levelList); + } + return res; + } + + @Test + public void test() { + TreeNode left = new TreeNode(9); + TreeNode right = new TreeNode(20, new TreeNode(15), new TreeNode(7)); + TreeNode root = new TreeNode(3, left, right); + + List> res = levelOrder(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java new file mode 100644 index 0000000..78f15ca --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java @@ -0,0 +1,128 @@ +package com.chen.algorithm.znn.tree.test103; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/solution/jiao-ti-shi-yong-zhan-jian-dan-shi-xian-ju-chi-xin/ + * + * @Auther: zhunn + * @Date: 2020/10/28 15:03 + * @Description: 二叉树的锯齿形层次遍历:交替使用栈 + */ +public class Solution { + + /** + * 交替使用栈 + * + * @param root + * @return + */ + public List> zigzagLevelOrder1(TreeNode root) { + if (root == null) { + return null; + } + + List> res = new ArrayList<>(); + Stack stack1 = new Stack<>(); + Stack stack2 = new Stack<>(); + + stack1.push(root); + + while (!stack1.isEmpty() || !stack2.isEmpty()) { + List subList = new ArrayList<>(); + + if (!stack1.isEmpty()) { + while (!stack1.isEmpty()) { + TreeNode node = stack1.pop(); + subList.add(node.val); + if (node.left != null) { + stack2.push(node.left); + } + if (node.right != null) { + stack2.push(node.right); + } + } + res.add(subList); + } else { + while (!stack2.isEmpty()) { + TreeNode node = stack2.pop(); + subList.add(node.val); + + if (node.right != null) { + stack1.push(node.right); + } + if (node.left != null) { + stack1.push(node.left); + } + } + res.add(subList); + } + } + return res; + } + + //public List> zigzagLevelOrder(TreeNode root) { + // List> list = new ArrayList<>(); + // if (root == null) { + // return list; + // } + // //栈1来存储右节点到左节点的顺序 + // Stack stack1 = new Stack<>(); + // //栈2来存储左节点到右节点的顺序 + // Stack stack2 = new Stack<>(); + // + // //根节点入栈 + // stack1.push(root); + // + // //每次循环中,都是一个栈为空,一个栈不为空,结束的条件两个都为空 + // while (!stack1.isEmpty() || !stack2.isEmpty()) { + // List subList = new ArrayList<>(); // 存储这一个层的数据 + // TreeNode cur; + // + // if (!stack1.isEmpty()) { //栈1不为空,则栈2此时为空,需要用栈2来存储从下一层从左到右的顺序 + // while (!stack1.isEmpty()) { //遍历栈1中所有元素,即当前层的所有元素 + // cur = stack1.pop(); + // subList.add(cur.val); //存储当前层所有元素 + // + // if (cur.left != null) { //左节点不为空加入下一层 + // stack2.push(cur.left); + // } + // if (cur.right != null) { //右节点不为空加入下一层 + // stack2.push(cur.right); + // } + // } + // list.add(subList); + // } else {//栈2不为空,则栈1此时为空,需要用栈1来存储从下一层从右到左的顺序 + // while (!stack2.isEmpty()) { + // cur = stack2.pop(); + // subList.add(cur.val); + // + // if (cur.right != null) {//右节点不为空加入下一层 + // stack1.push(cur.right); + // } + // if (cur.left != null) { //左节点不为空加入下一层 + // stack1.push(cur.left); + // } + // } + // list.add(subList); + // } + // } + // return list; + //} + + @Test + public void test() { + TreeNode left = new TreeNode(9); + TreeNode right = new TreeNode(20, new TreeNode(15), new TreeNode(7)); + TreeNode root = new TreeNode(3, left, right); + + List> res = zigzagLevelOrder1(root); + System.out.println(JSON.toJSON(res)); + } +} \ No newline at end of file diff --git a/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java new file mode 100644 index 0000000..aeb5c08 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java @@ -0,0 +1,101 @@ +package com.chen.algorithm.znn.tree.test107; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.*; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 15:50 + * @Description: 二叉树的层次遍历II + */ +public class Solution { + + /** + * 使用队列存储每层元素,用栈存储每层的结果集 + * @param root + * @return + */ + public List> levelOrderBottom(TreeNode root) { + if (root == null) { + return null; + } + + Stack> stack = new Stack<>(); + Queue queue = new LinkedList<>(); + queue.add(root); + + while (!queue.isEmpty()) { + int size = queue.size(); + List subList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + subList.add(node.val); + + if (node.left != null) { + queue.add(node.left); + } + + if (node.right != null) { + queue.add(node.right); + } + } + + stack.push(subList); + } + + List> res = new ArrayList<>(); + while (!stack.isEmpty()) { + res.add(stack.pop()); + } + return res; + } + + /** + * 使用java的LinkedList的性质,从上到下遍历,将新遍历的层结果集放入linkedlist的头部 + * @param root + * @return + */ + public List> levelOrderBottom1(TreeNode root) { + if (root == null) { + return null; + } + + List> res = new LinkedList<>(); + Queue queue = new LinkedList<>(); + queue.add(root); + + while (!queue.isEmpty()) { + int size = queue.size(); + List subList = new ArrayList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + subList.add(node.val); + + if (node.left != null) { + queue.add(node.left); + } + + if (node.right != null) { + queue.add(node.right); + } + } + + res.add(0, subList); + } + + return res; + } + + @Test + public void test() { + TreeNode left = new TreeNode(9); + TreeNode right = new TreeNode(20, new TreeNode(15), new TreeNode(7)); + TreeNode root = new TreeNode(3, left, right); + + List> res = levelOrderBottom1(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java new file mode 100644 index 0000000..a3aeb29 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java @@ -0,0 +1,76 @@ +package com.chen.algorithm.znn.tree.test144; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 16:25 + * @Description: 二叉树的前序遍历:1-递归;2-迭代 + */ +public class Solution { + + /** + * 1-递归 + * + * @param root + * @return + */ + public List preorderTraversal1(TreeNode root) { + if (root == null) { + return null; + } + List res = new ArrayList<>(); + preOrder(root, res); + return res; + } + + private void preOrder(TreeNode root, List res) { + if (root == null) { + return; + } + + res.add(root.val); + preOrder(root.left, res); + preOrder(root.right, res); + } + + public List preorderTraversal2(TreeNode root) { + if (root == null) { + return null; + } + + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + + stack.push(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + res.add(node.val); + + if (node.right != null) { + stack.push(node.right); + } + + if (node.left != null) { + stack.push(node.left); + } + } + + return res; + } + + @Test + public void test() { + TreeNode right = new TreeNode(2, new TreeNode(3), null); + TreeNode root = new TreeNode(1, null, right); + + List res = preorderTraversal2(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java new file mode 100644 index 0000000..4e2ed22 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java @@ -0,0 +1,112 @@ +package com.chen.algorithm.znn.tree.test145; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.*; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 10:28 + * @Description: 二叉树的后序遍历:1-递归;2-迭代(时间复杂度和空间复杂度都是O(n)) + */ +public class Solution { + + /** + * 1-递归 + * + * @param root + * @return + */ + public List postorderTraversal1(TreeNode root) { + if (root == null) { + return null; + } + List res = new ArrayList<>(); + postorder(root, res); + return res; + } + + private void postorder(TreeNode root, List res) { + if (root == null) return; + + postorder(root.left, res); + postorder(root.right, res); + res.add(root.val); + } + + /** + * 2-迭代法,两个栈实现 + * @param root + * @return + */ + public List postorderTraversal2(TreeNode root) { + if (root == null) return null; + + List res = new ArrayList<>(); + Stack stack1 = new Stack<>(); + Stack stack2 = new Stack<>(); + + stack1.push(root); + while (!stack1.isEmpty()) { + TreeNode node = stack1.pop(); + stack2.push(node); + + if (node.left != null) { + stack1.push(node.left); + } + + if (node.right != null) { + stack1.push(node.right); + } + } + + while (!stack2.isEmpty()) { + res.add(stack2.pop().val); + } + + return res; + } + + /** + * 2-迭代法 官方题解,双端队列实现 + * + * @param root + * @return + */ + public List postorderTraversal(TreeNode root) { + List res = new ArrayList<>(); + if (root == null) { + return res; + } + + Deque stack = new LinkedList<>(); + TreeNode prev = null; + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + if (root.right == null || root.right == prev) { + res.add(root.val); + prev = root; + root = null; + } else { + stack.push(root); + root = root.right; + } + } + return res; + } + + @Test + public void test() { + TreeNode right = new TreeNode(2, new TreeNode(3), null); + TreeNode root = new TreeNode(1, null, right); + + List res = postorderTraversal2(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java new file mode 100644 index 0000000..d6e4080 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.tree.test199; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 17:41 + * @Description: 二叉树的右视图 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java new file mode 100644 index 0000000..a9a870a --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java @@ -0,0 +1,105 @@ +package com.chen.algorithm.znn.tree.test226; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.apache.zookeeper.server.quorum.flexible.QuorumHierarchical; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * https://leetcode-cn.com/problems/invert-binary-tree/solution/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/ + * + * @Auther: zhunn + * @Date: 2020/10/28 17:58 + * @Description: 翻转二叉树:1-递归;2-迭代 + */ +public class Solution { + + /** + * 1-递归 + * + * @param root + * @return + */ + public TreeNode invertTree1(TreeNode root) { + if (root == null) { + return root; + } + TreeNode temp = root.right; + root.right = root.left; + root.left = temp; + + invertTree1(root.left); + invertTree1(root.right); + return root; + } + + /** + * 2-迭代 + * + * @param root + * @return + */ + public TreeNode invertTree2(TreeNode root) { + if (root == null) { + return root; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + + TreeNode temp = node.right; + node.right = node.left; + node.left = temp; + + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + } + return root; + } + + //public TreeNode invertTree3(TreeNode root) { + // if (root == null) { + // return null; + // } + // //将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素 + // LinkedList queue = new LinkedList<>(); + // queue.add(root); + // while (!queue.isEmpty()) { + // //每次都从队列中拿一个节点,并交换这个节点的左右子树 + // TreeNode tmp = queue.poll(); + // TreeNode left = tmp.left; + // tmp.left = tmp.right; + // tmp.right = left; + // //如果当前节点的左子树不为空,则放入队列等待后续处理 + // if (tmp.left != null) { + // queue.add(tmp.left); + // } + // //如果当前节点的右子树不为空,则放入队列等待后续处理 + // if (tmp.right != null) { + // queue.add(tmp.right); + // } + // + // } + // //返回处理完的根节点 + // return root; + //} + + @Test + public void test() { + TreeNode left = new TreeNode(9); + TreeNode right = new TreeNode(20, new TreeNode(15), new TreeNode(7)); + TreeNode root = new TreeNode(3, left, right); + + TreeNode res = invertTree2(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java new file mode 100644 index 0000000..90c28ca --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java @@ -0,0 +1,96 @@ +package com.chen.algorithm.znn.tree.test94; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/94er-cha-shu-de-zhong-xu-bian-li-by-wulin-v/ + * + * @Auther: zhunn + * @Date: 2020/10/28 16:25 + * @Description: 二叉树的中序遍历:1-递归;2-迭代 + */ +public class Solution { + + /** + * 1-递归 + * + * @param root + * @return + */ + public List inorderTraversal1(TreeNode root) { + if (root == null) { + return null; + } + List res = new ArrayList<>(); + inOrder(root, res); + return res; + } + + private void inOrder(TreeNode root, List res) { + if (root == null) { + return; + } + inOrder(root.left, res); + res.add(root.val); + inOrder(root.right, res); + } + + /** + * 2-迭代 + * @param root + * @return + */ + public List inorderTraversal2(TreeNode root) { + if (root == null) { + return null; + } + + List res = new ArrayList<>(); + Stack stack = new Stack<>(); + TreeNode curr = root; + + while (!stack.isEmpty() || curr != null) { + while (curr != null) { + stack.push(curr); + curr = curr.left; + } + + TreeNode temp = stack.pop(); + res.add(temp.val); + curr = temp.right; + } + return res; + } + + + //public List inorderTraversal3(TreeNode root) { + // List list = new ArrayList<>(); + // Stack s = new Stack<>(); + // while (root != null || !s.isEmpty()) { + // while (root != null) { //当前节点不为空,一直将左子树入栈 + // s.push(root); + // root = root.left; + // } + // TreeNode tem = s.pop(); //出栈 + // list.add(tem.val); // 操作数据 + // root = tem.right; //对出栈的节点检查是有否还有左节点,有的话继续入栈,没有的话就操作叶子节点的上一个节点 + // } + // return list; + //} + + @Test + public void test() { + TreeNode right = new TreeNode(2, new TreeNode(3), null); + TreeNode root = new TreeNode(1, null, right); + + List res = inorderTraversal2(root); + System.out.println(JSON.toJSON(res)); + } + +} From d0d7488d401861d225a5c83fba99845d5415cd9f Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 29 Oct 2020 19:08:32 +0800 Subject: [PATCH 08/63] tree-2 --- .../algorithm/study/test111/Solution2.java | 2 +- .../chen/algorithm/study/test98/Solution.java | 2 +- .../algorithm/znn/tree/test101/Solution.java | 82 +++++++++++++++++ .../algorithm/znn/tree/test104/Solution.java | 70 +++++++++++++++ .../algorithm/znn/tree/test111/Solution.java | 89 +++++++++++++++++++ .../algorithm/znn/tree/test235/Solution.java | 35 ++++++++ .../algorithm/znn/tree/test236/Solution.java | 86 ++++++++++++++++++ .../algorithm/znn/tree/test538/Solution.java | 35 ++++++++ .../algorithm/znn/tree/test543/Solution.java | 58 ++++++++++++ .../algorithm/znn/tree/test617/Solution.java | 40 +++++++++ .../algorithm/znn/tree/test96/Solution.java | 10 +++ .../algorithm/znn/tree/test98/Solution.java | 77 ++++++++++++++++ 12 files changed, 584 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java diff --git a/src/main/java/com/chen/algorithm/study/test111/Solution2.java b/src/main/java/com/chen/algorithm/study/test111/Solution2.java index 2d59b66..6cdb1ff 100644 --- a/src/main/java/com/chen/algorithm/study/test111/Solution2.java +++ b/src/main/java/com/chen/algorithm/study/test111/Solution2.java @@ -16,6 +16,6 @@ public int minDepth(TreeNode root) { int left = minDepth(root.left); int right = minDepth(root.right); - return (left == 0 || right == 0) ? 1 : Math.min(left, right) + 1; + return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1; } } diff --git a/src/main/java/com/chen/algorithm/study/test98/Solution.java b/src/main/java/com/chen/algorithm/study/test98/Solution.java index b7b37f1..c6ea865 100644 --- a/src/main/java/com/chen/algorithm/study/test98/Solution.java +++ b/src/main/java/com/chen/algorithm/study/test98/Solution.java @@ -29,7 +29,7 @@ public boolean isValidBST(TreeNode root) { } - public boolean isValid(TreeNode root, Integer max, Integer min) { + public boolean isValid(TreeNode root, Integer min, Integer max) { if (root == null) { return true; diff --git a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java new file mode 100644 index 0000000..63aad2c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java @@ -0,0 +1,82 @@ +package com.chen.algorithm.znn.tree.test101; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 11:03 + * @Description: 对称二叉树:1-递归,2-迭代 + */ +public class Solution { + + /** + * 1-递归 + * + * @param root + * @return + */ + public boolean isSymmetric1(TreeNode root) { + return isMirror(root, root); + } + + private boolean isMirror(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return true; + } + if (root1 == null || root2 == null) { + return false; + } + return (root1.val == root2.val) && isMirror(root1.left, root2.right) && isMirror(root1.right, root2.left); + } + + /** + * 2-迭代 + * + * @param root + * @return + */ + public boolean isSymmetric2(TreeNode root) { + return check(root, root); + } + + private boolean check(TreeNode u, TreeNode v) { + Queue queue = new LinkedList<>(); + queue.add(u); + queue.add(v); + while (!queue.isEmpty()) { + u = queue.poll(); + v = queue.poll(); + if (u == null && v == null) { + continue; + } + if ((u == null || v == null) || (u.val != v.val)) { + return false; + } + + queue.add(u.left); + queue.add(v.right); + + queue.add(u.right); + queue.add(v.left); + } + return true; + } + + @Test + public void test() { + TreeNode left3 = new TreeNode(3); + TreeNode right4 = new TreeNode(4); + TreeNode left3_3 = new TreeNode(3); + TreeNode right4_4 = new TreeNode(4); + TreeNode left2 = new TreeNode(2, left3, right4); + TreeNode right2 = new TreeNode(2, right4_4, left3_3); + TreeNode root = new TreeNode(1, left2, right2); + + System.out.println(isSymmetric2(root)); + + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java new file mode 100644 index 0000000..07debed --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java @@ -0,0 +1,70 @@ +package com.chen.algorithm.znn.tree.test104; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 17:57 + * @Description: 二叉树的最大深度:1-递归;2-广度优先搜索(BFS-层次遍历) + */ +public class Solution { + + /** + * 1-递归 + * + * @param root + * @return + */ + public int maxDepth(TreeNode root) { + return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; + } + + /** + * 2-广度优先搜索(层次遍历) + * + * @param root + * @return + */ + public int maxDepth2(TreeNode root) { + if (root == null) { + return 0; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + + int maxDepth = 0; + while (!queue.isEmpty()) { + maxDepth++; + + int len = queue.size(); + for (int i = 0; i < len; i++) { + TreeNode node = queue.poll(); + + if (node.left != null) { + queue.add(node.left); + } + + if (node.right != null) { + queue.add(node.right); + } + } + } + return maxDepth; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + int res = maxDepth2(root); + System.out.println(res); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java new file mode 100644 index 0000000..c8a9f60 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java @@ -0,0 +1,89 @@ +package com.chen.algorithm.znn.tree.test111; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 18:40 + * @Description: 二叉树的最小深度:1-深度优先搜索(DFS),即递归;2-广度优先搜索(BFS) + */ +public class Solution { + + /** + * 1-深度优先搜索(DFS),即递归 + * + * @param root + * @return + */ + public int minDepth(TreeNode root) { + + if (root == null) { + return 0; + } + int left = minDepth(root.left); + int right = minDepth(root.right); + + return (left == 0 || right == 0) ? left + right + 1 : Math.min(left, right) + 1; + } + + public int minDepth1(TreeNode root) { + if (root == null) { + return 0; + } + + int leftDepth = minDepth1(root.left); + int rightDepth = minDepth1(root.right); + + return root.left == null || root.right == null ? leftDepth + rightDepth + 1 : Math.min(leftDepth, rightDepth) + 1; + } + + /** + * 2-广度优先搜索(BFS) + * + * @param root + * @return + */ + public int minDepth2(TreeNode root) { + if (root == null) { + return 0; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + + int minDepth = 0; + while (!queue.isEmpty()) { + minDepth++; + + int length = queue.size(); + for (int i = 0; i < length; i++) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + + if (node.left == null && node.right == null) { + return minDepth; + } + } + } + return minDepth; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + int res = minDepth1(left); + System.out.println(res); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java new file mode 100644 index 0000000..6401cc8 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java @@ -0,0 +1,35 @@ +package com.chen.algorithm.znn.tree.test235; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 15:02 + * @Description: 二叉搜索树的最近公共祖先 + */ +public class Solution { + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + while (root != null) { + if (p.val < root.val && q.val < root.val) { + root = root.left; + } else if (p.val > root.val && q.val > root.val) { + root = root.right; + } else { + return root; + } + } + return root; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(6), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + TreeNode res = lowestCommonAncestor(root, left, right); + System.out.println(res.val); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java new file mode 100644 index 0000000..a5ae70e --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java @@ -0,0 +1,86 @@ +package com.chen.algorithm.znn.tree.test236; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 15:29 + * @Description: 二叉树的最近公共祖先:1-递归;2-存储父节点 + */ +public class Solution { + + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestor1(root.left, p, q); + TreeNode right = lowestCommonAncestor1(root.right, p, q); + + if (left == null) { + return right; + } + if (right == null) { + return left; + } + + return root; + } + + /** + * 2-存储父节点 + * + * @param root + * @param p + * @param q + * @return + */ + Map parent = new HashMap<>(); + Set visited = new HashSet<>(); + + public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) { + return root; + } + + dfs(root); + while (p != null) { + visited.add(p.val); + p = parent.get(p.val); + } + while (q != null) { + if (visited.contains(q.val)) { + return q; + } + q = parent.get(q.val); + } + return null; + } + + private void dfs(TreeNode root) { + if (root.left != null) { + parent.put(root.left.val, root); + dfs(root.left); + } + if (root.right != null) { + parent.put(root.right.val, root); + dfs(root.right); + } + } + + @Test + public void test() { + TreeNode left = new TreeNode(7, new TreeNode(5), new TreeNode(9)); + TreeNode right = new TreeNode(2); + TreeNode root = new TreeNode(8, left, right); + + TreeNode res = lowestCommonAncestor2(root, left, right); + System.out.println(res.val); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java new file mode 100644 index 0000000..467231d --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java @@ -0,0 +1,35 @@ +package com.chen.algorithm.znn.tree.test538; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 11:39 + * @Description: 把二叉搜索树转换成累加树 + */ +public class Solution { + + int sum = 0; + + public TreeNode convertBST(TreeNode root) { + if (root != null) { + convertBST(root.right); + sum += root.val; + root.val = sum; + convertBST(root.left); + } + return root; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(6), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + TreeNode res = convertBST(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java new file mode 100644 index 0000000..53ae92e --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java @@ -0,0 +1,58 @@ +package com.chen.algorithm.znn.tree.test543; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 14:26 + * @Description: 二叉树的直径: = 左子树的深度+右子树的深度 + * = 经过的左子树的节点数+右子树的节点数-1 = 左子树的深度+右子树的深度 + 1 - 1 + */ +public class Solution { + + int ans; + + public int diameterOfBinaryTree(TreeNode root) { + depth(root); + return ans; + } + + private int depth(TreeNode root) { + if (root == null) { + return 0; + } + + int leftDepth = depth(root.left); + int rightDepth = depth(root.right); + ans = Math.max(ans, leftDepth + rightDepth); + return Math.max(leftDepth, rightDepth) + 1; + } + + + //public int diameterOfBinaryTree2(TreeNode root) { + // depth2(root); + // return ans - 1; + //} + // + //private int depth2(TreeNode node) { + // if (node == null) { + // return 0; // 访问到空节点了,返回0 + // } + // int L = depth(node.left); // 左儿子为根的子树的深度 + // int R = depth(node.right); // 右儿子为根的子树的深度 + // ans = Math.max(ans, L + R + 1); // 计算d_node即L+R+1 并更新ans + // return Math.max(L, R) + 1; // 返回该节点为根的子树的深度 + //} + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + int res = diameterOfBinaryTree(root); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java new file mode 100644 index 0000000..9a42724 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java @@ -0,0 +1,40 @@ +package com.chen.algorithm.znn.tree.test617; + +import com.alibaba.fastjson.JSON; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 14:50 + * @Description: 合并二叉树 + */ +public class Solution { + + public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { + if (t1 == null) { + return t2; + } + if (t2 == null) { + return t1; + } + TreeNode mergeTree = new TreeNode(t1.val + t2.val); + mergeTree.left = mergeTrees(t1.left, t2.left); + mergeTree.right = mergeTrees(t1.right, t2.right); + return mergeTree; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(5), new TreeNode(6)); + TreeNode root = new TreeNode(3, left, right); + + TreeNode right2 = new TreeNode(8); + TreeNode left2 = new TreeNode(7, new TreeNode(1), new TreeNode(2)); + TreeNode root2 = new TreeNode(3, left2, right2); + + TreeNode res = mergeTrees(root, root2); + System.out.println(JSON.toJSON(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java new file mode 100644 index 0000000..795f0f6 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java @@ -0,0 +1,10 @@ +package com.chen.algorithm.znn.tree.test96; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 17:49 + * @Description: 不同的二叉搜索树:动态规划 + */ +public class Solution { + +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java new file mode 100644 index 0000000..1fc6b20 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java @@ -0,0 +1,77 @@ +package com.chen.algorithm.znn.tree.test98; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.Stack; + +/** + * @Auther: zhunn + * @Date: 2020/10/29 16:35 + * @Description: 验证二叉搜索树:1-递归,2-中序遍历 + */ +public class Solution { + + /** + * 1-递归:左子树里所有节点的值均小于根结点的值,右子树里所有节点的值均大于根结点的值 + * + * @param root + * @return + */ + public boolean isValidBST1(TreeNode root) { + return isValid(root, null, null); + } + private boolean isValid(TreeNode root, Integer min, Integer max) { + + if (root == null) { + return true; + } + if (min != null && root.val <= min) { + return false; + } + if (max != null && root.val >= max) { + return false; + } + + return isValid(root.left, min, root.val) && isValid(root.right, root.val, max); + } + + /** + * 2-中序遍历:遍历后是升序,后一个值不得有小于前一个值 + * + * @param root + * @return + */ + public boolean isValidBST2(TreeNode root) { + if (root == null) { + return true; + } + + Stack stack = new Stack<>(); + double inorder = -Double.MAX_VALUE; + while (!stack.isEmpty() || root != null) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + if (root.val <= inorder) { + return false; + } + inorder = root.val; + root = root.right; + } + return true; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1); + TreeNode right = new TreeNode(7, new TreeNode(6), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + boolean res = isValidBST2(root); + System.out.println(res); + } + +} From 1412efa004e7b3595d7c328df90ea2ac462925be Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 30 Oct 2020 20:00:32 +0800 Subject: [PATCH 09/63] tree-2 --- .../algorithm/znn/tree/test111/Solution.java | 8 ++++- .../algorithm/znn/tree/test96/Solution.java | 29 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java index c8a9f60..5f119ba 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java @@ -15,7 +15,7 @@ public class Solution { /** * 1-深度优先搜索(DFS),即递归 - * + * 叶子结点都为空,需要走到叶子结点,当一个结点为空一个结点不为空时,说明叶子结点在不为空的那个节点,返回不为空 * @param root * @return */ @@ -35,9 +35,15 @@ public int minDepth1(TreeNode root) { return 0; } + //if(root.left == null && root.right == null){ + // return 1; + //} + int leftDepth = minDepth1(root.left); int rightDepth = minDepth1(root.right); + // 叶子结点,是左右子节点都为空的节点,当某一个子节点为空时,则返回另一个结点的高度。 + // 当一个结点为空一个结点不为空时,说明**叶子结点**在不为空的那个节点。 return root.left == null || root.right == null ? leftDepth + rightDepth + 1 : Math.min(leftDepth, rightDepth) + 1; } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java index 795f0f6..9e79d17 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java @@ -1,10 +1,37 @@ package com.chen.algorithm.znn.tree.test96; +import org.junit.Test; + /** * @Auther: zhunn * @Date: 2020/10/29 17:49 - * @Description: 不同的二叉搜索树:动态规划 + * @Description: 不同的二叉搜索树:1-动态规划 */ public class Solution { + /** + * 1-动态规划 求G(n) + * G(0) = 1,G(1) = 1 + * G(n) = G(i-1)*G(n-i) 求和(1<= i <=n) + * + * @param n + * @return + */ + public int numTrees(int n) { + int[] dp = new int[n + 1]; + dp[0] = 1; + dp[1] = 1; + + for (int i = 2; i <= n; i++) { + for (int j = 1; j <= i; j++) { + dp[i] += dp[j - 1] * dp[i - j]; + } + } + return dp[n]; + } + + @Test + public void test() { + System.out.println(numTrees(3)); + } } From 1f0cf3459bd0485ebda43b5f37f9355158dde35a Mon Sep 17 00:00:00 2001 From: chenweijie Date: Sat, 31 Oct 2020 18:43:04 +0800 Subject: [PATCH 10/63] array --- src/main/java/com/chen/Test.java | 11 ----------- .../com/chen/algorithm/study/test3/Solution4.java | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 src/main/java/com/chen/Test.java diff --git a/src/main/java/com/chen/Test.java b/src/main/java/com/chen/Test.java deleted file mode 100644 index ce3beb4..0000000 --- a/src/main/java/com/chen/Test.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.chen; - -/** - * @author : chen weijie - * @Date: 2020-09-18 20:03 - */ -public class Test { - - - -} diff --git a/src/main/java/com/chen/algorithm/study/test3/Solution4.java b/src/main/java/com/chen/algorithm/study/test3/Solution4.java index 3e6daf1..16ba0ae 100644 --- a/src/main/java/com/chen/algorithm/study/test3/Solution4.java +++ b/src/main/java/com/chen/algorithm/study/test3/Solution4.java @@ -27,9 +27,9 @@ public int lengthOfLongestSubstring(String s) { char c = s.charAt(i); if (map.containsKey(c)) { - left = Math.max(left, map.get(c)); + left = Math.max(left, map.get(c) + 1); } - max = Math.max(max, i - left); + max = Math.max(max, i - left + 1); map.put(c, i); } return max; From af51819343b162ff56513d34f2aa112b4b0c3626 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Sun, 1 Nov 2020 21:35:46 +0800 Subject: [PATCH 11/63] tree-3 --- .../znn/tree/offer/test34/Solution.java | 10 -- .../algorithm/znn/tree/test113/Solution.java | 100 ++++++++++++++++++ .../algorithm/znn/tree/test199/Solution.java | 68 +++++++++++- 3 files changed, 167 insertions(+), 11 deletions(-) delete mode 100644 src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java deleted file mode 100644 index e04cc0a..0000000 --- a/src/main/java/com/chen/algorithm/znn/tree/offer/test34/Solution.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.chen.algorithm.znn.tree.offer.test34; - -/** - * @Auther: zhunn - * @Date: 2020/10/28 10:11 - * @Description: 二叉树中和为某一值的路径 - */ -public class Solution { - -} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java new file mode 100644 index 0000000..85d5b2d --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java @@ -0,0 +1,100 @@ +package com.chen.algorithm.znn.tree.test113; + +import com.chen.algorithm.znn.tree.TreeNode; + +import java.util.*; + +/** + * @Auther: zhunn + * @Date: 2020/10/28 10:11 + * @Description: 二叉树中和为某一值的路径:1-深度优先搜索;2-广度优先搜索 + * 同剑指 Offer 34 + */ +public class Solution { + + List> res = new LinkedList<>(); + Deque path = new LinkedList<>(); + + /** + * 1-深度优先搜索 + * + * @param root + * @param sum + * @return + */ + public List> pathSum(TreeNode root, int sum) { + if (root == null) { + return res; + } + dfs(root, sum); + return res; + } + + private void dfs(TreeNode root, int sum) { + if (root == null) { + return; + } + path.add(root.val); + sum -= root.val; + if (root.left == null && root.right == null && sum == 0) { + res.add(new LinkedList<>(path)); + } + + dfs(root.left, sum); + dfs(root.right, sum); + path.pollLast(); + } + + List> res2 = new LinkedList<>(); + Map map = new HashMap<>(); + + /** + * 2-广度优先搜索 + * + * @param root + * @param sum + * @return + */ + public List> pathSum2(TreeNode root, int sum) { + if (root == null) { + return res2; + } + Queue queueNode = new LinkedList<>(); + queueNode.add(root); + Queue queueSum = new LinkedList<>(); + queueSum.add(0); + + while (!queueNode.isEmpty()) { + TreeNode node = queueNode.poll(); + int rec = queueSum.poll() + node.val; + + if (node.left == null && node.right == null) { + if (rec == sum) { + getPath(node); + } + } else { + if (node.left != null) { + map.put(node.left, node); + queueNode.add(node.left); + queueSum.add(rec); + } + if (node.right != null) { + map.put(node.right, node); + queueNode.add(node.right); + queueSum.add(rec); + } + } + } + return res2; + } + + private void getPath(TreeNode node) { + List temp = new LinkedList<>(); + while (node != null) { + temp.add(node.val); + node = map.get(node); + } + Collections.reverse(temp); + res2.add(temp); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java index d6e4080..5e7ef4d 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java @@ -1,9 +1,75 @@ package com.chen.algorithm.znn.tree.test199; +import com.chen.algorithm.znn.tree.TreeNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + /** * @Auther: zhunn * @Date: 2020/10/28 17:41 - * @Description: 二叉树的右视图 + * @Description: 二叉树的右视图:1-广度优先搜索;2-深度优先搜索 */ public class Solution { + + /** + * 1-广度优先搜索 + * + * @param root + * @return + */ + public List rightSideView(TreeNode root) { + if (root == null) { + return null; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + List res = new ArrayList<>(); + + while (!queue.isEmpty()) { + int size = queue.size(); + + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + // 将当前层的最后一个节点放入结果列表 + if (i == size - 1) { + res.add(node.val); + } + } + } + return res; + } + + List res = new ArrayList<>(); + /** + * 2-深度优先搜索 + * @param root + * @return + */ + public List rightSideView2(TreeNode root) { + dfs(root, 0); // 从根节点开始访问,根节点深度是0 + return res; + } + + private void dfs(TreeNode root, int depth) { + if (root == null) { + return; + } + // 先访问 当前节点,再递归地访问 右子树 和 左子树。 + if (depth == res.size()) { // 如果当前节点所在深度还没有出现在res里,说明在该深度下当前节点是第一个被访问的节点,因此将当前节点加入res中。 + res.add(root.val); + } + depth++; + dfs(root.right, depth); + dfs(root.left, depth); + } } From 52a4e4c493e284c8b8c0c5b12d53fd11c7f6cdd0 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Sun, 1 Nov 2020 23:28:48 +0800 Subject: [PATCH 12/63] dfs --- .../java/com/chen/algorithm/znn/bfs/Test.java | 2 +- .../java/com/chen/algorithm/znn/dfs/Test.java | 2 +- .../algorithm/znn/dfs/test22/Solution.java | 50 ++++++++++++++++++ .../algorithm/znn/dfs/test22/Solution2.java | 51 +++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java diff --git a/src/main/java/com/chen/algorithm/znn/bfs/Test.java b/src/main/java/com/chen/algorithm/znn/bfs/Test.java index ac049c0..d520e05 100644 --- a/src/main/java/com/chen/algorithm/znn/bfs/Test.java +++ b/src/main/java/com/chen/algorithm/znn/bfs/Test.java @@ -3,7 +3,7 @@ /** * @Auther: zhunn * @Date: 2020/10/24 17:23 - * @Description: 广度优先搜索相关 + * @Description: 广度优先搜索相关,详见二叉树 */ public class Test { } diff --git a/src/main/java/com/chen/algorithm/znn/dfs/Test.java b/src/main/java/com/chen/algorithm/znn/dfs/Test.java index 1463404..63d1100 100644 --- a/src/main/java/com/chen/algorithm/znn/dfs/Test.java +++ b/src/main/java/com/chen/algorithm/znn/dfs/Test.java @@ -3,7 +3,7 @@ /** * @Auther: zhunn * @Date: 2020/10/24 17:23 - * @Description: 深度优先搜索相关 + * @Description: 深度优先搜索相关,详见二叉树 */ public class Test { } diff --git a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java new file mode 100644 index 0000000..ef1306f --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java @@ -0,0 +1,50 @@ +package com.chen.algorithm.znn.dfs.test22; + +import com.alibaba.fastjson.JSON; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/ + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 括号生成:1-dfs + */ +public class Solution { + + List res = new ArrayList<>(); + + public List generateParenthesis(int n) { + dfs(n, n, ""); + return res; + } + + private void dfs(int left, int right, String curStr) { + // 左右括号都不剩余了,递归终止 + if (left == 0 && right == 0) { + res.add(curStr); + return; + } + + // 剪枝 + if(left > right){ + return; + } + // 如果左括号还剩余的话,可以拼接左括号 + if (left > 0) { + dfs(left - 1, right, curStr + "("); + } + // 如果右括号剩余多于左括号剩余的话,可以拼接右括号 + if (right > left) { + dfs(left, right - 1, curStr + ")"); + } + } + + @Test + public void test() { + List res = generateParenthesis(3); + System.out.println(JSON.toJSONString(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java new file mode 100644 index 0000000..4fb0435 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java @@ -0,0 +1,51 @@ +package com.chen.algorithm.znn.dfs.test22; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + * https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/ + * + * @Auther: zhunn + * @Date: 2020/10/24 17:23 + * @Description: 括号生成:2-bfs + */ +public class Solution2 { + class Node { + private String str; // 当前得到的字符串 + private int left; // 剩余的左括号数量 + private int right; // 剩余的右括号数量 + + public Node(String str, int left, int right) { + this.str = str; + this.left = left; + this.right = right; + } + } + + public List generateParenthesis(int n) { + if (n == 0) { + return null; + } + Queue queue = new LinkedList<>(); + queue.add(new Node("", n, n)); + List res = new ArrayList<>(); + + while (!queue.isEmpty()) { + Node node = queue.poll(); + + if (node.left == 0 && node.right == 0) { + res.add(node.str); + } + if (node.left > 0) { + queue.add(new Node(node.str + "(", node.left - 1, node.right)); + } + if (node.right > 0 && node.left < node.right) { + queue.add(new Node(node.str + ")", node.left, node.right - 1)); + } + } + return res; + } +} From d8cb770ff8282501eff6c501fb9ff11cd57083c6 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 2 Nov 2020 18:40:38 +0800 Subject: [PATCH 13/63] greedy-divide --- .../algorithm/znn/dfs/test22/Solution2.java | 5 + .../znn/divide/test169/Solution.java | 128 ++++++++++++++++++ .../algorithm/znn/divide/test50/Solution.java | 73 ++++++++++ .../com/chen/algorithm/znn/dynamic/Test.java | 1 + .../znn/greedy/test122/Solution.java | 87 ++++++++++++ .../algorithm/znn/greedy/test55/Solution.java | 62 +++++++++ .../znn/recursion/HanNuoTa/HanNuoTa.java | 48 +++++++ .../znn/recursion/test172/Solution.java | 64 +++++++++ .../znn/recursion/test70/Solution.java | 72 ++++++++++ 9 files changed, 540 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/recursion/HanNuoTa/HanNuoTa.java create mode 100644 src/main/java/com/chen/algorithm/znn/recursion/test172/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java index 4fb0435..a006815 100644 --- a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java +++ b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution2.java @@ -25,6 +25,11 @@ public Node(String str, int left, int right) { } } + /** + * 2-bfs + * @param n + * @return + */ public List generateParenthesis(int n) { if (n == 0) { return null; diff --git a/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java b/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java new file mode 100644 index 0000000..e9f6126 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java @@ -0,0 +1,128 @@ +package com.chen.algorithm.znn.divide.test169; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * @Auther: zhunn + * @Date: 2020/11/2 16:23 + * @Description: 多数元素:1-排序;2-哈希表(优选);3-分治 + */ +public class Solution { + + /** + * 1-排序 + * + * @param nums + * @return + */ + public int majorityElement1(int[] nums) { + Arrays.sort(nums); + return nums[nums.length / 2]; + } + + /** + * 2-哈希表(优化后) + * + * @param nums + * @return + */ + public int majorityElement2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + Map map = new HashMap<>(); + for (int num : nums) { + if (!map.containsKey(num)) { + map.put(num, 1); + continue; + } + + int count = map.get(num) + 1; + if (count > nums.length / 2) { + return num; + } + map.put(num, count); + } + return 0; + } + + /** + * 2-哈希表(直观) + * + * @param nums + * @return + */ + //public int majorityElement2(int[] nums) { + // if (nums == null || nums.length == 0) { + // return 0; + // } + // Map map = new HashMap<>(); + // for (int i = 0; i < nums.length; i++) { + // if (map.containsKey(nums[i])) { + // int count = map.get(nums[i]) + 1; + // if (count > nums.length / 2) { + // return nums[i]; + // } + // map.put(nums[i], count); + // } else { + // map.put(nums[i], 1); + // } + // } + // return 0; + //} + + /** + * 3-分治:官方解答 + * + * @param nums + * @return + */ + public int majorityElement3(int[] nums) { + return majorityElementRec(nums, 0, nums.length - 1); + } + + private int countInRange(int[] nums, int num, int lo, int hi) { + int count = 0; + for (int i = lo; i <= hi; i++) { + if (nums[i] == num) { + count++; + } + } + return count; + } + + private int majorityElementRec(int[] nums, int lo, int hi) { + // base case; the only element in an array of size 1 is the majority + // element. + if (lo == hi) { + return nums[lo]; + } + + // recurse on left and right halves of this slice. + int mid = (hi - lo) / 2 + lo; + int left = majorityElementRec(nums, lo, mid); + int right = majorityElementRec(nums, mid + 1, hi); + + // if the two halves agree on the majority element, return it. + if (left == right) { + return left; + } + + // otherwise, count each element and return the "winner". + int leftCount = countInRange(nums, left, lo, hi); + int rightCount = countInRange(nums, right, lo, hi); + + return leftCount > rightCount ? left : right; + } + + @Test + public void test() { + int[] nums = {2, 2, 1, 1, 1, 2, 2}; + System.out.println(majorityElement2(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java b/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java new file mode 100644 index 0000000..f969b84 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java @@ -0,0 +1,73 @@ +package com.chen.algorithm.znn.divide.test50; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/11/2 16:13 + * @Description: Pow(x, n):1-递归;2-迭代 + */ +public class Solution { + + /** + * 1-递归 + * + * @param x + * @param n + * @return + */ + public double myPow1(double x, int n) { + if (n == 0) { + return 1.0d; + } + int N = n; + if (N < 0) { + N = -N; + x = 1 / x; + } + return quick(x, N); + } + + private double quick(double x, int n) { + if (n == 0) { + return 1.0d; + } + double y = quick(x, n / 2); + return n % 2 == 1 ? y * y * x : y * y; + } + + /** + * 2-迭代 + * + * @param x + * @param n + * @return + */ + public double myPow2(double x, int n) { + if (n == 0) { + return 1d; + } + + int N = n; + if (N < 0) { + x = 1 / x; + N = -N; + } + + double res = 1d; + double x_contribute = x; + while (N > 0) { + if (N % 2 == 1) { + res = res * x_contribute; + } + x_contribute = x_contribute * x_contribute; + N = N / 2; + } + return res; + } + + @Test + public void test() { + System.out.println(myPow2(2.0, 5)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/Test.java b/src/main/java/com/chen/algorithm/znn/dynamic/Test.java index 000ada8..0c8a237 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/Test.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/Test.java @@ -1,6 +1,7 @@ package com.chen.algorithm.znn.dynamic; /** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/ * @Auther: zhunn * @Date: 2020/10/24 17:23 * @Description: DP动态规划相关 diff --git a/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java b/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java new file mode 100644 index 0000000..a4c4814 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java @@ -0,0 +1,87 @@ +package com.chen.algorithm.znn.greedy.test122; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/ + * + * @Auther: zhunn + * @Date: 2020/11/2 13:50 + * @Description: 买卖股票的最佳时机 II:1-贪心算法;2-动态规划 + * 1、题意: + * 你可以尽可能地完成更多的交易(多次买卖一支股票) + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * 示例 1: + * 输入: [7,1,5,3,6,4] + * 输出: 7 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + *   随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + * 示例 2: + * 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + *   注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + *   因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + * 2、简述题意:(手里只能持有一支股票,可以买卖多次,必须在再次购买前出售掉之前的股票) + */ +public class Solution { + + /** + * 1-贪心算法(最优解) + * + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) { + return 0; + } + + int max = 0; + for (int i = 1; i < prices.length; i++) { + int profit = prices[i] - prices[i - 1]; + if (profit > 0) { + max += profit; + } + } + return max; + } + + /** + * 2-动态规划 + * 1)定义状态:dp[i][j] + * 2)思考状态转移方程 + * 3)确定初始值 + * 4)确定输出值 + * + * @param prices + * @return + */ + public int maxProfit2(int[] prices) { + if (prices == null || prices.length < 2) { + return 0; + } + + // 0:持有现金 + // 1:持有股票 + // 状态转移:0 -> 1 -> 0 + int len = prices.length; + int[][] dp = new int[len][2]; + // 初始值 + dp[0][0] = 0; + dp[0][1] = -prices[0]; + for (int i = 1; i < len; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); + } + // 输出值 + return dp[len - 1][0]; + } + + @Test + public void test() { + int[] prices = {7, 1, 5, 3, 6, 4}; + int max = maxProfit(prices); + System.out.println(max); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java new file mode 100644 index 0000000..6783ca7 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java @@ -0,0 +1,62 @@ +package com.chen.algorithm.znn.greedy.test55; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/11/2 14:51 + * @Description: 跳跃游戏:1-贪心算法;2-动态规划 + */ +public class Solution { + + /** + * 1-贪心算法 + * @param nums + * @return + */ + public boolean canJump(int[] nums) { + if (nums == null || nums.length == 0) { + return false; + } + + int lastPosition = nums.length - 1; + for (int i = nums.length - 1; i >= 0; i--) { + if (nums[i] + i >= lastPosition) { + lastPosition = i; + } + } + return lastPosition == 0; + } + + /** + * 2-动态规划 + * @param nums + * @return + */ + public boolean canJump2(int[] nums) { + + if (nums == null || nums.length == 0) { + return false; + } + boolean[] dp = new boolean[nums.length]; + dp[0] = true; + for (int i = 1; i < nums.length; i++) { + for (int j = 0; j < i; j++) { + // 如果之前的j节点可达,并且从此节点可以到跳到i + if (dp[j] && nums[j] + j >= i) { + dp[i] = true; + break; + } + } + } + return dp[nums.length - 1]; + } + + @Test + public void test() { + int[] nums = {3, 2, 1, 1, 4}; + int[] nums2 = {3, 2, 1, 0, 4}; + boolean res = canJump(nums2); + System.out.println(res); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/recursion/HanNuoTa/HanNuoTa.java b/src/main/java/com/chen/algorithm/znn/recursion/HanNuoTa/HanNuoTa.java new file mode 100644 index 0000000..73bc576 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/recursion/HanNuoTa/HanNuoTa.java @@ -0,0 +1,48 @@ +package com.chen.algorithm.znn.recursion.HanNuoTa; + +import org.junit.Test; + +import java.util.LinkedList; +import java.util.List; + +/** + * @Auther: zhunn + * @Date: 2020/11/2 10:12 + * @Description: 汉诺塔问题 + */ +public class HanNuoTa { + /** + * 将 A 上的所有盘子,借助 B,移动到C 上 + * + * @param A 原柱子 + * @param B 辅助柱子 + * @param C 目标柱子 + */ + public void hanota(List A, List B, List C) { + movePlate(A.size(), A, B, C); + } + + private void movePlate(int num, List original, List auxiliary, List target) { + if (num == 1) { // 只剩一个盘子时,直接移动即可 + target.add(original.remove(original.size() - 1)); + return; + } + + movePlate(num - 1, original, target, auxiliary); // 将 size-1 个盘子,从 original 移动到 auxiliary + target.add(original.remove(original.size() - 1)); // 将 第size个盘子,从 original 移动到 target + movePlate(num - 1, auxiliary, original, target); // 将 size-1 个盘子,从 auxiliary 移动到 target + } + + @Test + public void test() { + List listA = new LinkedList<>(); + listA.add(4); + listA.add(3); + listA.add(2); + listA.add(1); + List listB = new LinkedList<>(); + List listC = new LinkedList<>(); + hanota(listA, listB, listC); + System.out.println(listC); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/recursion/test172/Solution.java b/src/main/java/com/chen/algorithm/znn/recursion/test172/Solution.java new file mode 100644 index 0000000..411005e --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/recursion/test172/Solution.java @@ -0,0 +1,64 @@ +package com.chen.algorithm.znn.recursion.test172; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/11/2 10:43 + * @Description: 阶乘后的零的个数:1-递归;2-迭代 + */ +public class Solution { + + /** + * 1-递归 求阶乘 + * + * @param n + * @return + */ + private int getFactorial(int n) { + if (n < 0) { + return -1; + } + if (n == 0) { + return 1; + } + return n * getFactorial(n - 1); + } + + /** + * 2-迭代 求阶乘 + * + * @param n + * @return + */ + private int getFactorial2(int n) { + if (n < 0) { + return -1; + } + if (n == 0) { + return 1; + } + + int sum = 1; + for (int i = 1; i <= n; i++) { + sum *= i; + } + return sum; + } + + public int getZeroCount(int n) { + int sum = getFactorial2(n); + int count = 0; + while (sum % 10 == 0) { + count++; + sum /= 10; + } + return count; + } + + @Test + public void test() { + int res = getZeroCount(10); + System.out.println(res); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java b/src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java new file mode 100644 index 0000000..e060d37 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java @@ -0,0 +1,72 @@ +package com.chen.algorithm.znn.recursion.test70; + +import org.junit.Test; + +/** + * 不难发现,这个问题可以被分解为一些包含最优子结构的子问题,即它的最优解可以从其子问题的最优解来有效地构建,我们可以使用动态规划来解决这一问题。 + * 第 i 阶可以由以下两种方法得到: + * 在第(i−1) 阶后向上爬 1 阶。 + * 在第(i−2) 阶后向上爬 2 阶。 + * 所以到达第 i 阶的方法总数就是到第(i−1) 阶和第 (i−2) 阶的方法数之和。 + * 令 dp[i] 表示能到达第 i 阶的方法总数: + * dp[i]=dp[i-1]+dp[i-2] + * 在上述方法中,我们使用 dp 数组,其中 dp[i]=dp[i-1]+dp[i-2]。可以很容易通过分析得出 dp[i] 其实就是第 i 个斐波那契数。 + * Fib(n)=Fib(n-1)+Fib(n-2) + * 现在我们必须找出以 1 和 2 作为第一项和第二项的斐波那契数列中的第 n 个数,也就是说 Fib(1)=1Fib(1)=1 且 Fib(2)=2Fib(2)=2 + * + * @Auther: zhunn + * @Date: 2020/11/2 11:03 + * @Description: 爬楼梯:1-迭代/递归(斐波那契数列);2-动态规划 + */ +public class Solution { + + /** + * 1-迭代/递归(斐波那契数列) + * + * @param n + * @return + */ + public int climbStairs(int n) { + if (n <= 0) { + return 0; + } + if (n == 1) { + return 1; + } + if (n == 2) { + return 2; + } + int first = 1, second = 2, third = 0; + for (int i = 3; i <= n; i++) { + third = first + second; + first = second; + second = third; + } + return third; + } + + /** + * 2-动态规划 + * + * @param n + * @return + */ + public int climbStairs2(int n) { + if (n <= 0) { + return 0; + } + int[] dp = new int[n + 1]; + dp[1] = 1; + dp[2] = 2; + for (int i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; + } + + @Test + public void test() { + int res = climbStairs2(10); + System.out.println(res); + } +} From 134499417929315df2a196547af4afad4e0c96c3 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Mon, 2 Nov 2020 22:28:31 +0800 Subject: [PATCH 14/63] backtrack --- .../chen/algorithm/znn/backtrack/test51/Solution.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java new file mode 100644 index 0000000..3ad833f --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.backtrack.test51; + +/** + * @Auther: zhunn + * @Date: 2020/11/02 21:23 + * @Description: N皇后问题 + */ +public class Solution { +} From c4d2f139a077706c2b3fd3770f51d6fc99469ae4 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 3 Nov 2020 22:00:19 +0800 Subject: [PATCH 15/63] dp-1 --- .../algorithm/study/test39/Solution2.java | 13 +- .../chen/algorithm/znn/backtrack/Test.java | 15 +++ .../algorithm/znn/backtrack/ZeroOneBag.java | 104 +++++++++++++++ .../znn/backtrack/test36/Solution.java | 121 ++++++++++++++++++ .../znn/backtrack/test39/Solution.java | 73 +++++++++++ .../znn/backtrack/test40/Solution.java | 61 +++++++++ .../znn/backtrack/test46/Solution.java | 62 +++++++++ .../znn/backtrack/test47/Solution.java | 60 +++++++++ .../znn/backtrack/test51/Solution.java | 76 +++++++++++ .../znn/backtrack/test78/Solution.java | 42 ++++++ .../znn/backtrack/test79/Solution.java | 66 ++++++++++ .../znn/backtrack/test90/Solution.java | 40 ++++++ .../znn/dynamic/test121/Solution.java | 32 +++++ .../znn/dynamic/test123/Solution.java | 9 ++ .../test70/Solution.java | 2 +- src/main/java/com/chen/algorithm/znn/note | 13 +- 16 files changed, 774 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java rename src/main/java/com/chen/algorithm/znn/{recursion => dynamic}/test70/Solution.java (97%) diff --git a/src/main/java/com/chen/algorithm/study/test39/Solution2.java b/src/main/java/com/chen/algorithm/study/test39/Solution2.java index ef9cac8..b96af42 100644 --- a/src/main/java/com/chen/algorithm/study/test39/Solution2.java +++ b/src/main/java/com/chen/algorithm/study/test39/Solution2.java @@ -1,9 +1,11 @@ package com.chen.algorithm.study.test39; +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Stack; /** * https://leetcode-cn.com/problems/combination-sum/solution/di-gui-hui-su-tu-wen-fen-xi-ji-bai-liao-9987de-yon/ @@ -24,7 +26,7 @@ public List> combinationSum(int[] candidates, int target) { public void backtrack(List> res, int[] candidates, int target, List curList, int start) { if (target == 0) { - res.add(new ArrayList<>(new Stack<>())); + res.add(new ArrayList<>(curList)); return; } @@ -39,4 +41,11 @@ public void backtrack(List> res, int[] candidates, int target, Lis } } + @Test + public void test() { + int[] candidates = {2, 3, 6, 7}; + int target = 7; + + System.out.println(combinationSum(candidates, target)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/Test.java b/src/main/java/com/chen/algorithm/znn/backtrack/Test.java index a6e91ec..a007d19 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/Test.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/Test.java @@ -6,4 +6,19 @@ * @Description: 回溯相关 */ public class Test { + + /** + * 回溯算法的框架: + * + * result = [] + * def backtrack(路径, 选择列表): + * if 满足结束条件: + * result.add(路径) + * return + * + * for 选择 in 选择列表: + * 做选择 + * backtrack(路径, 选择列表) + * 撤销选择 + */ } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java b/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java new file mode 100644 index 0000000..dffdc31 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java @@ -0,0 +1,104 @@ +package com.chen.algorithm.znn.backtrack; + +/** + * 我们有一个背包,背包总的承载重量是Wkg。现在我们有n个物品,每个物品的重量不等,并且不可分割。我们现在期望选择几件物品, + * 装载到背包中。在不超过背包所能装载重量的前提下,如何让背包中物品的总重量最大? + * + * @Auther: zhunn + * @Date: 2020/11/3 14:53 + * @Description: 0-1背包问题:1-回溯;2-动态规划 + */ +public class ZeroOneBag { + + private int maxW = Integer.MAX_VALUE; + private int[] items = {2, 2, 4, 6, 3}; // 物品重量 + private int n = 5; // 物品个数 + private int w = 9; // 背包承受的最大重量 + + /** + * 1-回溯 + * // 假设背包可承受重量100,物品个数10,物品重量存储在数组a中,那可以这样调用函数: + * // f(0, 0, a, 10, 100) + *

+ * 我们可以把物品依次排列,整个问题就分解为了 n 个阶段,每个阶段对应一个物品怎么选择。 + * 先对第一个物品进行处理,选择装进去或者不装进去,然后再递归地处理剩下的物品。 + * + * @param i 表示考察到哪个物品了 + * @param cw 表示当前已经装进去的物品的重量和 + * items 表示每个物品的重量 + * n 表示物品个数 + * w 背包重量 + */ + public void bag1(int i, int cw) { + // cw==w表示装满了;i==n表示已经考察完所有的物品 + if (cw == w || i == n) { + if (cw > maxW) { + maxW = cw; + } + return; + } + bag1(i + 1, cw); + // 已经超过可以背包承受的重量的时候,就不要再装了 + if (cw + items[i] <= w) { + bag1(i + 1, cw + items[i]); + } + } + + private boolean[][] memo = new boolean[5][10]; + + public void bag2(int i, int cw) { + if (cw == w || i == n) { // cw==w表示装满了,i==n表示物品都考察完了 + if (cw > maxW) { + maxW = cw; + } + return; + } + if (memo[i][cw]) { + return; // 重复状态 + } + memo[i][cw] = true; // 记录(i, cw)这个状态 + bag2(i + 1, cw); // 选择不装第i个物品 + if (cw + items[i] <= w) { + bag2(i + 1, cw + items[i]); // 选择装第i个物品 + } + } + + /** + * 2-动态规划 + * 我们把整个求解过程分为n个阶段,每个阶段会决策一个物品是否放到背包中。每个物品决策(放入或者不放入背包)完之后,背包中的物品的重量会有多种情况,也就是说,会达到多种不同的状态,对应到递归树中,就是有很多不同的节点。 + * 我们把每一层重复的状态(节点)合并,只记录不同的状态,然后基于上一层的状态集合,来推导下一层的状态集合。我们可以通过合并每一层重复的状态,这样就保证每一层不同状态的个数都不会超过w个(w表示背包的承载重量),也就是例子中的9。于是,我们就成功避免了每层状态个数的指数级增长。 + * 我们用一个二维数组states[n][w+1],来记录每层可以达到的不同状态。 + * 第0个(下标从0开始编号)物品的重量是2,要么装入背包,要么不装入背包,决策完之后,会对应背包的两种状态,背包中物品的总重量是0或者2。我们用states[0][0]=true和states[0][2]=true来表示这两种状态。 + * 第1个物品的重量也是2,基于之前的背包状态,在这个物品决策完之后,不同的状态有3个,背包中物品总重量分别是0(0+0),2(0+2 or 2+0),4(2+2)。我们用states[1][0]=true,states[1][2]=true,states[1][4]=true来表示这三种状态。 + * 以此类推,直到考察完所有的物品后,整个states状态数组就都计算好了。我把整个计算的过程画了出来,你可以看看。图中0表示false,1表示true。我们只需要在最后一层,找一个值为true的最接近w(这里是9)的值,就是背包中物品总重量的最大值。 + * + * @param weight weight:物品重量(2、2、4、6、3) + * @param n n:物品个数(0-5) + * @param w w:背包可承载重量(0-9) + * @return + */ + public int knapsack(int[] weight, int n, int w) { + boolean[][] states = new boolean[n][w + 1]; //默认值false + states[0][0] = true; //初始化,第一行的数据要特殊处理,可以利用哨兵优化 + states[0][weight[0]] = true; + + for (int i = 1; i < n; i++) { // 动态规划状态转移 + for (int j = 0; j <= w; j++) { // 不把第i个物品放入背包 + if (states[i - 1][j] == true) { + states[i][j] = true; + } + } + for (int j = 0; j + weight[i] <= w; i++) { //把第i个物品放入背包 + if (states[i - 1][j] == true) { + states[i - 1][j + weight[i]] = true; + } + } + } + for (int i = w; i >= 0; i--) { // 输出结果 + if (states[n - 1][i]) { + return i; + } + } + return 0; + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java new file mode 100644 index 0000000..bc4b3ba --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java @@ -0,0 +1,121 @@ +package com.chen.algorithm.znn.backtrack.test36; + +import org.junit.Test; + +import java.util.HashSet; + +/** + * https://leetcode-cn.com/problems/valid-sudoku/solution/javawei-yun-suan-1ms-100-li-jie-fang-ge-suo-yin-by/ + * + * @Auther: zhunn + * @Date: 2020/11/3 13:54 + * @Description: 有效的数独:1-哈希数组;2-位运算数组 + */ +public class Solution { + + /** + * 1-哈希数组 + * + * @param board + * @return + */ + public boolean isValidSudoku(char[][] board) { + HashSet[] rows = new HashSet[9]; + HashSet[] cols = new HashSet[9]; + HashSet[] boxes = new HashSet[9]; + for (int i = 0; i < 9; i++) { + rows[i] = new HashSet<>(); + cols[i] = new HashSet<>(); + boxes[i] = new HashSet<>(); + } + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] == '.') + continue; + int tmp = board[i][j] - '0'; + if (rows[i].contains(tmp) //本行中已有数字 + || cols[j].contains(tmp) //本列中已有数字 + || boxes[(i / 3) * 3 + j / 3].contains(tmp)) //本方格中已有数字 + return false; + rows[i].add(tmp); //添加到本行 + cols[j].add(tmp); //添加到本列 + boxes[(i / 3) * 3 + j / 3].add(tmp); //添加到本方格 + } + } + return true; + } + + /** + * 2-位运算数组 + */ + public boolean isValidSudoku2(char[][] board) { + int[] rows = new int[9]; //行的位运算数组 + int[] cols = new int[9]; //列的位运算数组 + int[] boxes = new int[9]; //方格的位运算数组 + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] == '.') + continue; + int tmp = board[i][j] - '0'; + int boxIndex = i / 3 * 3 + j / 3; + if ((rows[i] >> tmp & 1) == 1 //rows[i] >> tmp & 1取出第i行的tmp数字,看是否已填,如果等于1,代表已填 + || (cols[j] >> tmp & 1) == 1 //cols[j] >> tmp & 1取出第j列的tmp数字,看是否已填,如果等于1,代表已填 + || (boxes[boxIndex] >> tmp & 1) == 1) //boxes[boxIndex] >> tmp & 1取出第boxIndex个方格的tmp数字,看是否已填,如果等于1,代表已填 + return false; + rows[i] = rows[i] | (1 << tmp); //将tmp数字加入到第i行的位运算数组 + cols[j] = cols[j] | (1 << tmp); //将tmp数字加入到第j列的位运算数组 + boxes[boxIndex] = boxes[boxIndex] | (1 << tmp); //将tmp数字加入到第boxIndex个方格的位运算数组 + } + } + return true; + } + + public boolean isValidSudoku1(char[][] board) { + int[][] row = new int[9][10]; // 哈希表存储每一行的每个数是否出现过,默认初始情况下,每一行每一个数都没有出现过 + // 整个board有9行,第二维的维数10是为了让下标有9,和数独中的数字9对应。 + int[][] col = new int[9][10]; // 存储每一列的每个数是否出现过,默认初始情况下,每一列的每一个数都没有出现过 + int[][] box = new int[9][10]; // 存储每一个box的每个数是否出现过,默认初始情况下,在每个box中,每个数都没有出现过。整个board有9个box。 + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] == '.') { + continue; + } + + // 遍历到第i行第j列的那个数,我们要判断这个数在其所在的行有没有出现过, + // 同时判断这个数在其所在的列有没有出现过 + // 同时判断这个数在其所在的box中有没有出现过 + int curNum = board[i][j] - '0'; + if (row[i][curNum] == 1) { + return false; + } + if (col[j][curNum] == 1) { + return false; + } + if (box[j / 3 + (i / 3) * 3][curNum] == 1) { + return false; + } + row[i][curNum] = 1; // 之前都没出现过,现在出现了,就给它置为1,下次再遇见就能够直接返回false了。 + col[j][curNum] = 1; + box[j / 3 + (i / 3) * 3][curNum] = 1; + } + } + return true; + } + + @Test + public void test() { + char[][] board = { + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + boolean res = isValidSudoku(board); + System.out.println(res); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java new file mode 100644 index 0000000..db4dbdc --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java @@ -0,0 +1,73 @@ +package com.chen.algorithm.znn.backtrack.test39; + +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/ + * + * @Auther: zhunn + * @Date: 2020/11/3 15:27 + * @Description: 组合总和 + */ +public class Solution { + + public List> combinationSum(int[] candidates, int target) { + if (candidates == null || candidates.length == 0) { + return null; + } + List> res = new ArrayList<>(); + // 排序是剪枝的前提 + Arrays.sort(candidates); + backtrack(0, target, candidates, new ArrayList<>(), res); + return res; + } + + private void backtrack(int start, int target, int[] candidates, List curList, List> res) { + if (target == 0) { + res.add(new ArrayList<>(curList)); + return; + } + for (int i = start; i < candidates.length; i++) { + if (candidates[i] > target) { + continue; + } + curList.add(candidates[i]); + //System.out.println("递归之前 => " + curList + ",剩余 = " + (target - candidates[i])); + backtrack(i, target - candidates[i], candidates, curList, res); + curList.remove(curList.size() - 1); + //System.out.println("递归之后 => " + curList); + } + } + //private void backtrack(int start, int target, int[] candidates, List curList, List> res) { + // // 由于进入更深层的时候,小于0的部分被剪枝,因此递归终止条件值只判断等于0的情况 + // //if (target < 0) { + // // return; + // //} + // if (target == 0) { + // res.add(new ArrayList<>(curList)); + // return; + // } + // // 重点理解这里从start开始搜索的语意 + // for (int i = start; i < candidates.length; i++) { + // if (candidates[i] > target) { // 重点理解这里剪枝,前提是候选数组已经有序 + // continue; + // } + // curList.add(candidates[i]); + // backtrack(i, target - candidates[i], candidates, curList, res);// 注意每个元素可以重复使用,下一轮搜索的起点依然是 i + // curList.remove(curList.size() - 1); //状态重置 + // } + //} + + @Test + public void test() { + int[] candidates = {2, 3, 6, 7}; + int target = 7; + + System.out.println(JSONObject.toJSONString(combinationSum(candidates, target))); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java new file mode 100644 index 0000000..80782f4 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java @@ -0,0 +1,61 @@ +package com.chen.algorithm.znn.backtrack.test40; + +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/combination-sum-ii/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-3/ + * @Auther: zhunn + * @Date: 2020/11/3 15:28 + * @Description: 组合总和 II + */ +public class Solution { + + public List> combinationSum2(int[] nums, int target) { + if (nums == null || nums.length == 0) { + return null; + } + // 排序是剪枝的前提 + Arrays.sort(nums); + List> res = new ArrayList<>(); + backtrack(0, target, nums, new ArrayList<>(), res); + return res; + } + + private void backtrack(int start, int target, int[] nums, List curList, List> res) { + // 由于进入更深层的时候,小于0的部分被剪枝,因此递归终止条件值只判断等于0的情况 + //if (target < 0) { + // return; + //} + if (target == 0) { + res.add(new ArrayList<>(curList)); + return; + } + for (int i = start; i < nums.length; i++) { + if (nums[i] > target) { + break; + } + if (i > start && nums[i - 1] == nums[i]) { + continue; + } + curList.add(nums[i]); + backtrack(i + 1, target - nums[i], nums, curList, res); + curList.remove(curList.size() - 1); + } + } + + @Test + public void testCase() { + int[] nums = {10, 1, 2, 7, 6, 1, 5}; + int target = 8; + + List> res = combinationSum2(nums, target); + System.out.println(JSONObject.toJSONString(res)); + + + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java new file mode 100644 index 0000000..47dafba --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java @@ -0,0 +1,62 @@ +package com.chen.algorithm.znn.backtrack.test46; + +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/ + * 回溯算法的框架: + * result = [] + * def backtrack(路径, 选择列表): + * if 满足结束条件: + * result.add(路径) + * return + * for 选择 in 选择列表: + * 做选择 + * backtrack(路径, 选择列表) + * 撤销选择 + * + * @Auther: zhunn + * @Date: 2020/11/3 17:52 + * @Description: 全排列 + */ +public class Solution { + + public List> permute(int[] nums) { + if (nums == null || nums.length == 0) { + return null; + } + List> res = new ArrayList<>(); + boolean[] used = new boolean[nums.length]; + backtrack(0, nums.length, nums, used, new ArrayList<>(), res); + return res; + } + + private void backtrack(int depth, int len, int[] nums, boolean[] used, List curList, List> res) { + if (depth == len) { + res.add(new ArrayList<>(curList)); + return; + } + for (int i = 0; i < len; i++) { + if (used[i]) { + continue; + } + + curList.add(nums[i]); + used[i] = true; + backtrack(depth + 1, len, nums, used, curList, res); + // 注意:这里是状态重置,是从深层结点回到浅层结点的过程,代码在形式上和递归之前是对称的 + curList.remove(curList.size() - 1); + used[i] = false; + } + } + + @Test + public void testCase() { + int[] nums = {1, 2, 3}; + System.out.println(JSONObject.toJSONString(permute(nums))); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java new file mode 100644 index 0000000..c3a7b79 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java @@ -0,0 +1,60 @@ +package com.chen.algorithm.znn.backtrack.test47; + +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +import java.util.*; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 19:39 + * @Description: 全排列 II + */ +public class Solution { + + public List> permuteUnique(int[] nums) { + if (nums == null || nums.length == 0) { + return null; + } + + List> res = new ArrayList<>(); + // 排序(升序或者降序都可以),排序是剪枝的前提 + Arrays.sort(nums); + + boolean[] used = new boolean[nums.length]; + dfs(nums, nums.length, 0, used, new ArrayList<>(), res); + return res; + } + + private void dfs(int[] nums, int len, int depth, boolean[] used, List curList, List> res) { + if (depth == len) { + res.add(new ArrayList<>(curList)); + return; + } + + for (int i = 0; i < len; ++i) { + if (used[i]) { + continue; + } + + // 剪枝条件:i > 0 是为了保证 nums[i - 1] 有意义 + // 写 !used[i - 1] 是因为 nums[i - 1] 在深度优先遍历的过程中刚刚被撤销选择 + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) { + continue; + } + + curList.add(nums[i]); + used[i] = true; + dfs(nums, len, depth + 1, used, curList, res); + // 回溯部分的代码,和 dfs 之前的代码是对称的 + used[i] = false; + curList.remove(curList.size() - 1); + } + } + + @Test + public void testCase() { + int[] nums = {1, 1, 2}; + System.out.println(JSONObject.toJSONString(permuteUnique(nums))); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java index 3ad833f..79ba277 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java @@ -1,9 +1,85 @@ package com.chen.algorithm.znn.backtrack.test51; +import com.alibaba.fastjson.JSONObject; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + /** + * https://leetcode-cn.com/problems/n-queens/solution/gen-ju-di-46-ti-quan-pai-lie-de-hui-su-suan-fa-si-/ + * * @Auther: zhunn * @Date: 2020/11/02 21:23 * @Description: N皇后问题 */ public class Solution { + + private boolean[] col; // 列 + private boolean[] master; // 主对角线 + private boolean[] slave; //副对角线 + private int n; // 行数 + private List> res; //结果集 + + public List> solveNQueues(int n) { + this.n = n; + res = new ArrayList<>(); + if (n == 0) { + return res; + } + col = new boolean[n]; + master = new boolean[2 * n - 1]; + slave = new boolean[2 * n - 1]; + Stack stack = new Stack<>(); + helper(0, stack); + return res; + } + + private void helper(int row, Stack stack) { + if (row == n) { + List board = convert2board(stack, n); + res.add(board); + return; + } + + // 针对每一列,尝试是否可以放置 + for (int i = 0; i < n; i++) { + if (col[i] || master[row + i] || slave[row - i + n - 1]) { + continue; + } + stack.push(i); + col[i] = true; + master[row + i] = true; + slave[row - i + n - 1] = true; + helper(row + 1, stack); + slave[row - i + n - 1] = false; + master[row + i] = false; + col[i] = false; + stack.pop(); + } + } + + private List convert2board(Stack stack, int n) { + List board = new ArrayList<>(); + for (Integer num : stack) { + char[] row = new char[n]; + for (int i = 0; i < n; i++) { + row[i] = '*'; + } + row[num] = 'Q'; + board.add(row.toString()); + } + return board; + } + + @Test + public void testCase() { + List> res = solveNQueues(4); + + for (List re : res) { + System.out.println("====" + JSONObject.toJSONString(re)); + } + + } } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java new file mode 100644 index 0000000..d848be9 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java @@ -0,0 +1,42 @@ +package com.chen.algorithm.znn.backtrack.test78; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + * https://leetcode-cn.com/problems/subsets/solution/hui-su-suan-fa-by-powcai-5/ + * + * @Auther: zhunn + * @Date: 2020/11/3 19:23 + * @Description: 子集 + */ +public class Solution { + + public List> subsets(int[] nums) { + if (nums == null || nums.length == 0) { + return null; + } + List> res = new ArrayList<>(); + backtrack(0, nums, new ArrayList<>(), res); + return res; + } + + private void backtrack(int start, int[] nums, List curList, List> res) { + res.add(new ArrayList<>(curList)); + for (int i = start; i < nums.length; i++) { + curList.add(nums[i]); + backtrack(i + 1, nums, curList, res); + curList.remove(curList.size() - 1); + } + } + + @Test + public void testCase() { + int[] n = {1, 2, 3}; + System.out.println(subsets(n)); + + + } +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java new file mode 100644 index 0000000..cc61cb8 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java @@ -0,0 +1,66 @@ +package com.chen.algorithm.znn.backtrack.test79; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/word-search/solution/zai-er-wei-ping-mian-shang-shi-yong-hui-su-fa-pyth/ + * @Auther: zhunn + * @Date: 2020/11/3 18:31 + * @Description: 单词搜索 + */ +public class Solution { + + private boolean[][] visited; + + public boolean exist(char[][] board, String word) { + if (board == null || board.length == 0) { + return false; + } + int m = board.length; + int n = board[0].length; + visited = new boolean[m][n]; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (dfs(0, word, board, i, j)) { + return true; + } + } + } + return false; + } + + private boolean dfs(int index, String word, char[][] board, int x, int y) { + if (x < 0 || y < 0 || x >= board.length || y >= board[0].length //越界 + || word.charAt(index) != board[x][y] // 字符不相等 + || visited[x][y]) { // 被访问过 + return false; + } + if (index == word.length() - 1) { // 已验证到单词结尾 + return true; + } + + visited[x][y] = true; + if (dfs(index + 1, word, board, x - 1, y) || dfs(index + 1, word, board, x + 1, y) + || dfs(index + 1, word, board, x, y - 1) || dfs(index + 1, word, board, x, y + 1)) { + return true; + } + visited[x][y] = false; + return false; + } + + @Test + public void test() { + char[][] board = + { + {'A', 'B', 'C', 'E'}, + {'S', 'F', 'C', 'S'}, + {'A', 'D', 'E', 'E'} + }; + + String word = "ABCCED"; + + System.out.println(exist(board, word)); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java new file mode 100644 index 0000000..c4a9bc3 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java @@ -0,0 +1,40 @@ +package com.chen.algorithm.znn.backtrack.test90; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 19:41 + * @Description: 子集 II + */ +public class Solution { + public List> subsetsWithDup(int[] nums) { + List> res = new ArrayList<>(); + Arrays.sort(nums); //排序 + backtrack(nums, 0, new ArrayList<>(), res); + return res; + } + + private void backtrack(int[] nums, int start, ArrayList curList, List> ans) { + ans.add(new ArrayList<>(curList)); + for (int i = start; i < nums.length; i++) { + //和上个数字相等就跳过 + if (i > start && nums[i] == nums[i - 1]) { + continue; + } + curList.add(nums[i]); + backtrack(nums, i + 1, curList, ans); + curList.remove(curList.size() - 1); + } + } + + @Test + public void testCase() { + int[] nums = {1, 2, 2}; + System.out.println(subsetsWithDup(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java new file mode 100644 index 0000000..0172cef --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java @@ -0,0 +1,32 @@ +package com.chen.algorithm.znn.dynamic.test121; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/kan-yi-bian-jiu-wang-bu-diao-de-jie-ti-si-lu-bu-di/ + * @Auther: zhunn + * @Date: 2020/11/3 19:59 + * @Description: 买卖股票的最佳时机:双指针法 + * 121、122(贪心)、123、188、309、714 + */ +public class Solution { + + public int maxProfit(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int min = nums[0]; + int max = 0; + for (int i = 0; i < nums.length; i++) { + min = Math.min(nums[i], min); + max = Math.max(max, nums[i] - min); + } + return max; + } + + @Test + public void test() { + int[] nums = {7, 1, 5, 3, 6, 4}; + System.out.println(maxProfit(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java new file mode 100644 index 0000000..79edab8 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic.test123; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 21:06 + * @Description: 买卖股票的最佳时机 III:1-动态规划 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java similarity index 97% rename from src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java rename to src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java index e060d37..4a9de71 100644 --- a/src/main/java/com/chen/algorithm/znn/recursion/test70/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java @@ -1,4 +1,4 @@ -package com.chen.algorithm.znn.recursion.test70; +package com.chen.algorithm.znn.dynamic.test70; import org.junit.Test; diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 42dafff..aee6262 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -1,26 +1,15 @@ 文档上没有,代码有的题: -test4 -test10 test11 -test13 -test17 -test31 -test33 -test75 -test90 -test139 -test234 test287 test343 test347 +test112 test437 test496 test674 offer.test57 文档上有,代码上没有的题: -test36 -test199 test474 test494 test213 From f0aaaced08e6a0109648464f0cb4cf9ddb1feff7 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 3 Nov 2020 22:18:47 +0800 Subject: [PATCH 16/63] dp-1 --- .../znn/backtrack/test90/Solution.java | 1 + .../znn/dynamic/test120/Solution.java | 9 +++++++ .../znn/dynamic/test152/Solution.java | 9 +++++++ .../znn/dynamic/test188/Solution.java | 9 +++++++ .../znn/dynamic/test309/Solution.java | 9 +++++++ .../znn/dynamic/test714/Solution.java | 9 +++++++ src/main/java/com/chen/algorithm/znn/note | 26 +++++++++---------- 7 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java index c4a9bc3..925410b 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java @@ -7,6 +7,7 @@ import java.util.List; /** + * https://leetcode-cn.com/problems/subsets/solution/hui-su-suan-fa-by-powcai-5/ * @Auther: zhunn * @Date: 2020/11/3 19:41 * @Description: 子集 II diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java new file mode 100644 index 0000000..2f88577 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic.test120; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 22:02 + * @Description: 三角形最小路径和 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java new file mode 100644 index 0000000..dfc89df --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic.test152; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 22:02 + * @Description: 乘积最大子数组 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java new file mode 100644 index 0000000..0648c52 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic.test188; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 22:03 + * @Description: 买卖股票的最佳时机 IV + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java new file mode 100644 index 0000000..5d781c9 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic.test309; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 22:03 + * @Description: 最佳买卖股票时机含冷冻期 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java new file mode 100644 index 0000000..cde6bce --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.dynamic.test714; + +/** + * @Auther: zhunn + * @Date: 2020/11/3 22:04 + * @Description: 买卖股票的最佳时机含手续费 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index aee6262..0583254 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -1,19 +1,19 @@ 文档上没有,代码有的题: -test11 -test287 -test343 -test347 -test112 -test437 -test496 -test674 -offer.test57 +test11 盛最多水的容器 https://leetcode-cn.com/problems/container-with-most-water +test287 寻找重复数 https://leetcode-cn.com/problems/find-the-duplicate-number +test343 整数拆分 https://leetcode-cn.com/problems/integer-break +test347 前 K 个高频元素 https://leetcode-cn.com/problems/top-k-frequent-elements +test112 路径总和 https://leetcode-cn.com/problems/path-sum +test437 路径总和 III https://leetcode-cn.com/problems/path-sum-iii +test496 下一个更大元素 I https://leetcode-cn.com/problems/next-greater-element-i +test674 最长连续递增序列 https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence +offer.test57 和为s的连续正数序列 (https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/) 文档上有,代码上没有的题: -test474 -test494 -test213 -test337 +test474 一和零 https://leetcode-cn.com/problems/ones-and-zeroes +test494 目标和 https://leetcode-cn.com/problems/target-sum +test213 打家劫舍 II https://leetcode-cn.com/problems/house-robber-ii +test337 打家劫舍 III https://leetcode-cn.com/problems/house-robber-iii 剑指offer第2版:共75题 简单:共41题 From 6fffcdd84963e7c2d719a6fe648fdfabd1ed6cda Mon Sep 17 00:00:00 2001 From: zhunn Date: Wed, 4 Nov 2020 19:08:58 +0800 Subject: [PATCH 17/63] dp-2 --- .../com/chen/algorithm/znn/dynamic/Test.java | 119 +++++++++++++++ .../znn/dynamic/test120/Solution.java | 71 ++++++++- .../znn/dynamic/test121/Solution.java | 3 +- .../znn/dynamic/test123/Solution.java | 73 +++++++++- .../znn/dynamic/test152/Solution.java | 70 ++++++++- .../znn/dynamic/test188/Solution.java | 136 +++++++++++++++++- .../znn/dynamic/test309/Solution.java | 72 +++++++++- .../znn/dynamic/test53/Solution.java | 59 ++++++++ .../znn/dynamic/test714/Solution.java | 64 ++++++++- src/main/java/com/chen/algorithm/znn/note | 21 +-- 10 files changed, 671 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/Test.java b/src/main/java/com/chen/algorithm/znn/dynamic/Test.java index 0c8a237..9408d3e 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/Test.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/Test.java @@ -2,9 +2,128 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/ + * * @Auther: zhunn * @Date: 2020/10/24 17:23 * @Description: DP动态规划相关 */ public class Test { + + /** + * 买卖股票的最佳时机相关题: + * 121(最多买卖一次)、122(贪心,最多买卖多次,不限次)、123(最多买卖两次)、188(最多买卖K次)、 + * 309(可以买卖多次,有冷冻期)、714(可以买卖多次,一次买卖含一次手续费) + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票) + * + * 理解状态转移方程: + * + * 人为规定:如果当天买入股票的时候记录「交易发生一次」,如果当天卖出股票,不增加交易次数; + * 买入股票,手上持有的现金数减少(减去当天股价),相应地,卖出股票,手上持有的现金数增加(加上当天股价); + * 难点:还没发生的交易,并且还规定了当天必须持股的状态值应该设置为负无穷 + * + */ + + /** 121. 买卖股票的最佳时机 **/ + //给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + //如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 + //注意:你不能在买入股票前卖出股票。 + // + //示例 1: + //输入: [7,1,5,3,6,4] + //输出: 5 + //解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 + //注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 + //示例 2: + //输入: [7,6,4,3,1] + //输出: 0 + //解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + + + /**122. 买卖股票的最佳时机 II **/ + //给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + //设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 + //注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + // + //示例 1: + //输入: [7,1,5,3,6,4] + //输出: 7 + //解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + //随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + //示例 2: + //输入: [1,2,3,4,5] + //输出: 4 + //解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + //注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + //因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + //示例 3: + //输入: [7,6,4,3,1] + //输出: 0 + //解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + + + /** 123. 买卖股票的最佳时机 III **/ + //给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 + //设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 + //注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + // + //示例 1: + //输入: [3,3,5,0,0,3,1,4] + //输出: 6 + //解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 + //随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。 + //示例 2: + //输入: [1,2,3,4,5] + //输出: 4 + //解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + //注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + //因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + //示例 3: + //输入: [7,6,4,3,1] + //输出: 0 + //解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。 + + + /** 188. 买卖股票的最佳时机 IV **/ + //给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。 + //设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。 + //注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + //   + //示例 1: + //输入:k = 2, prices = [2,4,1] + //输出:2 + //解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。 + //示例 2: + //输入:k = 2, prices = [3,2,6,5,0,3] + //输出:7 + //解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。 + //随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。 + + + /** 309. 最佳买卖股票时机含冷冻期 **/ + //给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​ + //设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): + //你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + //卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 + //示例: + //输入: [1,2,3,0,2] + //输出: 3 + //解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出] + + + /** 714. 买卖股票的最佳时机含手续费 **/ + //给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。 + //你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。 + //返回获得利润的最大值。 + //注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。 + // + //示例 1: + //输入: prices = [1, 3, 2, 8, 4, 9], fee = 2 + //输出: 8 + //解释: 能够达到的最大利润: + //在此处买入 prices[0] = 1 + //在此处卖出 prices[3] = 8 + //在此处买入 prices[4] = 4 + //在此处卖出 prices[5] = 9 + //总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8. + } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java index 2f88577..2953242 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java @@ -1,9 +1,78 @@ package com.chen.algorithm.znn.dynamic.test120; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** + * https://leetcode-cn.com/problems/triangle/solution/di-gui-ji-yi-hua-dp-bi-xu-miao-dong-by-sweetiee/ + * * @Auther: zhunn * @Date: 2020/11/3 22:02 - * @Description: 三角形最小路径和 + * @Description: 三角形最小路径和:1-动态规划;2-动态规划-空间优化(推荐) + * 第i行的列数等于 i+1,即行数加一 */ public class Solution { + + /** + * 1-动态规划:时间和空间复杂度都是O(n^2) + * + * @param triangle + * @return + */ + public int minimumTotal(List> triangle) { + if (triangle == null || triangle.size() == 0) { + return 0; + } + + int n = triangle.size(); // 总行数 + int m = triangle.get(n - 1).size(); // 总列数 + int[][] dp = new int[n + 1][m + 1]; // dp[i][j] 表示从点 (i, j) 到底边的最小路径和。 由于存储最高层的数据,所以需要数值上加1 + + for (int i = n - 1; i >= 0; i--) { // 从三角形的最后一行开始递推。 + for (int j = 0; j <= i; j++) { + dp[i][j] = Math.min(dp[i + 1][j], dp[i + 1][j + 1]) + triangle.get(i).get(j); + } + } + + return dp[0][0]; + } + + /** + * 2-动态规划-空间优化(推荐):时间复杂度O(n^2)、空间复杂度是O(n) + * + * @param triangle + * @return + */ + public int minimumTotal2(List> triangle) { + if (triangle == null || triangle.size() == 0) { + return 0; + } + + int n = triangle.size(); + int m = triangle.get(n - 1).size(); + int[] dp = new int[m + 1]; + + for (int i = n - 1; i >= 0; i--) { + for (int j = 0; j <= i; j++) { + dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j); + } + } + + return dp[0]; + } + + @Test + public void testCase() { + List> triangle = new ArrayList<>(); + triangle.add(Arrays.asList(1)); + triangle.add(Arrays.asList(3, 4)); + triangle.add(Arrays.asList(6, 5, 7)); + triangle.add(Arrays.asList(4, 1, 8, 3)); + + System.out.println(minimumTotal2(triangle)); + + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java index 0172cef..bc3306e 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java @@ -7,7 +7,8 @@ * @Auther: zhunn * @Date: 2020/11/3 19:59 * @Description: 买卖股票的最佳时机:双指针法 - * 121、122(贪心)、123、188、309、714 + * 121(最多买卖一次)、122(贪心,最多买卖多次,不限次)、123(最多买卖两次)、188(最多买卖K次)、309(可以买卖多次,有冷冻期)、714(可以买卖多次,一次买卖含一次手续费) + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票) */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java index 79edab8..14c8cc6 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java @@ -1,9 +1,80 @@ package com.chen.algorithm.znn.dynamic.test123; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/dong-tai-gui-hua-by-liweiwei1419-7/ + * * @Auther: zhunn * @Date: 2020/11/3 21:06 - * @Description: 买卖股票的最佳时机 III:1-动态规划 + * @Description: 买卖股票的最佳时机 III:1-动态规划-优化空间;2-动态规划 */ public class Solution { + + /** + * 1-动态规划-优化空间 + * (由于今天只参考了昨天的状态,所以直接去掉第一维度不会影响状态转移的正确性) + * + * @param prices + * @return dp[i][j][k]: i 表示第几天(0-n),j表示交易了几次(0,1,2),k表示是否持股(0-不持股,1-持股) + * 此题可以用dp[j][k] 即可 + */ + public int maxProfit(int[] prices) { + if (prices == null || prices.length < 2) { + return 0; + } + int[][] dp = new int[3][2]; + dp[0][0] = 0; + dp[1][1] = -prices[0]; + dp[2][1] = Integer.MIN_VALUE; // 还没发生的交易,持股的时候应该初始化为负无穷 + + for (int i = 1; i < prices.length; i++) { + dp[1][1] = Math.max(-prices[i], dp[1][1]); + dp[1][0] = Math.max(dp[1][1] + prices[i], dp[1][0]); + dp[2][1] = Math.max(dp[1][0] - prices[i], dp[2][1]); + dp[2][0] = Math.max(dp[2][1] + prices[i], dp[2][0]); + } + return Math.max(dp[1][0], dp[2][0]); + } + + /** + * 2-动态规划 + * + * @param prices + * @return + */ + public int maxProfit2(int[] prices) { + if (prices == null || prices.length == 0) { + return 0; + } + // dp[i][j] ,表示 [0, i] 区间里,状态为 j 的最大收益 + // j = 0:什么都不操作 + // j = 1:第 1 次买入一支股票 + // j = 2:第 1 次卖出一支股票 + // j = 3:第 2 次买入一支股票 + // j = 4:第 2 次卖出一支股票 + + int n = prices.length; + int[][] dp = new int[n][5]; + dp[0][0] = 0; + dp[0][1] = -prices[0]; + for (int i = 0; i < n; i++) { + dp[i][3] = Integer.MIN_VALUE; + } + + for (int i = 1; i < n; i++) { + dp[i][0] = 0; + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); + dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]); + dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]); + dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]); + } + return Math.max(Math.max(dp[n - 1][0], dp[n - 1][2]), dp[n - 1][4]); + } + + @Test + public void test() { + int[] prices = {3, 3, 5, 0, 0, 3, 1, 4}; + System.out.println(maxProfit2(prices)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java index dfc89df..6898741 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java @@ -1,9 +1,77 @@ package com.chen.algorithm.znn.dynamic.test152; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/maximum-product-subarray/solution/dong-tai-gui-hua-li-jie-wu-hou-xiao-xing-by-liweiw/ + * * @Auther: zhunn * @Date: 2020/11/3 22:02 - * @Description: 乘积最大子数组 + * @Description: 乘积最大子数组:1-动态规划;2-动态规划-优化空间 */ public class Solution { + + /** + * 1-动态规划 + * + * @param nums + * @return + */ + public int maxProduct(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + // dp[i][0]:以 nums[i] 结尾的连续子数组的最小值 + // dp[i][1]:以 nums[i] 结尾的连续子数组的最大值 + int len = nums.length; + int[][] dp = new int[len][2]; + dp[0][0] = nums[0]; + dp[0][1] = nums[0]; + + for (int i = 1; i < len; i++) { + dp[i][0] = Math.min(nums[i], Math.min(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i])); + dp[i][1] = Math.max(nums[i], Math.max(dp[i - 1][0] * nums[i], dp[i - 1][1] * nums[i])); + } + + // 只关心最大值,需要遍历 + int res = dp[0][1]; + for (int i = 1; i < len; i++) { + res = Math.max(dp[i][1], res); + } + return res; + } + + /** + * 2-动态规划-优化空间 + * + * @param nums + * @return + */ + public int maxProduct2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int len = nums.length; + int[] dp = new int[2]; + dp[0] = nums[0]; + dp[1] = nums[0]; + int res = nums[0]; + + for (int i = 1; i < len; i++) { + int min = dp[0], max = dp[1]; + + dp[0] = Math.min(nums[i], Math.min(min * nums[i], max * nums[i])); + dp[1] = Math.max(nums[i], Math.max(min * nums[i], max * nums[i])); + res = Math.max(res, dp[1]); + } + return res; + } + + @Test + public void test() { + int[] nums = {2, 3, -2, 4}; + System.out.println(maxProduct2(nums)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java index 0648c52..33edf5b 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java @@ -1,9 +1,143 @@ package com.chen.algorithm.znn.dynamic.test188; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/solution/dong-tai-gui-hua-by-liweiwei1419-4/ * @Auther: zhunn * @Date: 2020/11/3 22:03 - * @Description: 买卖股票的最佳时机 IV + * @Description: 买卖股票的最佳时机 IV :1-动态规划-三维超出内存限制;2-动态规划-优化空间,降维,使用二维 + *

+ * 理解状态转移方程: + * 人为规定:如果当天买入股票的时候记录「交易发生一次」,如果当天卖出股票,不增加交易次数; + * 买入股票,手上持有的现金数减少(减去当天股价),相应地,卖出股票,手上持有的现金数增加(加上当天股价); + * 难点:还没发生的交易,并且还规定了当天必须持股的状态值应该设置为负无穷 */ public class Solution { + + // 超出内存限制 + //public int maxProfit(int k, int[] prices) { + // int len = prices.length; + // // 特殊判断 + // if (k == 0 || len < 2) { + // return 0; + // } + // // 特殊判断,因为交易一次需要 2 天,如果 k >= len / 2,相当于没有限制 + // // 转换为「力扣」第 122 题,使用贪心算法 + // if (k >= len / 2) { + // return greedy(prices, len); + // } + // + // // 状态转移方程里下标有 -1 的时候,为了防止数组下标越界,多开一行,因此第一维的长度是 len + 1 + // // 第二维表示交易次数,从 0 开始,因此第二维的长度是 k + 1 + // // 第三维表示是否持股,0:不持股,1:持股 + // int[][][] dp = new int[len + 1][k + 1][2]; + // + // // 初始化:把持股的部分都设置为一个较小的负值 + // // 注意:如果使用默认值 0,状态转移的过程中会做出错误的决策 + // for (int i = 0; i <= len; i++) { + // for (int j = 0; j <= k; j++) { + // dp[i][j][1] = Integer.MIN_VALUE; + // } + // } + // + // // 注意:i 和 j 都有 1 个位置的偏移 + // for (int i = 1; i <= len; i++) { + // for (int j = 1; j <= k; j++) { + // dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i - 1]); + // dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i - 1]); + // } + // } + // // 说明:第一维和第二维状态都具有前缀性质的,输出最后一个状态即可 + // return dp[len][k][0]; + //} + //private int greedy(int[] prices, int len) { + // // 转换为股票系列的第 2 题,使用贪心算法完成,思路是只要有利润,就交易 + // int res = 0; + // for (int i = 1; i < len; i++) { + // if (prices[i] > prices[i - 1]) { + // res += prices[i] - prices[i - 1]; + // } + // } + // return res; + //} + + /** + * 1-动态规划-三维超出内存限制 + * + * @param prices + * @param k + * @return + */ + public int maxProfit(int[] prices, int k) { + if (prices == null || prices.length == 0 || k == 0) { + return 0; + } + int len = prices.length; + if (k >= len / 2) { + return greedy(prices); + } + + int[][][] dp = new int[len + 1][k + 1][2]; + for (int i = 0; i <= len; i++) { + for (int j = 0; j <= k; j++) { + dp[i][j][1] = Integer.MIN_VALUE; + } + } + + // 注意:i 和 j 都有 1 个位置的偏移 + for (int i = 1; i <= len; i++) { + for (int j = 1; j <= k; j++) { + dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i - 1]); + dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i - 1]); + } + } + + + return dp[len][k][0]; + } + + private int greedy(int[] prices) { + int res = 0; + for (int i = 1; i < prices.length; i++) { + if (prices[i] > prices[i - 1]) { + res += prices[i] - prices[i - 1]; + } + } + return res; + } + + /** + * 2-动态规划-优化空间,降维,使用二维 + * + * @param prices + * @return + */ + public int maxProfit2(int[] prices, int k) { + if (prices == null || prices.length == 0 || k == 0) { + return 0; + } + int len = prices.length; + if (k >= len / 2) { + return greedy(prices); + } + + int[][] dp = new int[k + 1][2]; + for (int i = 0; i <= k; i++) { + dp[i][1] = Integer.MIN_VALUE; + } + for (int price : prices) { + for (int j = 1; j <= k; j++) { + dp[j][0] = Math.max(dp[j][0], dp[j][1] + price); + dp[j][1] = Math.max(dp[j][1], dp[j - 1][0] - price); + } + } + return dp[k][0]; + } + + @Test + public void test() { + int[] prices = {3, 2, 6, 5, 0, 3}; + System.out.println(maxProfit2(prices, 2)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java index 5d781c9..bc02961 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java @@ -1,9 +1,79 @@ package com.chen.algorithm.znn.dynamic.test309; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/solution/dong-tai-gui-hua-by-liweiwei1419-5/ + * * @Auther: zhunn * @Date: 2020/11/3 22:03 - * @Description: 最佳买卖股票时机含冷冻期 + * @Description: 最佳买卖股票时机含冷冻期:1-动态规划;2-动态规划-优化空间 */ public class Solution { + + /** + * 1-动态规划 + * + * @param prices + * @return + */ + public int maxProfit(int[] prices) { + int len = prices.length; + if (len < 2) { + return 0; + } + + int[][] dp = new int[len][3]; + dp[0][0] = 0; + dp[0][1] = -prices[0]; + dp[0][2] = 0; + + // dp[i][0]: 手上不持有股票,并且今天不是由于卖出股票而不持股,我们拥有的现金数 + // dp[i][1]: 手上持有股票时,我们拥有的现金数 + // dp[i][2]: 手上不持有股票,并且今天是由于卖出股票而不持股,我们拥有的现金数 + for (int i = 1; i < len; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]); + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); + dp[i][2] = dp[i - 1][1] + prices[i]; + } + return Math.max(dp[len - 1][0], dp[len - 1][2]); + } + + /** + * 2-动态规划-优化空间 + * + * @param prices + * @return + */ + public int maxProfit2(int[] prices) { + int len = prices.length; + if (len < 2) { + return 0; + } + + int[] dp = new int[3]; + + dp[0] = 0; + dp[1] = -prices[0]; + dp[2] = 0; + + int pre0 = dp[0]; + int pre2 = dp[2]; + + for (int i = 1; i < len; i++) { + dp[0] = Math.max(dp[0], pre2); + dp[1] = Math.max(dp[1], pre0 - prices[i]); + dp[2] = dp[1] + prices[i]; + + pre0 = dp[0]; + pre2 = dp[2]; + } + return Math.max(dp[0], dp[2]); + } + + @Test + public void test() { + int[] prices = {1, 2, 3, 0, 2}; + System.out.println(maxProfit(prices)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java new file mode 100644 index 0000000..9ef8984 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java @@ -0,0 +1,59 @@ +package com.chen.algorithm.znn.dynamic.test53; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/11/4 18:56 + * @Description: 最大子序和:1-动态规划;2-动态规划优化空间 + */ +public class Solution { + + /** + * 1-动态规划 + * + * @param nums + * @return + */ + public int maxSubArray(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int len = nums.length; + int[] dp = new int[len]; + dp[0] = nums[0]; + int res = nums[0]; + + for (int i = 1; i < len; i++) { + dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]); + res = Math.max(res, dp[i]); + } + return res; + } + + /** + * 2-动态规划优化空间 + * + * @param nums + * @return + */ + public int maxSubArray2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int pre = nums[0], res = nums[0]; + for (int i = 1; i < nums.length; i++) { + pre = Math.max(pre + nums[i], nums[i]); + res = Math.max(res, pre); + } + return res; + } + + @Test + public void test() { + int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; + System.out.println(maxSubArray2(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java index cde6bce..81bdc13 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java @@ -1,9 +1,71 @@ package com.chen.algorithm.znn.dynamic.test714; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/dong-tai-gui-hua-by-liweiwei1419-6/ * @Auther: zhunn * @Date: 2020/11/3 22:04 - * @Description: 买卖股票的最佳时机含手续费 + * @Description: 买卖股票的最佳时机含手续费:1-动态规划,2-动态规划-优化空间 + * 注意:人为规定在买入股票的时候扣除手续费 */ public class Solution { + + /** + * 1-动态规划 + * + * @param prices + * @return + */ + public int maxProfit(int[] prices, int fee) { + if (prices == null || prices.length < 2) { + return 0; + } + + // dp[i][j] 表示 [0, i] 区间内,到第 i 天(从 0 开始)状态为 j 时的最大收益' + // j = 0 表示不持股,j = 1 表示持股 + // 并且规定在买入股票的时候,扣除手续费 + + int len = prices.length; + int[][] dp = new int[len][2]; // 定义状态转移方程 + // 初始化值 + dp[0][0] = 0; + dp[0][1] = -prices[0] - fee; + + for (int i = 1; i < len; i++) { + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i] - fee); + } + return dp[len - 1][0]; + } + + /** + * 2-动态规划-优化空间 + * + * @param prices + * @param fee + * @return + */ + public int maxProfit2(int[] prices, int fee) { + if (prices == null || prices.length < 2) { + return 0; + } + + int len = prices.length; + int[] dp = new int[2]; + dp[0] = 0; + dp[1] = -prices[0] - fee; + for (int i = 1; i < len; i++) { + dp[0] = Math.max(dp[0], dp[1] + prices[i]); + dp[1] = Math.max(dp[1], dp[0] - prices[i] - fee); + } + return dp[0]; + } + + @Test + public void test() { + int[] prices = {1, 3, 2, 8, 4, 9}; + int fee = 2; + System.out.println(maxProfit2(prices, fee)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 0583254..ad78c02 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -1,19 +1,20 @@ -文档上没有,代码有的题: +补充练习: +array: test11 盛最多水的容器 https://leetcode-cn.com/problems/container-with-most-water test287 寻找重复数 https://leetcode-cn.com/problems/find-the-duplicate-number -test343 整数拆分 https://leetcode-cn.com/problems/integer-break +offer.test57 和为s的连续正数序列 (https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/) + +heap: test347 前 K 个高频元素 https://leetcode-cn.com/problems/top-k-frequent-elements -test112 路径总和 https://leetcode-cn.com/problems/path-sum -test437 路径总和 III https://leetcode-cn.com/problems/path-sum-iii + +tree: +test112 路径总和 https://leetcode-cn.com/problems/path-sum +test437 路径总和 III https://leetcode-cn.com/problems/path-sum-iii + +stack: test496 下一个更大元素 I https://leetcode-cn.com/problems/next-greater-element-i test674 最长连续递增序列 https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence -offer.test57 和为s的连续正数序列 (https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/) -文档上有,代码上没有的题: -test474 一和零 https://leetcode-cn.com/problems/ones-and-zeroes -test494 目标和 https://leetcode-cn.com/problems/target-sum -test213 打家劫舍 II https://leetcode-cn.com/problems/house-robber-ii -test337 打家劫舍 III https://leetcode-cn.com/problems/house-robber-iii 剑指offer第2版:共75题 简单:共41题 From ceed111392ff5fe2a0df2a52198cdc286c765105 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Wed, 4 Nov 2020 23:34:18 +0800 Subject: [PATCH 18/63] dp-3 --- .../znn/dynamic/test300/Solution.java | 43 ++++++++++++++++++ .../znn/dynamic/test322/Solution.java | 44 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java new file mode 100644 index 0000000..cb2da78 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java @@ -0,0 +1,43 @@ +package com.chen.algorithm.znn.dynamic.test300; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/ + * + * @Auther: zhunn + * @Date: 2020/11/4 21:03 + * @Description: 最长上升子序列:1-动态规划;2-动态规划-优化空间(贪心+二分查找) + */ +public class Solution { + + public int lengthOfLIS(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int len = nums.length; + int[] dp = new int[len]; + Arrays.fill(dp, 1); + + int res = 0; + for (int i = 1; i < len; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + res = Math.max(res, dp[i]); + } + + return res; + } + + @Test + public void test() { + int[] nums = {10, 9, 2, 5, 3, 7, 101, 18}; + System.out.println(lengthOfLIS(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java new file mode 100644 index 0000000..1886acd --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java @@ -0,0 +1,44 @@ +package com.chen.algorithm.znn.dynamic.test322; + +import org.junit.Test; + +import java.util.Arrays; + + +/** + * https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-shi-yong-wan-quan-bei-bao-wen-ti-/ + * 官方解答:https://leetcode-cn.com/problems/coin-change/solution/322-ling-qian-dui-huan-by-leetcode-solution/ + * + * @Auther: zhunn + * @Date: 2020/11/4 22:03 + * @Description: 零钱兑换:1-动态规划;2-动态规划-优化空间 + */ +public class Solution { + + public int coinChange(int[] coins, int amount) { + if (coins == null || coins.length == 0) { + return -1; + } + + int max = amount + 1; + int[] dp = new int[amount + 1]; // 给 0 占位 + Arrays.fill(dp, max); // 注意:因为要比较的是最小值,这个不可能的值就得赋值成为一个最大值 + + dp[0] = 0; // 理解 dp[0] = 0 的合理性,单独一枚硬币如果能够凑出面值,符合最优子结构 + for (int i = 1; i <= amount; i++) { + for (int j = 0; j < coins.length; j++) { + if (coins[j] <= i) { + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); + } + } + } + return dp[amount] > amount ? -1 : dp[amount]; + } + + @Test + public void test() { + int[] nums = {1, 2, 5}; + int amount = 10; + System.out.println(coinChange(nums, amount)); + } +} From f2431dff0248ad652b09fc51a1c1a94609a0cd30 Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 6 Nov 2020 19:10:18 +0800 Subject: [PATCH 19/63] dp-3 --- .../algorithm/study/test279/Solution.java | 4 +- .../znn/dynamic/test198/Solution.java | 64 +++++++ .../znn/dynamic/test213/Solution.java | 54 ++++++ .../znn/dynamic/test279/Solution.java | 30 ++++ .../znn/dynamic/test322/Solution.java | 1 + .../znn/dynamic/test337/Solution.java | 42 +++++ .../znn/dynamic/test343/Solution.java | 39 +++++ .../znn/dynamic/test416/Solution.java | 147 ++++++++++++++++ .../znn/dynamic/test474/Solution.java | 89 ++++++++++ .../znn/dynamic/test494/Solution.java | 157 ++++++++++++++++++ .../znn/dynamic/test518/Solution.java | 65 ++++++++ .../znn/dynamic/test62/Solution.java | 41 +++++ .../znn/dynamic/test64/Solution.java | 102 ++++++++++++ .../znn/dynamic/test72/Solution.java | 48 ++++++ 14 files changed, 881 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java diff --git a/src/main/java/com/chen/algorithm/study/test279/Solution.java b/src/main/java/com/chen/algorithm/study/test279/Solution.java index 0649d49..d0d4338 100644 --- a/src/main/java/com/chen/algorithm/study/test279/Solution.java +++ b/src/main/java/com/chen/algorithm/study/test279/Solution.java @@ -8,11 +8,11 @@ public class Solution { public int numSquares(int n) { - int[] dp = new int[n + 1]; + for (int i = 1; i <= n; i++) { dp[i] = i; - for (int j = 0; i - j * j >= 0; j++) { + for (int j = 1; i - j * j >= 0; j++) { dp[i] = Math.min(dp[i], dp[i - j * j] + 1); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java new file mode 100644 index 0000000..d5419c1 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java @@ -0,0 +1,64 @@ +package com.chen.algorithm.znn.dynamic.test198; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/house-robber/solution/da-jia-jie-she-by-leetcode-solution/ + * + * @Auther: zhunn + * @Date: 2020/11/6 17:16 + * @Description: 打家劫舍:1-动态规划;2-动态规划 + 滚动数组 + */ +public class Solution { + + /** + * 1-动态规划 + * 1. 偷窃第 k 间房屋,那么就不能偷窃第 k−1 间房屋,偷窃总金额为前 k−2 间房屋的最高总金额与第 k 间房屋的金额之和。 + * 2. 不偷窃第 k 间房屋,偷窃总金额为前 k−1 间房屋的最高总金额。 + * + * @param nums + * @return + */ + public int rob(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int len = nums.length; + if (len == 1) { + return nums[0]; + } + + int[] dp = new int[len]; // dp[i] 表示前 ii 间房屋能偷窃到的最高总金额 + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + + for (int i = 2; i < len; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); + } + return dp[len - 1]; + } + + public int rob2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int len = nums.length; + if (len == 1) { + return nums[0]; + } + + int first = nums[0], second = Math.max(nums[0], nums[1]); + for (int i = 2; i < len; i++) { + int temp = second; + second = Math.max(first + nums[i], temp); + first = temp; + } + return second; + } + + @Test + public void test() { + int[] nums = {2, 7, 9, 3, 1}; + System.out.println(rob2(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java new file mode 100644 index 0000000..518efab --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java @@ -0,0 +1,54 @@ +package com.chen.algorithm.znn.dynamic.test213; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * @Auther: zhunn + * @Date: 2020/11/6 17:45 + * @Description: 打家劫舍 II:在198题的基础上,选择不偷第一家或不偷最后一家 + */ +public class Solution { + + public int rob(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + int len = nums.length; + if (len == 1) { + return nums[0]; + } + return Math.max(myRob(Arrays.copyOfRange(nums, 0, len - 1)), + myRob(Arrays.copyOfRange(nums, 1, len))); + + } + + private int myRob2(int[] nums) { + int len = nums.length; + int[] dp = new int[len]; + dp[0] = nums[0]; + dp[1] = Math.max(nums[0], nums[1]); + + for (int i = 2; i < len; i++) { + dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); + } + return dp[len - 1]; + } + + private int myRob(int[] nums) { + int first = nums[0], second = nums[1]; + for (int i = 2; i < nums.length; i++) { + int temp = second; + second = Math.max(first + nums[i], temp); + first = temp; + } + return second; + } + + @Test + public void test() { + int[] nums = {1, 2, 3, 1}; + System.out.println(rob(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java new file mode 100644 index 0000000..4eb0e0d --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java @@ -0,0 +1,30 @@ +package com.chen.algorithm.znn.dynamic.test279; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/11/5 18:00 + * @Description: 完全平方数:1-动态规划 + */ +public class Solution { + + public int numSquares(int n) { + + int[] dp = new int[n + 1]; + //dp[0] = 0; //题意是给定正整数,不用考虑0 + + for (int i = 1; i <= n; i++) { + dp[i] = i; + for (int j = 1; i - j * j >= 0; j++) { + dp[i] = Math.min(dp[i], dp[i - j * j] + 1); + } + } + return dp[n]; + } + + @Test + public void test() { + System.out.println(numSquares(9)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java index 1886acd..02de398 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java @@ -12,6 +12,7 @@ * @Auther: zhunn * @Date: 2020/11/4 22:03 * @Description: 零钱兑换:1-动态规划;2-动态规划-优化空间 + * 返回所需的最少的硬币个数 */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java new file mode 100644 index 0000000..62b704c --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java @@ -0,0 +1,42 @@ +package com.chen.algorithm.znn.dynamic.test337; + +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/house-robber-iii/solution/shu-xing-dp-ru-men-wen-ti-by-liweiwei1419/ + * + * @Auther: zhunn + * @Date: 2020/11/6 18:35 + * @Description: 打家劫舍 III:1-树的后序遍历; + */ +public class Solution { + + public int rob(TreeNode root) { + int[] res = dfs(root); // 树的后序遍历 + return Math.max(res[0], res[1]); + } + + private int[] dfs(TreeNode root) { + if (root == null) { + return new int[]{0, 0}; + } + + int[] left = dfs(root.left); // 分类讨论的标准是:当前结点偷或者不偷 + int[] right = dfs(root.right); // 由于需要后序遍历,所以先计算左右子结点,然后计算当前结点的状态值 + + + int[] res = new int[2]; // dp[0]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点不偷; dp[1]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点偷 + res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); + res[1] = root.val + left[0] + right[0]; + return res; + } + + @Test + public void test() { + TreeNode left = new TreeNode(2, null, new TreeNode(3)); + TreeNode right = new TreeNode(3, null, new TreeNode(1)); + TreeNode root = new TreeNode(3, left, right); + System.out.println(rob(root)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java new file mode 100644 index 0000000..f026068 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java @@ -0,0 +1,39 @@ +package com.chen.algorithm.znn.dynamic.test343; + +import org.junit.Test; + +/** + * 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 + * + * @Auther: zhunn + * @Date: 2020/11/5 18:46 + * @Description: 整数拆分 + */ +public class Solution { + + public int integerBreak(int n) { + if (n < 2) { + return n; + } + + int[] dp = new int[n + 1]; // dp[i] 表示将正整数 i 拆分成至少两个正整数的和之后,这些正整数的最大乘积 + dp[0] = 0; + dp[1] = 1; + + for (int i = 2; i <= n; i++) { + for (int j = 1; j < i; j++) { + dp[i] = Math.max(dp[i], Math.max(dp[i - j] * j, (i - j) * j)); // 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j×(i−j); + // 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j×dp[i−j]。 + } + } + return dp[n]; + } + + + @Test + public void test() { + System.out.println(integerBreak(2)); + System.out.println(integerBreak(10)); + System.out.println(integerBreak(58)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java new file mode 100644 index 0000000..ab32363 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java @@ -0,0 +1,147 @@ +package com.chen.algorithm.znn.dynamic.test416; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/ + * 给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 + * + * @Auther: zhunn + * @Date: 2020/11/5 18:27 + * @Description: 分割等和子集:1-动态规划, 0-1背包问题;2-动态规划-剪枝;3-动态规划-优化空间 + */ +public class Solution { + + /** + * 1-动态规划, 0-1背包问题 + * + * @param nums + * @return + */ + public boolean canPartition(int[] nums) { + if (nums == null || nums.length == 0) { + return false; + } + + int len = nums.length; + int sum = 0; + for (int i = 0; i < len; i++) { + sum += nums[i]; + } + if ((sum & 1) == 1) { // 特判:如果是奇数,就不符合要求 + return false; + } + + int target = sum / 2; + boolean[][] dp = new boolean[len][target + 1]; // 创建二维数组,行:物品索引,列:容量(包括0) + //dp[0][0] = true; // 初始化成为 true 虽然不符合状态定义,但是从状态转移来说是完全可以的 + + if (nums[0] <= target) { // 先填表格第0行,第 1 个数只能让容积为它自己的背包恰好装满 + dp[0][nums[0]] = true; + } + + for (int i = 1; i < len; i++) { //再填表格后面几行 + for (int j = 0; j <= target; j++) { + dp[i][j] = dp[i - 1][j]; //直接把结果从上面一行抄下来,然后再修正 + if (nums[i] == j) { + dp[i][j] = true; + continue; + } + + if (nums[i] < j) { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; + } + } + } + + return dp[len - 1][target]; + } + + /** + * 2-动态规划-剪枝 + * + * @param nums + * @return + */ + public boolean canPartition2(int[] nums) { + if (nums == null || nums.length == 0) { + return false; + } + + int len = nums.length; + int sum = 0; + for (int num : nums) { + sum += num; + } + if ((sum & 1) == 1) { + return false; + } + + int target = sum / 2; + boolean[][] dp = new boolean[len][target + 1]; + dp[0][0] = true; // 初始化成为 true 虽然不符合状态定义,但是从状态转移来说是完全可以的 + + if (nums[0] <= target) { + dp[0][nums[0]] = true; + } + + for (int i = 1; i < len; i++) { + for (int j = 0; j <= target; j++) { + dp[i][j] = dp[i - 1][j]; + if (nums[i] <= j) { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; + } + + if (dp[i][target]) { // 由于状态转移方程的特殊性,提前结束,可以认为是剪枝操作 + return true; + } + } + } + return dp[len - 1][target]; + } + + /** + * 3-动态规划-优化空间 + * + * @param nums + * @return + */ + public boolean canPartition3(int[] nums) { + if (nums == null || nums.length == 0) { + return false; + } + + int len = nums.length; + int sum = 0; + for (int num : nums) { + sum += num; + } + if ((sum & 1) == 1) { + return false; + } + + int target = sum / 2; + boolean[] dp = new boolean[target + 1]; + dp[0] = true; + + if (nums[0] <= target) { + dp[nums[0]] = true; + } + + for (int i = 1; i < len; i++) { + for (int j = target; j >= nums[i]; j--) { // 使用一维表格,从后向前 + if (dp[target]) { + return true; + } + dp[j] = dp[j] || dp[j - nums[i]]; + } + } + return dp[target]; + } + + @Test + public void test() { + int[] nums = {1, 5, 11, 5}; + System.out.println(canPartition(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java new file mode 100644 index 0000000..1aff993 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java @@ -0,0 +1,89 @@ +package com.chen.algorithm.znn.dynamic.test474; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/ones-and-zeroes/solution/dong-tai-gui-hua-zhuan-huan-wei-0-1-bei-bao-wen-ti/ + * + * @Auther: zhunn + * @Date: 2020/11/6 14:54 + * @Description: 一和零:1-动态规划,0-1背包问题;2-动态规划优化空间(滚动数组,从后往前) + */ +public class Solution { + + public int findMaxForm(String[] strs, int m, int n) { + int[][] dp = new int[m + 1][n + 1]; + for (String s : strs) { + int[] count = countzeroesones(s); + for (int zeroes = m; zeroes >= count[0]; zeroes--) + for (int ones = n; ones >= count[1]; ones--) + dp[zeroes][ones] = Math.max(1 + dp[zeroes - count[0]][ones - count[1]], dp[zeroes][ones]); + } + return dp[m][n]; + } + + public int[] countzeroesones(String s) { + int[] cnt = new int[2]; + for (int i = 0; i < s.length(); i++) { + cnt[s.charAt(i) - '0']++; + } + return cnt; + } + + /** + * 1-动态规划,0-1背包问题 + * 定义状态:尝试题目问啥,就把啥定义成状态。dp[i][j][k] 表示输入字符串在子区间 [0, i] 能够使用 j 个 0 和 k 个 1 的字符串的最大数量。 + * + * @param strs + * @param m 0的个数 + * @param n 1的个数 + * @return + */ + public int findMaxForm1(String[] strs, int m, int n) { + int len = strs.length; + int[][][] dp = new int[len + 1][m + 1][n + 1]; + + for (int i = 1; i <= len; i++) { + int[] cnt = countzeroesones(strs[i - 1]); // 注意:有一位偏移 + for (int j = 0; j <= m; j++) { + for (int k = 0; k <= n; k++) { + dp[i][j][k] = dp[i - 1][j][k]; // 先把上一行抄下来 + + if (j >= cnt[0] && k >= cnt[1]) { // 超过最大0和1的限制,不选此字符串 + dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - cnt[0]][k - cnt[1]] + 1); // dp[i - 1][j][k],不选;dp[i][j - cnt[0]][k - cnt[1]] + 1,选 + } + } + } + } + return dp[len][m][n]; + } + + /** + * 2-动态规划优化空间(滚动数组,从后往前) + * + * @param strs + * @param m 0的个数 + * @param n 1的个数 + * @return + */ + public int findMaxForm2(String[] strs, int m, int n) { + int[][] dp = new int[m + 1][n + 1]; + //dp[0][0] = 0; + + for (String str : strs) { + int[] cnt = countzeroesones(str); + for (int i = m; i >= cnt[0]; i--) { + for (int j = n; j >= cnt[1]; j--) { + dp[i][j] = Math.max(dp[i][j], dp[i - cnt[0]][j - cnt[1]] + 1); + } + } + } + return dp[m][n]; + } + + @Test + public void test() { + String[] strs = {"10", "0001", "111001", "1", "0"}; + System.out.println(findMaxForm2(strs, 5, 3)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java new file mode 100644 index 0000000..2e025c5 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java @@ -0,0 +1,157 @@ +package com.chen.algorithm.znn.dynamic.test494; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/target-sum/solution/huan-yi-xia-jiao-du-ke-yi-zhuan-huan-wei-dian-xing/ + * + * @Auther: zhunn + * @Date: 2020/11/6 16:03 + * @Description: 目标和:1-枚举;2-动态规划,0-1背包问题;3-动态规划-优化空间 + */ +public class Solution { + + + int count = 0; + + /** + * 1-暴力枚举 + * 时间复杂度:O(2^n) + * 空间复杂度:O(n) + * + * @param nums + * @param S + * @return + */ + public int findTargetSumWays(int[] nums, int S) { + if (nums == null || nums.length == 0) { + return count; + } + caculate(nums, 0, 0, S); + return count; + } + + private void caculate(int[] nums, int i, int sum, int S) { + if (i == nums.length) { + if (sum == S) count++; + return; + } + caculate(nums, i + 1, sum + nums[i], S); + caculate(nums, i + 1, sum - nums[i], S); + } + + /** + * 2-动态规划,0-1背包问题 + * 时间复杂度:O(n*sum),其中 N 是数组 nums 的长度。 + * 空间复杂度:O(n*sum) + * dp[i][j]: i(1 ~ len)表示遍历(不一定选)了 i 个元素,j(0 ~ sum) 表示它们的和 + *

+ * 初始化: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] + * + * @param nums + * @param S + * @return + */ + public int findTargetSumWays2(int[] nums, int S) { + int sum = 0; + for (int num : nums) { + sum += num; + } + if (((sum + S) & 1) == 1) { // 背包容量为整数,sum + S为奇数的话不满足要求 + return 0; + } + if (S > sum) { // 目标和不可能大于总和 + return 0; + } + + int target = (sum + S) >> 1; + int len = nums.length; + int[][] dp = new int[len + 1][target + 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 <= target; 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][target]; + } + + public int findTargetSumWays2_test(int[] nums, int S) { + int sum = 0; + for (int num : nums) { + sum += num; + } + if (((sum + S) & 1) == 1) { // 奇数 + return 0; + } + if (S > sum) { + return 0; + } + + int target = (S + sum) >> 1; + int len = nums.length; + int[][] dp = new int[len + 1][target + 1]; + dp[0][0] = 1; + + for (int i = 1; i <= len; i++) { + for (int j = 0; j <= target; j++) { + if (j < nums[i - 1]) { + 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][target]; + } + + public int findTargetSumWays3(int[] nums, int S) { + int sum = 0; + for (int num : nums) { + sum += num; + } + if (((sum + S) & 1) == 1) { // 背包容量为整数,sum+S为奇数的话不满足要求 + return 0; + } + if (S > sum) { // 目标和不可能大于总和 + return 0; + } + + int target = (sum + S) >> 1; + int[] dp = new int[target + 1]; + dp[0] = 1; + + for (int num : nums) { + for (int i = target; i >= num; i--) { + dp[i] = dp[i] + dp[i - num]; + } + } + return dp[target]; + } + + @Test + public void test() { + int[] nums = {1, 1, 1, 1, 1}; + System.out.println(findTargetSumWays3(nums, 3)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java new file mode 100644 index 0000000..55af139 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java @@ -0,0 +1,65 @@ +package com.chen.algorithm.znn.dynamic.test518; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/coin-change-2/solution/ling-qian-dui-huan-iihe-pa-lou-ti-wen-ti-dao-di-yo/ + * https://leetcode-cn.com/problems/coin-change-2/solution/dong-tai-gui-hua-wan-quan-bei-bao-wen-ti-by-liweiw/ + * 官方解答:https://leetcode-cn.com/problems/coin-change-2/solution/ling-qian-dui-huan-ii-by-leetcode/ + * + * @Auther: zhunn + * @Date: 2020/11/5 9:52 + * @Description: 零钱兑换 II:1-动态规划 + * 返回所有组合数 + * 组合问题,交换循环顺序就是排列问题(爬楼梯) + */ +public class Solution { + + public int change(int amount, int[] coins) { + if (coins == null || coins.length == 0) { + if (amount == 0) { + return 1; + } + return 0; + } + + int[] dp = new int[amount + 1]; + dp[0] = 1; // amount=0时,有一种组合 0 + + for (int coin : coins) { + for (int x = coin; x <= amount; x++) { + dp[x] = dp[x] + dp[x - coin]; + } + } + return dp[amount]; + } + + public int change2(int amount, int[] coins) { + if (coins == null || coins.length == 0) { + if (amount == 0) { + return 1; + } + return 0; + } + + int[] dp = new int[amount + 1]; + dp[0] = 1; + + for (int coin : coins) { // 枚举硬币 + for (int x = 1; x <= amount; x++) { // 枚举金额 + if (coin > x) { + continue; // coin不能大于金额 + } + dp[x] = dp[x] + dp[x - coin]; + } + } + return dp[amount]; + } + + @Test + public void test() { + int amount = 5; + int[] coins = {1, 2, 5}; + System.out.println(change2(amount, coins)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java new file mode 100644 index 0000000..c487aae --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java @@ -0,0 +1,41 @@ +package com.chen.algorithm.znn.dynamic.test62; + +import org.junit.Test; + +/** + * @Auther: zhunn + * @Date: 2020/11/5 16:05 + * @Description: 不同路径:1-动态规划 + * 返回共有几条路径 + */ +public class Solution { + + public int uniquePaths(int m, int n) { + if (m == 0 || n == 0) { + return 0; + } + //if (m == 1 || n == 1) { + // return 1; + //} + + int[][] dp = new int[m][n]; //定义状态转移方程 + for (int i = 0; i < m; i++) { //边界初始化 + dp[i][0] = 1; + } + for (int j = 0; j < n; j++) { + dp[0][j] = 1; + } + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; + } + } + return dp[m - 1][n - 1]; + } + + @Test + public void test() { + System.out.println(uniquePaths(7, 3)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java new file mode 100644 index 0000000..1131243 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java @@ -0,0 +1,102 @@ +package com.chen.algorithm.znn.dynamic.test64; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/ + * + * @Auther: zhunn + * @Date: 2020/11/5 11:33 + * @Description: 最小路径和:1-动态规划;2-动态规划-优化空间,使用原数组空间;3-动态规划-优化空间,不更改原数组(可忽略) + */ +public class Solution { + + /** + * 1-动态规划,官方解答 + * + * @param grid + * @return + */ + public int minPathSum(int[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + int[][] dp = new int[rows][cols]; // dp[i][j],i表示行,j表示列 + dp[0][0] = grid[0][0]; + + for (int i = 1; i < rows; i++) { + dp[i][0] = dp[i - 1][0] + grid[i][0]; + } + for (int j = 1; j < cols; j++) { + dp[0][j] = dp[0][j - 1] + grid[0][j]; + } + + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; + } + } + return dp[rows - 1][cols - 1]; + } + + /** + * 2-动态规划-优化空间,使用原数组空间 + * + * @return + */ + public int minPathSum2(int[][] grid) { + if (grid == null || grid.length == 0) { + return 0; + } + + int rows = grid.length; + int cols = grid[0].length; + + //int[][] dp = new int[rows][cols]; // dp[i][j],i表示行,j表示列 + //dp[0][0] = grid[0][0]; + + for (int i = 1; i < rows; i++) { + grid[i][0] = grid[i - 1][0] + grid[i][0]; + } + for (int j = 1; j < cols; j++) { + grid[0][j] = grid[0][j - 1] + grid[0][j]; + } + + for (int i = 1; i < rows; i++) { + for (int j = 1; j < cols; j++) { + grid[i][j] = Math.min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]; + } + } + return grid[rows - 1][cols - 1]; + } + + /** + * 3-动态规划-优化空间,不更改原数组 + * + * @param grid + * @return + */ + public int minPathSum3(int[][] grid) { + int len = grid[0].length; + int[] dp = new int[len]; + dp[0] = grid[0][0]; + for (int i = 1; i < len; i++) + dp[i] = dp[i - 1] + grid[0][i]; + for (int i = 1; i < grid.length; i++) { + dp[0] = dp[0] + grid[i][0]; + for (int j = 1; j < len; j++) + dp[j] = Math.min(dp[j - 1] + grid[i][j], dp[j] + grid[i][j]); + } + return dp[len - 1]; + } + + @Test + public void testCase() { + int[][] nums = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; + + System.out.println(minPathSum2(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java new file mode 100644 index 0000000..bc22da5 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java @@ -0,0 +1,48 @@ +package com.chen.algorithm.znn.dynamic.test72; + +import org.junit.Test; + +/** + * 官方:https://leetcode-cn.com/problems/edit-distance/solution/bian-ji-ju-chi-by-leetcode-solution/ + * https://leetcode-cn.com/problems/edit-distance/solution/zi-di-xiang-shang-he-zi-ding-xiang-xia-by-powcai-3/ + * + * @Auther: zhunn + * @Date: 2020/11/5 15:09 + * @Description: 编辑距离:1-动态规划 + */ +public class Solution { + + public int minDistance(String word1, String word2) { + int m = word1 == null ? 0 : word1.length(); + int n = word2 == null ? 0 : word2.length(); + if (m == 0 || n == 0) { // m*n == 0,有一个字符串为空串 + return m + n; + } + + int[][] dp = new int[m + 1][n + 1]; // 多开一行一列是为了保存边界条件,即字符长度为 0 的情况,这一点在字符串的动态规划问题中比较常见 + for (int i = 0; i < m + 1; i++) { // 边界状态初始化:当 word 2 长度为 0 时,将 word1 的全部删除 + dp[i][0] = i; + } + for (int j = 0; j < n + 1; j++) { // 当 word1 长度为 0 时,就插入所有 word2 的字符 + dp[0][j] = j; + } + + for (int i = 1; i < m + 1; i++) { + for (int j = 1; j < n + 1; j++) { + if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i][j - 1]) + 1; + } + } + } + return dp[m][n]; + } + + @Test + public void test() { + System.out.println(minDistance("horse", "ros")); + } + + +} From d533dc67750aaa50bcf96733e477abbdf514427e Mon Sep 17 00:00:00 2001 From: chenweijie Date: Sun, 8 Nov 2020 15:24:27 +0800 Subject: [PATCH 20/63] bitmap --- .../com/chen/algorithm/znn/bitmap/Test.java | 9 +++ .../znn/bitmap/test136/Solution.java | 39 +++++++++++ .../znn/bitmap/test191/Solution.java | 47 +++++++++++++ .../znn/bitmap/test231/Solution.java | 48 +++++++++++++ .../znn/bitmap/test338/Solution.java | 58 ++++++++++++++++ .../znn/bitmap/test461/Solution.java | 68 +++++++++++++++++++ 6 files changed, 269 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/Test.java b/src/main/java/com/chen/algorithm/znn/bitmap/Test.java index 8c71c49..6700ac6 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/Test.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/Test.java @@ -6,4 +6,13 @@ * @Description: 位运算相关 */ public class Test { + /* + 位运算操作: + 1、 x & 1 == 1 or x & 1 == 0 判断奇偶(x % 2 == 1) + 2、 x = x & (x-1) =>清零最低位的 1,即将最低位的1设置为0 + 3、 x & -x => 得到最低位的 1 + 4、任何数和 0 做异或运算,结果仍然是原来的数,即 a⊕0=a。 + 5、任何数和其自身做异或运算,结果是 0,a⊕a=0。 + 6、异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。 + */ } diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java new file mode 100644 index 0000000..97377ab --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java @@ -0,0 +1,39 @@ +package com.chen.algorithm.znn.bitmap.test136; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/ + * + * @Auther: zhunn + * @Date: 2020/11/07 17:23 + * @Description: 只出现一次的数字:1-hash表存储;2-位运算 + * 1、任何数和 0 做异或运算,结果仍然是原来的数,即 a⊕0=a。 + * 2、任何数和其自身做异或运算,结果是 0,a⊕a=0。 + * 3、异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。 + */ +public class Solution { + + /** + * 2-位运算 + * @param nums + * @return + */ + public int singleNumber(int[] nums) { + if (nums == null || nums.length == 0) { + return -1; + } + + int single = 0; + for (int num : nums) { + single = single ^ num; + } + return single; + } + + @Test + public void test() { + int[] nums = {7, 1, 2, 1, 2}; + System.out.println(singleNumber(nums)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java new file mode 100644 index 0000000..b188add --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java @@ -0,0 +1,47 @@ +package com.chen.algorithm.znn.bitmap.test191; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/number-of-1-bits/solution/wei-1de-ge-shu-by-leetcode/ + * + * @Auther: zhunn + * @Date: 2020/11/07 21:23 + * @Description: 位1的个数:1-位运算;2-循环和位移动 + * 对于任意数字 n ,将 n 和 n−1 做与运算,会把最后一个 1 的位变成 0 + */ +public class Solution { + + /** + * 1-位运算 + * + * @param n + * @return + */ + public int hammingWeight(int n) { + int sum = 0; + while (n != 0) { + sum++; + n = n & (n - 1); // 将数字n最后一位1变为0 + } + return sum; + } + + public int hammingWeight2(int n) { + + int sum = 0; + int mask = 1; + for (int i = 0; i < 32; i++) { + if ((n & mask) != 0) { + sum++; + } + mask = mask << 1; + } + return sum; + } + + @Test + public void test() { + System.out.println(hammingWeight(-3)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java new file mode 100644 index 0000000..74cbec5 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java @@ -0,0 +1,48 @@ +package com.chen.algorithm.znn.bitmap.test231; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/power-of-two/solution/2de-mi-by-leetcode/ + * + * @Auther: zhunn + * @Date: 2020/11/07 22:23 + * @Description: 2的幂:1-位运算-获取二进制中最右边的 1(x&(-x));2-位运算-去除二进制中最右边的 1 (x&(x-1)) + * 2 的幂二进制表示只含有一个 1。 + */ +public class Solution { + + /** + * 1-位运算-获取二进制中最右边的 1(x&(-x)) + * + * @param n + * @return + */ + public boolean isPowerOfTwo(int n) { + if (n == 0) { + return false; + } + + long x = (long) n; + return (x & (-x)) == x; + } + + /** + * 2-位运算-去除二进制中最右边的 1 (x&(x-1)) + * + * @param n + * @return + */ + public boolean isPowerOfTwo2(int n) { + if (n == 0) { + return false; + } + long x = (long) n; + return (x & (x - 1)) == 0; + } + + @Test + public void test() { + System.out.println(isPowerOfTwo(16)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java new file mode 100644 index 0000000..1777d29 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java @@ -0,0 +1,58 @@ +package com.chen.algorithm.znn.bitmap.test338; + +import com.alibaba.fastjson.JSON; +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode/ + * + * @Auther: zhunn + * @Date: 2020/11/07 22:23 + * @Description: 比特位计数:1-位运算-Pop count;2-动态规划+最后设置位;3-动态规划+最高有效位;4-动态规划+最低有效位; + */ +public class Solution { + + /** + * 1-位运算-Pop count + * + * @param num + * @return + */ + public int[] countBits(int num) { + int[] res = new int[num + 1]; + + for (int i = 1; i <= num; i++) { + res[i] = popCount(i); + } + return res; + } + + private int popCount(int n) { + int count = 0; + while (n != 0) { + count++; + n = n & (n - 1); + } + return count; + } + + /** + * 2-动态规划+最后设置位 + * + * @param num + * @return + */ + public int[] countBits2(int num) { + int[] res = new int[num + 1]; + for (int i = 1; i <= num; i++) { + res[i] = res[i & (i - 1)] + 1; + } + return res; + } + + @Test + public void test() { + System.out.println(JSON.toJSONString(countBits(2))); + System.out.println(JSON.toJSONString(countBits2(5))); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java new file mode 100644 index 0000000..ce2b87d --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java @@ -0,0 +1,68 @@ +package com.chen.algorithm.znn.bitmap.test461; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode/ + * + * @Auther: zhunn + * @Date: 2020/11/07 22:23 + * @Description: 汉明距离:1-内置位计数功能;2-移位;3-布赖恩·克尼根算法(x&(x-1)) + */ +public class Solution { + + /** + * 1-内置位计数功能 + * + * @param x + * @param y + * @return + */ + public int hammingDistance(int x, int y) { + return Integer.bitCount(x ^ y); + } + + /** + * 2-移位 + * + * @param x + * @param y + * @return + */ + public int hammingDistance2(int x, int y) { + int dis = x ^ y; + int res = 0; + + while (dis != 0) { + if ((dis & 1) == 1) { + res++; + } + dis = dis >> 1; + } + return res; + } + + /** + * 3-布赖恩·克尼根算法(x&(x-1)) + * + * @param x + * @param y + * @return + */ + public int hammingDistance3(int x, int y) { + int dis = x ^ y; + int res = 0; + while (dis != 0) { + res++; + dis = dis & (dis - 1); + } + return res; + } + + @Test + public void test() { + System.out.println(hammingDistance(1, 4)); + System.out.println(hammingDistance2(1, 4)); + System.out.println(hammingDistance3(1, 4)); + } +} From af0506be1033d43ed47489645501cfd2e0a812db Mon Sep 17 00:00:00 2001 From: chenweijie Date: Sun, 8 Nov 2020 22:32:49 +0800 Subject: [PATCH 21/63] frequency --- .../chen/algorithm/study/test208/Trie.java | 3 +- .../znn/array/offer/test57/Solution.java | 9 ++ .../algorithm/znn/array/test11/Solution.java | 9 ++ .../algorithm/znn/array/test287/Solution.java | 9 ++ .../znn/frequency/test146/LRUCache.java | 96 +++++++++++++++++++ .../znn/frequency/test146/LRUCacheMap.java | 32 +++++++ .../algorithm/znn/frequency/test208/Trie.java | 69 +++++++++++++ .../algorithm/znn/heap/test347/Solution.java | 9 ++ .../algorithm/znn/stack/test496/Solution.java | 9 ++ .../algorithm/znn/stack/test674/Solution.java | 9 ++ .../algorithm/znn/tree/test112/Solution.java | 9 ++ .../algorithm/znn/tree/test437/Solution.java | 9 ++ 12 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test11/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test287/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCacheMap.java create mode 100644 src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java create mode 100644 src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java diff --git a/src/main/java/com/chen/algorithm/study/test208/Trie.java b/src/main/java/com/chen/algorithm/study/test208/Trie.java index 43a4bd7..d8a712d 100644 --- a/src/main/java/com/chen/algorithm/study/test208/Trie.java +++ b/src/main/java/com/chen/algorithm/study/test208/Trie.java @@ -77,8 +77,7 @@ public TrieNode() { } TrieNode(char c) { - TrieNode node = new TrieNode(); - node.val = c; + this.val = c; } } diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java new file mode 100644 index 0000000..ac4e8cc --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.array.offer.test57; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 剑指 Offer 57 - II. 和为s的连续正数序列 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java new file mode 100644 index 0000000..eea074e --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.array.test11; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 盛最多水的容器 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java new file mode 100644 index 0000000..394eeee --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.array.test287; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 寻找重复数 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java new file mode 100644 index 0000000..501c198 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java @@ -0,0 +1,96 @@ +package com.chen.algorithm.znn.frequency.test146; + + +import java.util.HashMap; +import java.util.Map; + +/** + * https://leetcode-cn.com/problems/lru-cache/ + * + * @Auther: zhunn + * @Date: 2020/11/08 14:47 + * @Description: LRU缓存机制:哈希表 + 双向链表 + */ +public class LRUCache { + + class CacheNode { + private int key; + private int val; + private CacheNode pre; + private CacheNode next; + + public CacheNode() { + } + + public CacheNode(int key, int val) { + this.key = key; + this.val = val; + } + } + + private Map cache = new HashMap<>(); + private int size; + private int capacity; + private CacheNode head, tail; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.size = 0; + this.head = new CacheNode(); + this.tail = new CacheNode(); + head.next = tail; + tail.pre = head; + } + + public int get(int key) { + CacheNode node = cache.get(key); + if (node == null) { + return -1; + } + moveToHead(node); + return node.val; + } + + public void put(int key, int value) { + CacheNode node = cache.get(key); + if (node != null) { + node.val = value; + moveToHead(node); + return; + } + + CacheNode newNode = new CacheNode(key, value); + cache.put(key, newNode); + addToHead(newNode); + size++; + + if (size > capacity) { + CacheNode tail = removeTail(); + cache.remove(tail.key); + size--; + } + } + + public void addToHead(CacheNode node) { + node.pre = head; + node.next = head.next; + head.next.pre = node; + head.next = node; + } + + public void removeNode(CacheNode node) { + node.pre.next = node.next; + node.next.pre = node.pre; + } + + public void moveToHead(CacheNode node) { + removeNode(node); + addToHead(node); + } + + public CacheNode removeTail() { + CacheNode res = tail.pre; + removeNode(res); + return res; + } +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCacheMap.java b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCacheMap.java new file mode 100644 index 0000000..a4bb03e --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCacheMap.java @@ -0,0 +1,32 @@ +package com.chen.algorithm.znn.frequency.test146; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 14:47 + * @Description: LRU缓存机制:1-使用java的LinkedHashMap + */ +public class LRUCacheMap extends LinkedHashMap { + + private int capacity; + + public LRUCacheMap(int capacity) { + super(capacity, 0.75f, true); + this.capacity = capacity; + } + + public int get(int key) { + return super.getOrDefault(key, -1); + } + + public void put(int key, int value) { + super.put(key, value); + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } +} diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java b/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java new file mode 100644 index 0000000..cc4a6ca --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java @@ -0,0 +1,69 @@ +package com.chen.algorithm.znn.frequency.test208; + +/** + * https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shu-ju-jie-gou-she-ji-zhi-shi-xian-trie-qian-zhui-/ + * + * @Auther: zhunn + * @Date: 2020/11/08 14:46 + * @Description: 实现 Trie (前缀树) + */ +public class Trie { + + public Trie root; + public char val; + public Trie[] children = new Trie[26]; + public boolean isWord; + + public Trie() { + root = new Trie(' '); + } + + public Trie(char val) { + this.val = val; + } + + /** + * Inserts a word into the trie. + */ + public void insert(String word) { + Trie ws = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (ws.children[c - 'a'] == null) { + ws.children[c - 'a'] = new Trie(c); + } + ws = ws.children[c - 'a']; + } + ws.isWord = true; + } + + /** + * Returns if the word is in the trie. + */ + public boolean search(String word) { + Trie ws = root; + for (int i = 0; i < word.length(); i++) { + char c = word.charAt(i); + if (ws.children[c - 'a'] == null) { + return false; + } + ws = ws.children[c - 'a']; + } + return ws.isWord; + } + + /** + * Returns if there is any word in the trie that starts with the given prefix. + */ + public boolean startsWith(String prefix) { + Trie ws = root; + for (int i = 0; i < prefix.length(); i++) { + char c = prefix.charAt(i); + if (ws.children[c - 'a'] == null) { + return false; + } + ws = ws.children[c - 'a']; + } + return true; + } +} diff --git a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java new file mode 100644 index 0000000..9ba67d4 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.heap.test347; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 前 K 个高频元素 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java new file mode 100644 index 0000000..694c38b --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.stack.test496; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 下一个更大元素 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java new file mode 100644 index 0000000..80ef45f --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.stack.test674; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 最长连续递增序列 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java new file mode 100644 index 0000000..7ec7104 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.tree.test112; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 路径总和 + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java new file mode 100644 index 0000000..4fefe1d --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.tree.test437; + +/** + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 路径总和 III + */ +public class Solution { +} From 90ec6fdac99471ee5e409dbc5ca1471514c38013 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 9 Nov 2020 17:38:32 +0800 Subject: [PATCH 22/63] =?UTF-8?q?=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../znn/array/offer/test57/Solution.java | 78 ++++++++++++++++++- .../algorithm/znn/array/test11/Solution.java | 28 ++++++- .../algorithm/znn/array/test287/Solution.java | 58 +++++++++++++- .../algorithm/znn/array/test674/Solution.java | 32 ++++++++ .../com/chen/algorithm/znn/heap/Test.java | 3 +- .../algorithm/znn/heap/test347/Solution.java | 50 +++++++++++- .../algorithm/znn/stack/test496/Solution.java | 42 +++++++++- .../algorithm/znn/stack/test674/Solution.java | 9 --- .../algorithm/znn/tree/test112/Solution.java | 75 +++++++++++++++++- .../algorithm/znn/tree/test113/Solution.java | 36 ++++++--- .../algorithm/znn/tree/test437/Solution.java | 24 ++++++ 11 files changed, 407 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/array/test674/Solution.java delete mode 100644 src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java index ac4e8cc..40cd28b 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java @@ -1,9 +1,85 @@ package com.chen.algorithm.znn.array.offer.test57; +import com.alibaba.fastjson.JSON; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + /** + * https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/solution/shi-yao-shi-hua-dong-chuang-kou-yi-ji-ru-he-yong-h/ + * * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 剑指 Offer 57 - II. 和为s的连续正数序列 + * @Description: 剑指 Offer 57 - II. 和为s的连续正数序列:滑动窗口法 */ public class Solution { + + //public int[][] findContinuousSequence(int target) { + // int i = 1; // 滑动窗口的左边界 + // int j = 1; // 滑动窗口的右边界 + // int sum = 0; // 滑动窗口中数字的和 + // List res = new ArrayList<>(); + // + // while (i <= target / 2) { + // if (sum < target) { + // // 右边界向右移动 + // sum += j; + // j++; + // } else if (sum > target) { + // // 左边界向右移动 + // sum -= i; + // i++; + // } else { + // // 记录结果 + // int[] arr = new int[j - i]; + // for (int k = i; k < j; k++) { + // arr[k - i] = k; + // } + // res.add(arr); + // // 左边界向右移动 + // sum -= i; + // i++; + // } + // } + // + // return res.toArray(new int[res.size()][]); + //} + + /** + * 滑动窗口法 + * + * @param target + * @return + */ + public int[][] findContinuousSequence(int target) { + int left = 1, right = 1; + int sum = 0; + List res = new ArrayList<>(); + + while (left <= target / 2) { + if (sum < target) { + sum += right; + right++; + } else if (sum > target) { + sum -= left; + left++; + } else { + int[] arr = new int[right - left]; + for (int i = left; i < right; i++) { + arr[i - left] = i; + } + res.add(arr); + + sum -= left; + left++; + } + } + return res.toArray(new int[res.size()][]); + } + + @Test + public void test() { + System.out.println(JSON.toJSONString(findContinuousSequence(15))); + } } diff --git a/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java index eea074e..0b21f0d 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java @@ -1,9 +1,35 @@ package com.chen.algorithm.znn.array.test11; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/ + * * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 盛最多水的容器 + * @Description: 盛最多水的容器:双指针法 */ public class Solution { + + public int maxArea(int[] height) { + int left = 0, right = height.length - 1; + int res = 0; + + while (left < right) { + int area = Math.min(height[left], height[right]) * (right - left); + res = Math.max(res, area); + if (height[left] <= height[right]) { + left++; + } else { + right--; + } + } + return res; + } + + @Test + public void test() { + int[] height = {1, 8, 6, 2, 5, 4, 8, 3, 7}; + System.out.println(maxArea(height)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java index 394eeee..93b8a5a 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java @@ -1,9 +1,65 @@ package com.chen.algorithm.znn.array.test287; +import org.junit.Test; + +import java.util.Arrays; + /** * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 寻找重复数 + * @Description: 寻找重复数:1-排序迭代;2-快慢指针 + * 将i 指向 nums[i],如果有重复,就会形成环状 */ public class Solution { + + /** + * 1-排序迭代 + * + * @param nums + * @return + */ + public int findDuplicate(int[] nums) { + if (nums == null || nums.length == 0) { + return -1; + } + Arrays.sort(nums); + for (int i = 1; i < nums.length; i++) { + if (nums[i] == nums[i - 1]) { + return nums[i]; + } + } + return -1; + } + + /** + * 2-快慢指针 + * + * @param nums + * @return + */ + public int findDuplicate2(int[] nums) { + if (nums == null || nums.length == 0) { + return -1; + } + + int slow = 0, fast = 0; + do { + slow = nums[slow]; + fast = nums[nums[fast]]; + } while (slow != fast); + + slow = 0; + while (slow != fast) { + slow = nums[slow]; + fast = nums[fast]; + } + return slow; + } + + @Test + public void test() { + int[] nums = {1, 6, 7, 7, 7, 2, 3, 5}; + System.out.println(findDuplicate(nums)); + System.out.println(findDuplicate2(nums)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java new file mode 100644 index 0000000..2026ee3 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java @@ -0,0 +1,32 @@ +package com.chen.algorithm.znn.array.test674; + +import org.junit.Test; + +/** + * https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/solution/zui-chang-lian-xu-di-zeng-xu-lie-by-leetcode/ + * + * @Auther: zhunn + * @Date: 2020/11/08 15:25 + * @Description: 最长连续递增序列:滑动窗口 + */ +public class Solution { + + public int findLengthOfLCIS(int[] nums) { + int res = 0, anchor = 0; + for (int i = 0; i < nums.length; i++) { + if (i > 0 && nums[i - 1] >= nums[i]) { + anchor = i; + } + res = Math.max(res, i - anchor + 1); + } + return res; + } + + @Test + public void test() { + int[] nums = {1, 3, 5, 4, 7}; + int[] nums2 = {2, 2, 2, 2, 2}; + System.out.println(findLengthOfLCIS(nums)); + System.out.println(findLengthOfLCIS(nums2)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/heap/Test.java b/src/main/java/com/chen/algorithm/znn/heap/Test.java index 3e3fcb0..093eff9 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/Test.java +++ b/src/main/java/com/chen/algorithm/znn/heap/Test.java @@ -6,7 +6,8 @@ * @Description: 堆相关 * 1、堆的基本操作 heap/Heap * - * 2、堆化,大根堆,小根堆,堆排序,堆的应用(优先级队列,topK,中位数) + * 2、堆化,大根堆,小根堆,堆排序 + * 3、堆的应用(大根堆-优先级队列,小根堆-topK,中位数) * java的priorityQueue 用小根堆实现的优先级队列 */ public class Test { diff --git a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java index 9ba67d4..eb56510 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java @@ -1,9 +1,57 @@ package com.chen.algorithm.znn.heap.test347; +import org.junit.Test; + +import java.util.*; + /** * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 前 K 个高频元素 + * @Description: 前 K 个高频元素:PriorityQueue-小根堆 */ public class Solution { + + public int[] topKFrequent(int[] nums, int k) { + // 计算频次 + Map map = new HashMap<>(); + for (int num : nums) { + if (map.containsKey(num)) { + map.put(num, map.get(num) + 1); + } else { + map.put(num, 1); + } + } + + //PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(map::get)); + PriorityQueue queue = new PriorityQueue<>(new Comparator() { + @Override + public int compare(Integer o1, Integer o2) { + return map.get(o1) - map.get(o2); + } + }); + + for (Integer key : map.keySet()) { + if (queue.size() < k) { + queue.add(key); + } else if (map.get(queue.peek()) < map.get(key)) { + queue.poll(); + queue.add(key); + } + } + + int[] res = new int[k]; + int i = 0; + while (!queue.isEmpty()) { + res[i] = queue.poll(); + i++; + } + return res; + } + + @Test + public void test() { + int[] nums = {5, 2, 5, 3, 5, 3, 1, 1, 3}; + int[] res = topKFrequent(nums, 2); + System.out.println(Arrays.toString(res)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java index 694c38b..301a38e 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java @@ -1,9 +1,49 @@ package com.chen.algorithm.znn.stack.test496; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + /** + * https://leetcode-cn.com/problems/next-greater-element-i/solution/xia-yi-ge-geng-da-yuan-su-i-by-leetcode/ + * * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 下一个更大元素 + * @Description: 下一个更大元素:单调栈 */ public class Solution { + + public int[] nextGreaterElement(int[] nums1, int[] nums2) { + Map map = new HashMap<>(); + Stack stack = new Stack<>(); + + for (int i = 0; i < nums2.length; i++) { + int num = nums2[i]; + while (!stack.isEmpty() && num > stack.peek()) { + map.put(stack.pop(), num); + } + stack.push(num); + } + + while (!stack.isEmpty()) { + map.put(stack.pop(), -1); + } + + int[] res = new int[nums1.length]; + for (int i = 0; i < nums1.length; i++) { + res[i] = map.get(nums1[i]); + } + return res; + } + + @Test + public void test() { + int[] nums1 = {4, 1, 2}; + int[] nums2 = {1, 3, 4, 2}; + int[] res = nextGreaterElement(nums1, nums2); + System.out.println(Arrays.toString(res)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java deleted file mode 100644 index 80ef45f..0000000 --- a/src/main/java/com/chen/algorithm/znn/stack/test674/Solution.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.chen.algorithm.znn.stack.test674; - -/** - * @Auther: zhunn - * @Date: 2020/11/08 15:25 - * @Description: 最长连续递增序列 - */ -public class Solution { -} diff --git a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java index 7ec7104..d7b20fd 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java @@ -1,9 +1,82 @@ package com.chen.algorithm.znn.tree.test112; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + /** * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 路径总和 + * @Description: 路径总和:1-递归;2-广度优先搜索 */ public class Solution { + + /** + * 1-深度优先搜索 + * + * @param root + * @param sum + * @return + */ + public boolean hasPathSum(TreeNode root, int sum) { + if (root == null) { + return false; + } + if (root.left == null && root.right == null) { + return sum == root.val; + } + return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); + } + + /** + * 2-广度优先搜索 + * + * @param root + * @param sum + * @return + */ + public boolean hasPathSum2(TreeNode root, int sum) { + if (root == null) { + return false; + } + Queue queueNode = new LinkedList<>(); + queueNode.add(root); + Queue queueSum = new LinkedList<>(); + queueSum.add(0); + + while (!queueNode.isEmpty()) { + TreeNode node = queueNode.poll(); + int rec = queueSum.poll() + node.val; + + if (node.left == null && node.right == null) { + if (rec == sum) { + return true; + } + continue; + } + if (node.left != null) { + queueNode.add(node.left); + queueSum.add(rec); + } + if (node.right != null) { + queueNode.add(node.right); + queueSum.add(rec); + } + + } + return false; + } + + @Test + public void test() { + TreeNode left = new TreeNode(1, new TreeNode(3), null); + TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + System.out.println(hasPathSum(root, 7)); + System.out.println(hasPathSum2(root, 7)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java index 85d5b2d..6186b6f 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java @@ -1,13 +1,14 @@ package com.chen.algorithm.znn.tree.test113; import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; import java.util.*; /** * @Auther: zhunn * @Date: 2020/10/28 10:11 - * @Description: 二叉树中和为某一值的路径:1-深度优先搜索;2-广度优先搜索 + * @Description: 路径之和 II,二叉树中和为某一值的路径:1-深度优先搜索;2-广度优先搜索 * 同剑指 Offer 34 */ public class Solution { @@ -72,18 +73,19 @@ public List> pathSum2(TreeNode root, int sum) { if (rec == sum) { getPath(node); } - } else { - if (node.left != null) { - map.put(node.left, node); - queueNode.add(node.left); - queueSum.add(rec); - } - if (node.right != null) { - map.put(node.right, node); - queueNode.add(node.right); - queueSum.add(rec); - } + continue; + } + if (node.left != null) { + map.put(node.left, node); + queueNode.add(node.left); + queueSum.add(rec); + } + if (node.right != null) { + map.put(node.right, node); + queueNode.add(node.right); + queueSum.add(rec); } + } return res2; } @@ -97,4 +99,14 @@ private void getPath(TreeNode node) { Collections.reverse(temp); res2.add(temp); } + + @Test + public void test() { + TreeNode left = new TreeNode(1, new TreeNode(3), null); + TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + List> res = pathSum2(root, 7); + System.out.println(res); + } } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java index 4fefe1d..c8bdd69 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java @@ -1,9 +1,33 @@ package com.chen.algorithm.znn.tree.test437; +import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; + /** * @Auther: zhunn * @Date: 2020/11/08 15:25 * @Description: 路径总和 III */ public class Solution { + + public int pathSum(TreeNode root, int sum) { + if (root == null) return 0; + return find(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum); + } + + private int find(TreeNode root, int sum) { + return (root.val == sum ? 1 : 0) + + (root.left == null ? 0 : find(root.left, sum - root.val)) + + (root.right == null ? 0 : find(root.right, sum - root.val)); + } + + @Test + public void test() { + TreeNode left = new TreeNode(1, new TreeNode(3), null); + TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); + TreeNode root = new TreeNode(3, left, right); + + int res = pathSum(root, 7); + System.out.println(res); + } } From b945035f72a6d2e1e60327f1b6c85e88601fff07 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 9 Nov 2020 18:56:40 +0800 Subject: [PATCH 23/63] sort --- src/main/java/com/chen/algorithm/znn/note | 18 +----------------- .../chen/algorithm/znn/sort/BubbleSort.java | 9 +++++++++ .../chen/algorithm/znn/sort/ChoiceSort.java | 9 +++++++++ .../chen/algorithm/znn/sort/InsertSort.java | 9 +++++++++ .../com/chen/algorithm/znn/sort/MergeSort.java | 9 +++++++++ .../com/chen/algorithm/znn/sort/QuickSort.java | 9 +++++++++ 6 files changed, 46 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java create mode 100644 src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java create mode 100644 src/main/java/com/chen/algorithm/znn/sort/InsertSort.java create mode 100644 src/main/java/com/chen/algorithm/znn/sort/MergeSort.java create mode 100644 src/main/java/com/chen/algorithm/znn/sort/QuickSort.java diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index ad78c02..69b94b5 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -1,20 +1,4 @@ -补充练习: -array: -test11 盛最多水的容器 https://leetcode-cn.com/problems/container-with-most-water -test287 寻找重复数 https://leetcode-cn.com/problems/find-the-duplicate-number -offer.test57 和为s的连续正数序列 (https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/) - -heap: -test347 前 K 个高频元素 https://leetcode-cn.com/problems/top-k-frequent-elements - -tree: -test112 路径总和 https://leetcode-cn.com/problems/path-sum -test437 路径总和 III https://leetcode-cn.com/problems/path-sum-iii - -stack: -test496 下一个更大元素 I https://leetcode-cn.com/problems/next-greater-element-i -test674 最长连续递增序列 https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence - +已实现的有:共223题 剑指offer第2版:共75题 简单:共41题 diff --git a/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java b/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java new file mode 100644 index 0000000..4c9caf0 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.sort; + +/** + * @Auther: zhunn + * @Date: 2020/11/9 18:40 + * @Description: 冒泡排序 + */ +public class BubbleSort { +} diff --git a/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java b/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java new file mode 100644 index 0000000..ba3b056 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.sort; + +/** + * @Auther: zhunn + * @Date: 2020/11/9 18:41 + * @Description: 选择排序 + */ +public class ChoiceSort { +} diff --git a/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java b/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java new file mode 100644 index 0000000..1c6c322 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.sort; + +/** + * @Auther: zhunn + * @Date: 2020/11/9 18:41 + * @Description: 插入排序 + */ +public class InsertSort { +} diff --git a/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java b/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java new file mode 100644 index 0000000..7712fb2 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.sort; + +/** + * @Auther: zhunn + * @Date: 2020/11/9 18:41 + * @Description: 归并排序 + */ +public class MergeSort { +} diff --git a/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java b/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java new file mode 100644 index 0000000..c8bee24 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java @@ -0,0 +1,9 @@ +package com.chen.algorithm.znn.sort; + +/** + * @Auther: zhunn + * @Date: 2020/11/9 18:41 + * @Description: 快速排序 + */ +public class QuickSort { +} From ff0a1470f2326e912c505041ef1576b8aa8affe1 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 10 Nov 2020 18:17:43 +0800 Subject: [PATCH 24/63] sort-1 --- .../algorithm/sort/standrd/QuickSort.java | 8 +- .../chen/algorithm/znn/sort/BubbleSort.java | 35 ++++++++- .../chen/algorithm/znn/sort/ChoiceSort.java | 39 +++++++++- .../com/chen/algorithm/znn/sort/HeapSort.java | 78 +++++++++++++++++++ .../chen/algorithm/znn/sort/InsertSort.java | 29 ++++++- .../chen/algorithm/znn/sort/MergeSort.java | 57 +++++++++++++- .../chen/algorithm/znn/sort/QuickSort.java | 50 +++++++++++- .../com/chen/algorithm/znn/sort/Test.java | 61 +++++++++++++++ 8 files changed, 348 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/chen/algorithm/znn/sort/HeapSort.java diff --git a/src/main/java/com/chen/algorithm/sort/standrd/QuickSort.java b/src/main/java/com/chen/algorithm/sort/standrd/QuickSort.java index 89a81f7..f959948 100644 --- a/src/main/java/com/chen/algorithm/sort/standrd/QuickSort.java +++ b/src/main/java/com/chen/algorithm/sort/standrd/QuickSort.java @@ -2,6 +2,8 @@ import org.junit.Test; +import java.util.Arrays; + /** * 如果要排序数组中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot(分区点)。 * 我们遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到中间。经过这一步骤之后,数组 p 到 r 之间的数据就被分成了三个部分, @@ -17,11 +19,9 @@ public class QuickSort { @Test public void quickSort() { - int[] nums = {3, 7, 2, 10, -1, 4}; + int[] nums = {3, 7, 2, 10, -1, 6}; sort(0, nums.length - 1, nums); - for (int num : nums) { - System.out.println(num); - } + System.out.println(Arrays.toString(nums)); } diff --git a/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java b/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java index 4c9caf0..91e7e5b 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/BubbleSort.java @@ -1,9 +1,42 @@ package com.chen.algorithm.znn.sort; +import org.junit.Test; + +import java.util.Arrays; + /** * @Auther: zhunn * @Date: 2020/11/9 18:40 - * @Description: 冒泡排序 + * @Description: 冒泡排序:O(n^2)稳定 */ public class BubbleSort { + + /** + * 冒泡排序: + * 初始关键字:[36 28 45 13 67 36 18 56] + * 第一趟:13 [36 28 45 18 67 36 56] + * 第二趟:13 18 [36 28 45 36 67 56] + * 第三趟:13 18 28 [36 36 45 56 67] + * 第四趟:13 18 28 36 [36 45 56 67] + */ + public int[] bubbleSort(int[] nums) { + + for (int i = 0; i < nums.length; i++) { + for (int j = nums.length - 1; j > i; j--) { + if (nums[j] < nums[j - 1]) { + int temp = nums[j]; + nums[j] = nums[j - 1]; + nums[j - 1] = temp; + } + } + } + return nums; + } + + @Test + public void test() { + int[] nums = {36, 28, 45, 13, 67, 36, 18, 56}; + int[] res = bubbleSort(nums); + System.out.println(Arrays.toString(res)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java b/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java index ba3b056..561f561 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java @@ -1,9 +1,46 @@ package com.chen.algorithm.znn.sort; +import org.junit.Test; + +import java.util.Arrays; + /** * @Auther: zhunn * @Date: 2020/11/9 18:41 - * @Description: 选择排序 + * @Description: 选择排序:O(n^2) 不稳定 */ public class ChoiceSort { + + /** + * 每一轮选择最小元素交换到未排定部分的开头 + * + * @param nums + * @return + */ + public int[] choiceSort(int[] nums) { + int len = nums.length; + + for (int i = 0; i < len - 1; i++) { // 循环不变量:[0, i) 有序,且该区间里所有元素就是最终排定的样子 + int minIndex = i; // 选择无序区间 [i, len - 1] 里最小的元素的索引,交换到下标 i,即为排序部分的开头 + for (int j = i + 1; j < len; j++) { + if (nums[j] < nums[minIndex]) { + minIndex = j; + } + } + + // 交换 + int temp = nums[i]; + nums[i] = nums[minIndex]; + nums[minIndex] = temp; + } + return nums; + } + + @Test + public void test() { + int[] nums = {36, 28, 45, 13, 67, 36, 18, 56}; + int[] res = choiceSort(nums); + System.out.println(Arrays.toString(res)); + } + } diff --git a/src/main/java/com/chen/algorithm/znn/sort/HeapSort.java b/src/main/java/com/chen/algorithm/znn/sort/HeapSort.java new file mode 100644 index 0000000..23df845 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/sort/HeapSort.java @@ -0,0 +1,78 @@ +package com.chen.algorithm.znn.sort; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * (了解) + * + * @Auther: zhunn + * @Date: 2020/11/10 16:32 + * @Description: 堆排序:O(nlogn) 不稳定 + */ +public class HeapSort { + + public int[] sortArray(int[] nums) { + int len = nums.length; + // 将数组整理成堆 + heapify(nums); + + // 循环不变量:区间 [0, i] 堆有序 + for (int i = len - 1; i >= 1; ) { + // 把堆顶元素(当前最大)交换到数组末尾 + swap(nums, 0, i); + // 逐步减少堆有序的部分 + i--; + // 下标 0 位置下沉操作,使得区间 [0, i] 堆有序 + siftDown(nums, 0, i); + } + return nums; + } + + /** + * 将数组整理成堆(堆有序) + * + * @param nums + */ + private void heapify(int[] nums) { + int len = nums.length; + // 只需要从 i = (len - 1) / 2 这个位置开始逐层下移 + for (int i = (len - 1) / 2; i >= 0; i--) { + siftDown(nums, i, len - 1); + } + } + + /** + * @param nums + * @param k 当前下沉元素的下标 + * @param end [0, end] 是 nums 的有效部分 + */ + private void siftDown(int[] nums, int k, int end) { + while (2 * k + 1 <= end) { + int j = 2 * k + 1; + if (j + 1 <= end && nums[j + 1] > nums[j]) { + j++; + } + if (nums[j] > nums[k]) { + swap(nums, j, k); + } else { + break; + } + k = j; + } + } + + private void swap(int[] nums, int index1, int index2) { + int temp = nums[index1]; + nums[index1] = nums[index2]; + nums[index2] = temp; + } + + @Test + public void test() { + int[] nums = {6, 8, 2, 1, 2, 7}; + int[] res = sortArray(nums); + System.out.println(Arrays.toString(res)); + } +} diff --git a/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java b/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java index 1c6c322..3943d43 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/InsertSort.java @@ -1,9 +1,36 @@ package com.chen.algorithm.znn.sort; +import org.junit.Test; + +import java.util.Arrays; + /** * @Auther: zhunn * @Date: 2020/11/9 18:41 - * @Description: 插入排序 + * @Description: 插入排序:O(n^2) 稳定 + * 稳定排序,在接近有序的情况下,表现优异 */ public class InsertSort { + + public int[] insertSort(int[] nums) { + int len = nums.length; + for (int i = 1; i < len; i++) { // 循环不变量:将 nums[i] 插入到区间 [0, i) 使之成为有序数组 + int temp = nums[i]; // 先暂存这个元素,然后之前元素逐个后移,留出空位 + int left = i - 1; + // 注意边界 left >= 0 + while (left >= 0 && nums[left] > temp) { + nums[left + 1] = nums[left]; + left--; + } + nums[left + 1] = temp; + } + return nums; + } + + @Test + public void test() { + int[] nums = {6, 8, 2, 1, 2, 7}; + int[] res = insertSort(nums); + System.out.println(Arrays.toString(res)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java b/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java index 7712fb2..a38e5d8 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/MergeSort.java @@ -1,9 +1,64 @@ package com.chen.algorithm.znn.sort; +import org.junit.Test; + +import java.util.Arrays; + /** * @Auther: zhunn * @Date: 2020/11/9 18:41 - * @Description: 归并排序 + * @Description: 归并排序:O(nlogn) 稳定,非原地排序 */ public class MergeSort { + + public int[] sortArray(int[] nums) { + int len = nums.length; + mergeSort(nums, 0, len - 1); + return nums; + } + + private void mergeSort(int[] nums, int low, int hight) { + if (low >= hight) { + return; + } + int mid = low + (hight - low) / 2; + mergeSort(nums, low, mid); + mergeSort(nums, mid + 1, hight); + merge(nums, low, mid, hight); + } + + public void merge(int[] nums, int low, int mid, int hight) { + int i = low; + int j = mid + 1; + int k = 0; + + int[] temp = new int[hight - low + 1]; + + while (i <= mid && j <= hight) { + if (nums[i] <= nums[j]) { + temp[k++] = nums[i++]; + } else { + temp[k++] = nums[j++]; + } + } + + while (i <= mid) { + temp[k++] = nums[i++]; + } + while (j <= hight) { + temp[k++] = nums[j++]; + } + + for (int m = 0; m < temp.length; m++) { + nums[low + m] = temp[m]; + } + } + + @Test + public void test() { + int[] nums = {6, 8, 2, 1, 2, 7}; + int[] res = sortArray(nums); + System.out.println(Arrays.toString(res)); + } + } diff --git a/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java b/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java index c8bee24..4dc493e 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java @@ -1,9 +1,57 @@ package com.chen.algorithm.znn.sort; +import org.junit.Test; + +import java.util.Arrays; + /** + * 重点 + * * @Auther: zhunn * @Date: 2020/11/9 18:41 - * @Description: 快速排序 + * @Description: 快速排序:O(nlogn) 不稳定 */ public class QuickSort { + + public int[] sortArray(int[] nums) { + if (nums == null || nums.length < 2) { + return nums; + } + quickSort(nums, 0, nums.length - 1); + return nums; + } + + private void quickSort(int[] nums, int low, int hight) { + if (low >= hight) { + return; + } + // 枢轴(基准值) + int pivot = partition(nums, low, hight); + quickSort(nums, low, pivot - 1); + quickSort(nums, pivot + 1, hight); + } + + private int partition(int[] nums, int low, int hight) { + int pivotValue = nums[low]; + while (low < hight) { + while (low < hight && pivotValue <= nums[hight]) { + hight--; + } + nums[low] = nums[hight]; + while (low < hight && nums[low] <= pivotValue) { + low++; + } + nums[hight] = nums[low]; + } + nums[low] = pivotValue; + return low; + } + + @Test + public void test() { + int[] nums = {3, 7, 2, 7, 10, -1, 6}; + int[] res = sortArray(nums); + System.out.println(Arrays.toString(res)); + } + } diff --git a/src/main/java/com/chen/algorithm/znn/sort/Test.java b/src/main/java/com/chen/algorithm/znn/sort/Test.java index b2e8e63..fbdab5e 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/Test.java +++ b/src/main/java/com/chen/algorithm/znn/sort/Test.java @@ -6,4 +6,65 @@ * @Description: 排序相关 */ public class Test { + + /** + * 冒泡排序 sort/BubbleSort (n2 稳定) *** (了解) + * 快速排序 sort/QuickSort (nlogn 不稳定)**(重点) + * 归并排序 sort/MergeSort (nlogn 稳定,非原地排序)(重点) + * 选择排序 sort/ChoiceSort (n2 稳定) *** (了解) + * 插入排序 sort/InsertSort (n2 不稳定) ***(熟悉) + * + * 堆排序 (根据需要熟悉) + */ + + /* + 一、内部排序: + 1、插入排序:1)直接插入排序 + 2)折半插入排序 + 3)希尔排序 + 2、交换排序:1)冒泡排序 + 2)快速排序 + 3、选择排序:1)简单选择排序 + 2)堆排序 + 4、归并排序 + 5、基数排序 + 二、外部排序:多路归并排序 + */ + + /** + * https://leetcode-cn.com/problems/sort-an-array/solution/fu-xi-ji-chu-pai-xu-suan-fa-java-by-liweiwei1419/ + * 十大经典排序算法:https://www.cnblogs.com/onepixel/articles/7674659.html + * https://www.cnblogs.com/mcgrady/category/396002.html + * 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 + * 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序 + */ + + /** + * 排序分为以下四类共七种排序方法: + * 交换排序: + * 1) 冒泡排序 + * 2) 快速排序 + * 选择排序: + * 3) 直接选择排序 + * 4) 堆排序 + * 插入排序: + * 5) 直接插入排序 + * 6) 希尔排序 + * 合并排序: + * 7) 归并排序 + * + * 每个排序方法的时间复杂度详细请看链接:https://www.cnblogs.com/onepixel/articles/7674659.html + * + * 排序方法 时间复杂度(平均) 时间复杂度(最坏) 时间复杂度(最好) 空间复杂度 稳定性 复杂性 备注 + * 直接插入排序 O(n2) O(n2) O(n) O(1) 稳定 简单 大部分已排序时较好 + * 希尔排序 O(nlog2n) O(n2) O(n) O(1) 不稳定 较复杂 + * 直接选择排序 O(n2) O(n2) O(n2) O(1) 不稳定 简单 n小时较好 + * 堆排序 O(nlog2n) O(nlog2n) O(nlog2n) O(1) 不稳定 较复杂 n大时较好 + * 冒泡排序 O(n2) O(n2) O(n) O(1) 稳定 简单 n小时较好 + * 快速排序 O(nlog2n) O(n2) O(nlog2n) O(nlog2n) 不稳定 较复杂 n大时较好 + * 归并排序 O(nlog2n) O(nlog2n) O(nlog2n) O(n) 稳定 较复杂 n大时较好 + * 基数排序 O(n*k) O(n*k) O(n*k) O(n+k) 稳定 较复杂 + * 计数排序 O(n+k) O(n+k) O(n+k) O(n+k) 稳定 + * 桶排序 O(n+k) O(n2) O(n) O(n+k) 稳定 + */ } From 704cfae976700079ee950eae096cffca08fe7d72 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 10 Nov 2020 20:50:19 +0800 Subject: [PATCH 25/63] tips --- .../znn/array/offer/test29/Solution.java | 9 +++++ .../znn/array/offer/test57/Solution.java | 9 +++++ .../algorithm/znn/array/test1/Solution.java | 8 +++++ .../algorithm/znn/array/test11/Solution.java | 16 +++++++++ .../algorithm/znn/array/test238/Solution.java | 8 +++++ .../algorithm/znn/array/test240/Solution.java | 17 ++++++++- .../algorithm/znn/array/test26/Solution.java | 12 +++++++ .../algorithm/znn/array/test27/Solution.java | 14 ++++++++ .../algorithm/znn/array/test283/Solution.java | 7 +++- .../algorithm/znn/array/test287/Solution.java | 9 +++++ .../algorithm/znn/array/test34/Solution.java | 11 ++++++ .../algorithm/znn/array/test448/Solution.java | 9 +++++ .../algorithm/znn/array/test56/Solution.java | 12 ++++++- .../algorithm/znn/array/test581/Solution.java | 10 ++++-- .../algorithm/znn/array/test674/Solution.java | 12 +++++++ .../algorithm/znn/array/test69/Solution.java | 12 +++++++ .../algorithm/znn/array/test704/Solution.java | 11 ++++++ .../algorithm/znn/array/test88/Solution.java | 14 ++++++-- .../znn/backtrack/test36/Solution.java | 35 +++++++++++++++++++ .../znn/backtrack/test39/Solution.java | 21 +++++++++++ .../znn/backtrack/test40/Solution.java | 26 +++++++++++++- .../znn/backtrack/test46/Solution.java | 23 ++++++------ .../znn/backtrack/test47/Solution.java | 12 +++++++ .../znn/backtrack/test51/Solution.java | 18 ++++++++++ .../znn/backtrack/test78/Solution.java | 16 +++++++++ .../znn/backtrack/test79/Solution.java | 14 ++++++++ .../znn/backtrack/test90/Solution.java | 15 ++++++++ .../znn/bitmap/test136/Solution.java | 11 ++++++ .../znn/bitmap/test191/Solution.java | 14 ++++++++ .../znn/bitmap/test231/Solution.java | 13 +++++++ .../znn/bitmap/test338/Solution.java | 8 +++++ .../znn/bitmap/test461/Solution.java | 13 +++++++ .../algorithm/znn/dfs/test22/Solution.java | 14 +++++++- .../znn/divide/test169/Solution.java | 10 ++++++ .../algorithm/znn/divide/test50/Solution.java | 13 +++++++ .../znn/dynamic/test120/Solution.java | 11 ++++++ .../znn/dynamic/test121/Solution.java | 14 ++++++++ .../znn/dynamic/test123/Solution.java | 19 ++++++++++ .../znn/dynamic/test152/Solution.java | 10 ++++++ .../znn/dynamic/test188/Solution.java | 14 ++++++++ .../znn/dynamic/test198/Solution.java | 12 +++++++ .../znn/dynamic/test213/Solution.java | 16 +++++++++ .../znn/dynamic/test279/Solution.java | 11 ++++++ .../znn/dynamic/test300/Solution.java | 6 ++++ .../znn/dynamic/test309/Solution.java | 9 +++++ .../znn/dynamic/test322/Solution.java | 19 ++++++++++ .../znn/dynamic/test337/Solution.java | 21 +++++++++++ .../znn/dynamic/test343/Solution.java | 10 ++++++ .../znn/dynamic/test416/Solution.java | 12 +++++++ .../znn/dynamic/test474/Solution.java | 13 +++++++ .../znn/dynamic/test494/Solution.java | 13 +++++++ .../znn/dynamic/test518/Solution.java | 17 +++++++++ .../znn/dynamic/test53/Solution.java | 7 ++++ .../znn/dynamic/test62/Solution.java | 16 +++++++++ .../znn/dynamic/test64/Solution.java | 10 ++++++ .../znn/dynamic/test70/Solution.java | 18 ++++++++++ .../znn/dynamic/test714/Solution.java | 15 ++++++++ .../znn/dynamic/test72/Solution.java | 22 ++++++++++++ .../znn/frequency/test146/LRUCache.java | 24 +++++++++++++ .../algorithm/znn/frequency/test208/Trie.java | 10 ++++++ .../znn/frequency/test48/Solution.java | 34 ++++++++++++++++++ .../znn/frequency/test7/Solution.java | 12 +++++++ .../znn/frequency/test9/Solution.java | 14 ++++++++ .../znn/greedy/test122/Solution.java | 25 +++++++------ .../algorithm/znn/greedy/test55/Solution.java | 15 ++++++++ .../algorithm/znn/hash/test15/Solution.java | 11 ++++++ .../algorithm/znn/hash/test18/Solution.java | 14 ++++++++ .../algorithm/znn/hash/test242/Solution.java | 9 +++++ .../algorithm/znn/hash/test49/Solution.java | 11 ++++++ .../algorithm/znn/heap/test215/Solution.java | 9 +++++ .../algorithm/znn/heap/test347/Solution.java | 9 +++++ .../znn/linkedlist/test141/Solution.java | 22 ++++++++++++ .../znn/linkedlist/test142/Solution.java | 21 +++++++++++ .../znn/linkedlist/test160/Solution.java | 18 ++++++++++ .../znn/linkedlist/test19/Solution.java | 6 ++++ .../znn/linkedlist/test2/Solution.java | 11 +++++- .../znn/linkedlist/test206/Solution.java | 10 ++++-- .../znn/linkedlist/test21/Solution.java | 10 ++++-- .../znn/linkedlist/test24/Solution.java | 16 +++++++++ .../znn/linkedlist/test25/Solution.java | 18 ++++++++-- .../znn/linkedlist/test83/Solution.java | 9 +++++ .../znn/linkedlist/test92/Solution.java | 22 ++++++++---- .../znn/recursion/test172/Solution.java | 11 ++++++ .../algorithm/znn/stack/test155/Solution.java | 22 ++++++++++++ .../algorithm/znn/stack/test20/Solution.java | 22 ++++++++++++ .../algorithm/znn/stack/test225/MyStack.java | 11 ++++++ .../algorithm/znn/stack/test227/Solution.java | 13 +++++++ .../algorithm/znn/stack/test232/Solution.java | 26 ++++++++++++++ .../algorithm/znn/stack/test239/Solution.java | 18 ++++++++++ .../algorithm/znn/stack/test496/Solution.java | 16 +++++++++ .../algorithm/znn/stack/test703/Solution.java | 19 ++++++++++ .../algorithm/znn/string/test14/Solution.java | 11 ++++++ .../algorithm/znn/string/test3/Solution.java | 16 +++++++++ .../znn/string/test415/Solution.java | 3 ++ .../algorithm/znn/string/test5/Solution.java | 10 ++++++ .../algorithm/znn/tree/test101/Solution.java | 15 ++++++++ .../algorithm/znn/tree/test102/Solution.java | 16 +++++++++ .../algorithm/znn/tree/test103/Solution.java | 15 ++++++++ .../algorithm/znn/tree/test104/Solution.java | 13 +++++++ .../algorithm/znn/tree/test107/Solution.java | 16 +++++++++ .../algorithm/znn/tree/test111/Solution.java | 12 +++++++ .../algorithm/znn/tree/test112/Solution.java | 15 ++++++++ .../algorithm/znn/tree/test113/Solution.java | 19 ++++++++++ .../algorithm/znn/tree/test144/Solution.java | 3 ++ .../algorithm/znn/tree/test145/Solution.java | 4 +++ .../algorithm/znn/tree/test199/Solution.java | 12 +++++++ .../algorithm/znn/tree/test226/Solution.java | 15 ++++++++ .../algorithm/znn/tree/test235/Solution.java | 15 +++++++- .../algorithm/znn/tree/test236/Solution.java | 13 +++++++ .../algorithm/znn/tree/test437/Solution.java | 19 ++++++++++ .../algorithm/znn/tree/test538/Solution.java | 20 +++++++++++ .../algorithm/znn/tree/test543/Solution.java | 12 +++++++ .../algorithm/znn/tree/test617/Solution.java | 20 +++++++++++ .../algorithm/znn/tree/test94/Solution.java | 3 ++ .../algorithm/znn/tree/test96/Solution.java | 14 ++++++++ .../algorithm/znn/tree/test98/Solution.java | 23 ++++++++++++ 116 files changed, 1600 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java index 6cc9963..0574b23 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java @@ -3,6 +3,15 @@ import java.util.Arrays; /** + * 剑指 Offer 29. 顺时针打印矩阵: + * 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 + * 示例 1: + * 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] + * 输出:[1,2,3,6,9,8,7,4,5] + * 示例 2: + * 输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]] + * 输出:[1,2,3,4,8,12,11,10,9,5,6,7] + * * @Auther: zhunn * @Date: 2020/10/10 13:58 * @Description: 顺时针从外往里打印矩阵(螺旋矩阵,力扣第54题) diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java index 40cd28b..9d6e985 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java @@ -8,6 +8,15 @@ /** * https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/solution/shi-yao-shi-hua-dong-chuang-kou-yi-ji-ru-he-yong-h/ + * 剑指 Offer 57 - II. 和为s的连续正数序列: + * 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。 + * 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。 + * 示例 1: + * 输入:target = 9 + * 输出:[[2,3,4],[4,5]] + * 示例 2: + * 输入:target = 15 + * 输出:[[1,2,3,4,5],[4,5,6],[7,8]] * * @Auther: zhunn * @Date: 2020/11/08 15:25 diff --git a/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java index 181ae76..acfc854 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java @@ -7,6 +7,14 @@ import java.util.Map; /** + * 1. 两数之和 + * 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 + * 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 + * 示例: + * 给定 nums = [2, 7, 11, 15], target = 9 + * 因为 nums[0] + nums[1] = 2 + 7 = 9 + * 所以返回 [0, 1] + * * @Auther: zhunn * @Date: 2020/10/22 19:00 * @Description: 两数之和 diff --git a/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java index 0b21f0d..bb659fe 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test11/Solution.java @@ -4,6 +4,22 @@ /** * https://leetcode-cn.com/problems/container-with-most-water/solution/sheng-zui-duo-shui-de-rong-qi-by-leetcode-solution/ + * 11. 盛最多水的容器 + * 给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 + * 说明:你不能倾斜容器。 + * 示例 1: + * 输入:[1,8,6,2,5,4,8,3,7] + * 输出:49 + * 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。 + * 示例 2: + * 输入:height = [1,1] + * 输出:1 + * 示例 3: + * 输入:height = [4,3,2,1,4] + * 输出:16 + * 示例 4: + * 输入:height = [1,2,1] + * 输出:2 * * @Auther: zhunn * @Date: 2020/11/08 15:25 diff --git a/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java index 7776136..0f56b46 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test238/Solution.java @@ -3,6 +3,14 @@ import com.alibaba.fastjson.JSON; /** + * 238. 除自身以外数组的乘积 + * 给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。 + * 示例: + * 输入: [1,2,3,4] + * 输出: [24,12,8,6] + * 提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。 + * 说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。 + * * @Auther: zhunn * @Date: 2020/10/16 14:30 * @Description: 除自身以外数组的乘积 diff --git a/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java index 01ff129..13ae883 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java @@ -2,10 +2,25 @@ /** * https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/er-fen-fa-pai-chu-fa-python-dai-ma-java-dai-ma-by-/ + * 240. 搜索二维矩阵 II + * 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性: + * 每行的元素从左到右升序排列。 + * 每列的元素从上到下升序排列。 + * 示例: + * 现有矩阵 matrix 如下: + * [ + * [1, 4, 7, 11, 15], + * [2, 5, 8, 12, 19], + * [3, 6, 9, 16, 22], + * [10, 13, 14, 17, 24], + * [18, 21, 23, 26, 30] + * ] + * 给定 target = 5,返回 true。 + * 给定 target = 20,返回 false。 * * @Author: zhunn * @Date: 2020-10-22 14:26 - * @Description: 搜索二维矩阵 + * @Description: 搜索二维矩阵 II */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java index 336627f..1045a5a 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java @@ -3,6 +3,18 @@ import org.junit.Test; /** + * 26. 删除排序数组中的重复项 + * 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。 + * 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。 + * 示例 1: + * 给定数组 nums = [1,1,2], + * 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 + * 你不需要考虑数组中超出新长度后面的元素。 + * 示例 2: + * 给定 nums = [0,0,1,1,1,2,2,3,3,4], + * 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。 + * 你不需要考虑数组中超出新长度后面的元素。 + * * @Auther: zhunn * @Date: 2020/10/10 16:23 * @Description: 删除排序数组中的重复项,返回新数组长度。双指针法 diff --git a/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java index e06ce69..8625f95 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test27/Solution.java @@ -5,6 +5,20 @@ import java.util.Arrays; /** + * 27. 移除元素 + * 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 + * 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 + * 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。 + * 示例 1: + * 给定 nums = [3,2,2,3], val = 3, + * 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 + * 你不需要考虑数组中超出新长度后面的元素。 + * 示例 2: + * 给定 nums = [0,1,2,2,3,0,4,2], val = 2, + * 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。 + * 注意这五个元素可为任意顺序。 + * 你不需要考虑数组中超出新长度后面的元素。 + * * @Auther: zhunn * @Date: 2020/10/10 16:40 * @Description: 移除元素,双指针法 diff --git a/src/main/java/com/chen/algorithm/znn/array/test283/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test283/Solution.java index a901e0d..6296c38 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test283/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test283/Solution.java @@ -5,7 +5,12 @@ import java.util.Arrays; /** - * 移动0 + * 283. 移动零 + * 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 + * 示例: + * 输入: [0,1,0,3,12] + * 输出: [1,3,12,0,0] + * * @author: zhunn * @Date: 2019-11-03 18:44 * @Description: 移动0至末尾 diff --git a/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java index 93b8a5a..ee21fdd 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test287/Solution.java @@ -5,6 +5,15 @@ import java.util.Arrays; /** + * 287. 寻找重复数 + * 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 + * 示例 1: + * 输入: [1,3,4,2,2] + * 输出: 2 + * 示例 2: + * 输入: [3,1,3,4,2] + * 输出: 3 + * * @Auther: zhunn * @Date: 2020/11/08 15:25 * @Description: 寻找重复数:1-排序迭代;2-快慢指针 diff --git a/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java index db762a5..56076e3 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test34/Solution.java @@ -5,6 +5,17 @@ import java.util.Arrays; /** + * 34. 在排序数组中查找元素的第一个和最后一个位置 + * 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 + * 你的算法时间复杂度必须是 O(log n) 级别。 + * 如果数组中不存在目标值,返回 [-1, -1]。 + * 示例 1: + * 输入: nums = [5,7,7,8,8,10], target = 8 + * 输出: [3,4] + * 示例 2: + * 输入: nums = [5,7,7,8,8,10], target = 6 + * 输出: [-1,-1] + * * @Auther: zhunn * @Date: 2020/10/10 17:04 * @Description: 在排序数组中查找元素的第一个和最后一个位置 diff --git a/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java index 5d541ad..ccd2825 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java @@ -7,6 +7,15 @@ /** * https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/solution/e-wai-liang-ge-intkong-jian-shi-jian-fu-za-du-jin-/ + * 448. 找到所有数组中消失的数字 + * 给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。 + * 找到所有在 [1, n] 范围之间没有出现在数组中的数字。 + * 您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。 + * 示例: + * 输入: + * [4,3,2,7,8,2,3,1] + * 输出: + * [5,6] * * @author: zhunn * @Date: 2020-10-04 00:06 diff --git a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java index 0dfd005..88ff8a5 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java @@ -9,6 +9,16 @@ /** * https://leetcode-cn.com/problems/merge-intervals/solution/pai-xu-by-powcai/ + * 56. 合并区间 + * 给出一个区间的集合,请合并所有重叠的区间。 + * 示例 1: + * 输入: intervals = [[1,3],[2,6],[8,10],[15,18]] + * 输出: [[1,6],[8,10],[15,18]] + * 解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]. + * 示例 2: + * 输入: intervals = [[1,4],[4,5]] + * 输出: [[1,5]] + * 解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。 * * @author: zhunn * @Date: 2020-10-14 00:22 @@ -34,7 +44,7 @@ public int[][] merge(int[][] intervals) { List inner = Arrays.asList(intervals); List newInner = new ArrayList<>(inner); - newInner.sort((o1,o2)-> o1[0]-o2[0]); + newInner.sort((o1, o2) -> o1[0] - o2[0]); List res = new ArrayList<>(); diff --git a/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java index 39428c0..ac5bd0b 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java @@ -5,8 +5,14 @@ import java.util.Arrays; /** - * * https://leetcode-cn.com/problems/shortest-unsorted-continuous-subarray/solution/zui-duan-wu-xu-lian-xu-zi-shu-zu-by-leetcode/ + * 581. 最短无序连续子数组 + * 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 + * 你找到的子数组应是最短的,请输出它的长度。 + * 示例 1: + * 输入: [2, 6, 4, 8, 10, 9, 15] + * 输出: 5 + * 解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 * * @author: zhunn * @Date: 2020-10-07 23:34 @@ -16,7 +22,7 @@ public class Solution { public int findUnsortedSubarray(int[] nums) { - if(nums == null || nums.length == 0){ + if (nums == null || nums.length == 0) { return 0; } diff --git a/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java index 2026ee3..b014ef3 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java @@ -4,6 +4,18 @@ /** * https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/solution/zui-chang-lian-xu-di-zeng-xu-lie-by-leetcode/ + * 674. 最长连续递增序列 + * 给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。 + * 连续递增的子序列 可以由两个下标 l 和 r(l < r)确定,如果对于每个 l <= i < r,都有 nums[i] < nums[i + 1] ,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] 就是连续递增子序列。 + * 示例 1: + * 输入:nums = [1,3,5,4,7] + * 输出:3 + * 解释:最长连续递增序列是 [1,3,5], 长度为3。 + * 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。 + * 示例 2: + * 输入:nums = [2,2,2,2,2] + * 输出:1 + * 解释:最长连续递增序列是 [2], 长度为1。 * * @Auther: zhunn * @Date: 2020/11/08 15:25 diff --git a/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java index 964bf1c..3961ff1 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test69/Solution.java @@ -3,6 +3,18 @@ import org.junit.Test; /** + * 69. x 的平方根 + * 实现 int sqrt(int x) 函数。 + * 计算并返回 x 的平方根,其中 x 是非负整数。 + * 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。 + * 示例 1: + * 输入: 4 + * 输出: 2 + * 示例 2: + * 输入: 8 + * 输出: 2 + * 说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。 + * * @author: zhunn * @Date: 2020-10-03 09:39 * @Description: x的平方根,舍弃小数 diff --git a/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java index 3aa10a5..8197937 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java @@ -1,6 +1,17 @@ package com.chen.algorithm.znn.array.test704; /** + * 704. 二分查找 + * 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 + * 示例 1: + * 输入: nums = [-1,0,3,5,9,12], target = 9 + * 输出: 4 + * 解释: 9 出现在 nums 中并且下标为 4 + * 示例 2: + * 输入: nums = [-1,0,3,5,9,12], target = 2 + * 输出: -1 + * 解释: 2 不存在 nums 中因此返回 -1 + * * @Auther: zhunn * @Date: 2020/10/9 15:31 * @Description: 二分查找及其变种 https://blog.csdn.net/Lngxling/article/details/78217619 diff --git a/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java index d5de67f..ae7229e 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test88/Solution.java @@ -6,6 +6,16 @@ /** * https://leetcode-cn.com/problems/merge-sorted-array/solution/leetcode88-he-bing-liang-ge-you-xu-shu-zu-by-ma-xi/ + * 88. 合并两个有序数组 + * 给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。 + * 说明: + * 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。 + * 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。 + * 示例: + * 输入: + * nums1 = [1,2,3,0,0,0], m = 3 + * nums2 = [2,5,6], n = 3 + * 输出:[1,2,2,3,5,6] * * @author: zhunn * @Date: 2020-10-20 11:33 @@ -31,8 +41,8 @@ public void testCase() { //int[] m = {1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0}; //int[] n = {0, 2, 5, 6, 8, 9, 25}; //merge(m, 4, n, n.length); - int[] m = {1,2,3,0,0,0}; - int[] n = {2,5,6}; + int[] m = {1, 2, 3, 0, 0, 0}; + int[] n = {2, 5, 6}; merge(m, 3, n, n.length); System.out.println(Arrays.toString(m)); } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java index bc4b3ba..9e98f96 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java @@ -6,6 +6,41 @@ /** * https://leetcode-cn.com/problems/valid-sudoku/solution/javawei-yun-suan-1ms-100-li-jie-fang-ge-suo-yin-by/ + * 36. 有效的数独 + * 判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。 + * 数字 1-9 在每一行只能出现一次。 + * 数字 1-9 在每一列只能出现一次。 + * 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。 + * 示例 1: + * 输入: + * [ + * ["5","3",".",".","7",".",".",".","."], + * ["6",".",".","1","9","5",".",".","."], + * [".","9","8",".",".",".",".","6","."], + * ["8",".",".",".","6",".",".",".","3"], + * ["4",".",".","8",".","3",".",".","1"], + * ["7",".",".",".","2",".",".",".","6"], + * [".","6",".",".",".",".","2","8","."], + * [".",".",".","4","1","9",".",".","5"], + * [".",".",".",".","8",".",".","7","9"] + * ] + * 输出: true + * 示例 2: + * 输入: + * [ + * ["8","3",".",".","7",".",".",".","."], + * ["6",".",".","1","9","5",".",".","."], + * [".","9","8",".",".",".",".","6","."], + * ["8",".",".",".","6",".",".",".","3"], + * ["4",".",".","8",".","3",".",".","1"], + * ["7",".",".",".","2",".",".",".","6"], + * [".","6",".",".",".",".","2","8","."], + * [".",".",".","4","1","9",".",".","5"], + * [".",".",".",".","8",".",".","7","9"] + * ] + * 输出: false + * 解释: 除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 + * 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。 * * @Auther: zhunn * @Date: 2020/11/3 13:54 diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java index db4dbdc..b2da0fb 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java @@ -9,6 +9,27 @@ /** * https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/ + * 39. 组合总和 + * 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 + * candidates 中的数字可以无限制重复被选取。 + * 说明: + * 所有数字(包括 target)都是正整数。 + * 解集不能包含重复的组合。 + * 示例 1: + * 输入:candidates = [2,3,6,7], target = 7, + * 所求解集为: + * [ + * [7], + * [2,2,3] + * ] + * 示例 2: + * 输入:candidates = [2,3,5], target = 8, + * 所求解集为: + * [ + * [2,2,2,2], + * [2,3,3], + * [3,5] + * ] * * @Auther: zhunn * @Date: 2020/11/3 15:27 diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java index 80782f4..e075d89 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test40/Solution.java @@ -9,6 +9,30 @@ /** * https://leetcode-cn.com/problems/combination-sum-ii/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-3/ + * 40. 组合总和 II + * 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 + * candidates 中的每个数字在每个组合中只能使用一次。 + * 说明: + * 所有数字(包括目标数)都是正整数。 + * 解集不能包含重复的组合。 + * 示例 1: + * 输入: candidates = [10,1,2,7,6,1,5], target = 8, + * 所求解集为: + * [ + * [1, 7], + * [1, 2, 5], + * [2, 6], + * [1, 1, 6] + * ] + * 示例 2: + *

+ * 输入: candidates = [2,5,2,1,2], target = 5, + * 所求解集为: + * [ + * [1,2,2], + * [5] + * ] + * * @Auther: zhunn * @Date: 2020/11/3 15:28 * @Description: 组合总和 II @@ -27,7 +51,7 @@ public List> combinationSum2(int[] nums, int target) { } private void backtrack(int start, int target, int[] nums, List curList, List> res) { - // 由于进入更深层的时候,小于0的部分被剪枝,因此递归终止条件值只判断等于0的情况 + // 由于进入更深层的时候,小于0的部分被剪枝,因此递归终止条件值只判断等于0的情况 //if (target < 0) { // return; //} diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java index 47dafba..ebecb1a 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test46/Solution.java @@ -8,16 +8,19 @@ /** * https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/ - * 回溯算法的框架: - * result = [] - * def backtrack(路径, 选择列表): - * if 满足结束条件: - * result.add(路径) - * return - * for 选择 in 选择列表: - * 做选择 - * backtrack(路径, 选择列表) - * 撤销选择 + * 46. 全排列 + * 给定一个 没有重复 数字的序列,返回其所有可能的全排列。 + * 示例: + * 输入: [1,2,3] + * 输出: + * [ + * [1,2,3], + * [1,3,2], + * [2,1,3], + * [2,3,1], + * [3,1,2], + * [3,2,1] + * ] * * @Auther: zhunn * @Date: 2020/11/3 17:52 diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java index c3a7b79..a872b55 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java @@ -6,6 +6,18 @@ import java.util.*; /** + * 47. 全排列 II + * 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 + * 示例 1: + * 输入:nums = [1,1,2] + * 输出: + * [[1,1,2], + * [1,2,1], + * [2,1,1]] + * 示例 2: + * 输入:nums = [1,2,3] + * 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] + * * @Auther: zhunn * @Date: 2020/11/3 19:39 * @Description: 全排列 II diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java index 79ba277..8f39ebc 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test51/Solution.java @@ -9,6 +9,24 @@ /** * https://leetcode-cn.com/problems/n-queens/solution/gen-ju-di-46-ti-quan-pai-lie-de-hui-su-suan-fa-si-/ + * 51. N 皇后 + * n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。 + * 给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。 + * 每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。 + * 示例: + * 输入:4 + * 输出:[ + * [".Q..", // 解法 1 + * "...Q", + * "Q...", + * "..Q."], + *

+ * ["..Q.", // 解法 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + * 解释: 4 皇后问题存在两个不同的解法。 * * @Auther: zhunn * @Date: 2020/11/02 21:23 diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java index d848be9..93c9202 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java @@ -7,6 +7,22 @@ /** * https://leetcode-cn.com/problems/subsets/solution/hui-su-suan-fa-by-powcai-5/ + * 78. 子集 + * 给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + * 说明:解集不能包含重复的子集。 + * 示例: + * 输入: nums = [1,2,3] + * 输出: + * [ + * [3], + * [1], + * [2], + * [1,2,3], + * [1,3], + * [2,3], + * [1,2], + * [] + * ] * * @Auther: zhunn * @Date: 2020/11/3 19:23 diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java index cc61cb8..98eb479 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test79/Solution.java @@ -4,6 +4,20 @@ /** * https://leetcode-cn.com/problems/word-search/solution/zai-er-wei-ping-mian-shang-shi-yong-hui-su-fa-pyth/ + * 79. 单词搜索 + * 给定一个二维网格和一个单词,找出该单词是否存在于网格中。 + * 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。 + * 示例: + * board = + * [ + * ['A','B','C','E'], + * ['S','F','C','S'], + * ['A','D','E','E'] + * ] + * 给定 word = "ABCCED", 返回 true + * 给定 word = "SEE", 返回 true + * 给定 word = "ABCB", 返回 false + * * @Auther: zhunn * @Date: 2020/11/3 18:31 * @Description: 单词搜索 diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java index 925410b..ee91024 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java @@ -8,6 +8,21 @@ /** * https://leetcode-cn.com/problems/subsets/solution/hui-su-suan-fa-by-powcai-5/ + * 90. 子集 II + * 给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。 + * 说明:解集不能包含重复的子集。 + * 示例: + * 输入: [1,2,2] + * 输出: + * [ + * [2], + * [1], + * [1,2,2], + * [2,2], + * [1,2], + * [] + * ] + * * @Auther: zhunn * @Date: 2020/11/3 19:41 * @Description: 子集 II diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java index 97377ab..c766b5e 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test136/Solution.java @@ -4,6 +4,16 @@ /** * https://leetcode-cn.com/problems/single-number/solution/zhi-chu-xian-yi-ci-de-shu-zi-by-leetcode-solution/ + * 136. 只出现一次的数字 + * 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 + * 说明: + * 你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? + * 示例 1: + * 输入: [2,2,1] + * 输出: 1 + * 示例 2: + * 输入: [4,1,2,1,2] + * 输出: 4 * * @Auther: zhunn * @Date: 2020/11/07 17:23 @@ -16,6 +26,7 @@ public class Solution { /** * 2-位运算 + * * @param nums * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java index b188add..b71d5e9 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test191/Solution.java @@ -4,6 +4,20 @@ /** * https://leetcode-cn.com/problems/number-of-1-bits/solution/wei-1de-ge-shu-by-leetcode/ + * 191. 位1的个数 + * 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 + * 示例 1: + * 输入:00000000000000000000000000001011 + * 输出:3 + * 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 + * 示例 2: + * 输入:00000000000000000000000010000000 + * 输出:1 + * 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 + * 示例 3: + * 输入:11111111111111111111111111111101 + * 输出:31 + * 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 * * @Auther: zhunn * @Date: 2020/11/07 21:23 diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java index 74cbec5..2ba6bf9 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test231/Solution.java @@ -4,6 +4,19 @@ /** * https://leetcode-cn.com/problems/power-of-two/solution/2de-mi-by-leetcode/ + * 231. 2的幂 + * 给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 + * 示例 1: + * 输入: 1 + * 输出: true + * 解释: 20 = 1 + * 示例 2: + * 输入: 16 + * 输出: true + * 解释: 24 = 16 + * 示例 3: + * 输入: 218 + * 输出: false * * @Auther: zhunn * @Date: 2020/11/07 22:23 diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java index 1777d29..a1e4745 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test338/Solution.java @@ -5,6 +5,14 @@ /** * https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode/ + * 338. 比特位计数 + * 给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。 + * 示例 1: + * 输入: 2 + * 输出: [0,1,1] + * 示例 2: + * 输入: 5 + * 输出: [0,1,1,2,1,2] * * @Auther: zhunn * @Date: 2020/11/07 22:23 diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java index ce2b87d..047e5d5 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java @@ -4,6 +4,19 @@ /** * https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode/ + * 461. 汉明距离 + * 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。 + * 给出两个整数 x 和 y,计算它们之间的汉明距离。 + * 注意: + * 0 ≤ x, y < 231. + * 示例: + * 输入: x = 1, y = 4 + * 输出: 2 + * 解释: + * 1 (0 0 0 1) + * 4 (0 1 0 0) + * ↑ ↑ + * 上面的箭头指出了对应二进制位不同的位置。 * * @Auther: zhunn * @Date: 2020/11/07 22:23 diff --git a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java index ef1306f..8d71208 100644 --- a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java @@ -8,6 +8,18 @@ /** * https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/ + * 22. 括号生成 + * 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 + * 示例: + * 输入:n = 3 + * 输出:[ + * "((()))", + * "(()())", + * "(())()", + * "()(())", + * "()()()" + * ] + * * @Auther: zhunn * @Date: 2020/10/24 17:23 * @Description: 括号生成:1-dfs @@ -29,7 +41,7 @@ private void dfs(int left, int right, String curStr) { } // 剪枝 - if(left > right){ + if (left > right) { return; } // 如果左括号还剩余的话,可以拼接左括号 diff --git a/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java b/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java index e9f6126..42a3d70 100644 --- a/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/divide/test169/Solution.java @@ -7,6 +7,16 @@ import java.util.Map; /** + * 169. 多数元素 + * 给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 + * 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 + * 示例 1: + * 输入: [3,2,3] + * 输出: 3 + * 示例 2: + * 输入: [2,2,1,1,1,2,2] + * 输出: 2 + * * @Auther: zhunn * @Date: 2020/11/2 16:23 * @Description: 多数元素:1-排序;2-哈希表(优选);3-分治 diff --git a/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java b/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java index f969b84..e0ca4f4 100644 --- a/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java @@ -3,6 +3,19 @@ import org.junit.Test; /** + * 50. Pow(x, n) + * 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 + * 示例 1: + * 输入: 2.00000, 10 + * 输出: 1024.00000 + * 示例 2: + * 输入: 2.10000, 3 + * 输出: 9.26100 + * 示例 3: + * 输入: 2.00000, -2 + * 输出: 0.25000 + * 解释: 2-2 = 1/22 = 1/4 = 0.25 + * * @Auther: zhunn * @Date: 2020/11/2 16:13 * @Description: Pow(x, n):1-递归;2-迭代 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java index 2953242..d0212d7 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java @@ -8,6 +8,17 @@ /** * https://leetcode-cn.com/problems/triangle/solution/di-gui-ji-yi-hua-dp-bi-xu-miao-dong-by-sweetiee/ + * 120. 三角形最小路径和 + * 给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 + * 相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。 + * 例如,给定三角形: + * [ + * [2], + * [3,4], + * [6,5,7], + * [4,1,8,3] + * ] + * 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 * * @Auther: zhunn * @Date: 2020/11/3 22:02 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java index bc3306e..26e5481 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java @@ -4,6 +4,20 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/kan-yi-bian-jiu-wang-bu-diao-de-jie-ti-si-lu-bu-di/ + * 121. 买卖股票的最佳时机 + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * 如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。 + * 注意:你不能在买入股票前卖出股票。 + * 示例 1: + * 输入: [7,1,5,3,6,4] + * 输出: 5 + * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 + * 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 + * 示例 2: + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + * * @Auther: zhunn * @Date: 2020/11/3 19:59 * @Description: 买卖股票的最佳时机:双指针法 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java index 14c8cc6..4c47fc2 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java @@ -4,6 +4,25 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/dong-tai-gui-hua-by-liweiwei1419-7/ + * 123. 买卖股票的最佳时机 III + * 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 + * 注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * 示例 1: + * 输入: [3,3,5,0,0,3,1,4] + * 输出: 6 + * 解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 + * 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。 + * 示例 2: + * 输入: [1,2,3,4,5] + * 输出: 4 + * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 + * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + * 示例 3: + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。 * * @Auther: zhunn * @Date: 2020/11/3 21:06 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java index 6898741..7f0dfa6 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test152/Solution.java @@ -4,6 +4,16 @@ /** * https://leetcode-cn.com/problems/maximum-product-subarray/solution/dong-tai-gui-hua-li-jie-wu-hou-xiao-xing-by-liweiw/ + * 152. 乘积最大子数组 + * 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 + * 示例 1: + * 输入: [2,3,-2,4] + * 输出: 6 + * 解释: 子数组 [2,3] 有最大乘积 6。 + * 示例 2: + * 输入: [-2,0,-1] + * 输出: 0 + * 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。 * * @Auther: zhunn * @Date: 2020/11/3 22:02 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java index 33edf5b..09e4b2f 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java @@ -4,6 +4,20 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/solution/dong-tai-gui-hua-by-liweiwei1419-4/ + * 188. 买卖股票的最佳时机 IV + * 给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。 + * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * 示例 1: + * 输入:k = 2, prices = [2,4,1] + * 输出:2 + * 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。 + * 示例 2: + * 输入:k = 2, prices = [3,2,6,5,0,3] + * 输出:7 + * 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。 + * 随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。 + * * @Auther: zhunn * @Date: 2020/11/3 22:03 * @Description: 买卖股票的最佳时机 IV :1-动态规划-三维超出内存限制;2-动态规划-优化空间,降维,使用二维 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java index d5419c1..30d89e3 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java @@ -4,6 +4,18 @@ /** * https://leetcode-cn.com/problems/house-robber/solution/da-jia-jie-she-by-leetcode-solution/ + * 198. 打家劫舍 + * 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 + * 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 + * 示例 1: + * 输入:[1,2,3,1] + * 输出:4 + * 解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。 + * 偷窃到的最高金额 = 1 + 3 = 4 。 + * 示例 2: + * 输入:[2,7,9,3,1] + * 输出:12 + * 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。 * * @Auther: zhunn * @Date: 2020/11/6 17:16 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java index 518efab..8239c61 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java @@ -5,6 +5,22 @@ import java.util.Arrays; /** + * 213. 打家劫舍 II + * 你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。 + * 给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。 + * 示例 1: + * 输入:nums = [2,3,2] + * 输出:3 + * 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。 + * 示例 2: + * 输入:nums = [1,2,3,1] + * 输出:4 + * 解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。 + * 偷窃到的最高金额 = 1 + 3 = 4 。 + * 示例 3: + * 输入:nums = [0] + * 输出:0 + * * @Auther: zhunn * @Date: 2020/11/6 17:45 * @Description: 打家劫舍 II:在198题的基础上,选择不偷第一家或不偷最后一家 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java index 4eb0e0d..21f442a 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java @@ -3,6 +3,17 @@ import org.junit.Test; /** + * 279. 完全平方数 + * 给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。 + * 示例 1: + * 输入: n = 12 + * 输出: 3 + * 解释: 12 = 4 + 4 + 4. + * 示例 2: + * 输入: n = 13 + * 输出: 2 + * 解释: 13 = 4 + 9. + * * @Auther: zhunn * @Date: 2020/11/5 18:00 * @Description: 完全平方数:1-动态规划 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java index cb2da78..6c1a119 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java @@ -6,6 +6,12 @@ /** * https://leetcode-cn.com/problems/longest-increasing-subsequence/solution/dong-tai-gui-hua-er-fen-cha-zhao-tan-xin-suan-fa-p/ + * 300. 最长上升子序列 + * 给定一个无序的整数数组,找到其中最长上升子序列的长度。 + * 示例: + * 输入: [10,9,2,5,3,7,101,18] + * 输出: 4 + * 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。 * * @Auther: zhunn * @Date: 2020/11/4 21:03 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java index bc02961..f575b61 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java @@ -4,6 +4,15 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/solution/dong-tai-gui-hua-by-liweiwei1419-5/ + * 309. 最佳买卖股票时机含冷冻期 + * 给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​ + * 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): + * 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 + * 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。 + * 示例: + * 输入: [1,2,3,0,2] + * 输出: 3 + * 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出] * * @Auther: zhunn * @Date: 2020/11/3 22:03 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java index 02de398..82ff4d5 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java @@ -8,6 +8,25 @@ /** * https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-shi-yong-wan-quan-bei-bao-wen-ti-/ * 官方解答:https://leetcode-cn.com/problems/coin-change/solution/322-ling-qian-dui-huan-by-leetcode-solution/ + * 322. 零钱兑换 + * 给定不同面额的硬币 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 * * @Auther: zhunn * @Date: 2020/11/4 22:03 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java index 62b704c..feef2cd 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test337/Solution.java @@ -5,6 +5,27 @@ /** * https://leetcode-cn.com/problems/house-robber-iii/solution/shu-xing-dp-ru-men-wen-ti-by-liweiwei1419/ + * 337. 打家劫舍 III + * 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。 + * 计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。 + * 示例 1: + * 输入: [3,2,3,null,3,null,1] + * 3 + * / \ + * 2 3 + * \ \ + * 3 1 + * 输出: 7 + * 解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7. + * 示例 2: + * 输入: [3,4,5,1,3,null,1] + * 3 + * / \ + * 4 5 + * / \ \ + * 1 3 1 + * 输出: 9 + * 解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9. * * @Auther: zhunn * @Date: 2020/11/6 18:35 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java index f026068..483a6a7 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java @@ -4,6 +4,16 @@ /** * 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 + * 343. 整数拆分 + * 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 + * 示例 1: + * 输入: 2 + * 输出: 1 + * 解释: 2 = 1 + 1, 1 × 1 = 1。 + * 示例 2: + * 输入: 10 + * 输出: 36 + * 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。 * * @Auther: zhunn * @Date: 2020/11/5 18:46 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java index ab32363..418cf63 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java @@ -4,7 +4,19 @@ /** * https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/ + * 416. 分割等和子集 * 给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 + * 注意: + * 每个数组中的元素不会超过 100 + * 数组的大小不会超过 200 + * 示例 1: + * 输入: [1, 5, 11, 5] + * 输出: true + * 解释: 数组可以分割成 [1, 5, 5] 和 [11]. + * 示例 2: + * 输入: [1, 2, 3, 5] + * 输出: false + * 解释: 数组不能分割成两个元素和相等的子集. * * @Auther: zhunn * @Date: 2020/11/5 18:27 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java index 1aff993..39cee04 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java @@ -4,6 +4,19 @@ /** * https://leetcode-cn.com/problems/ones-and-zeroes/solution/dong-tai-gui-hua-zhuan-huan-wei-0-1-bei-bao-wen-ti/ + * 474. 一和零 + * 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 + * 请你找出并返回 strs 的最大子集的大小,该子集中 最多 有 m 个 0 和 n 个 1 。 + * 如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。 + * 示例 1: + * 输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3 + * 输出:4 + * 解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 + * 其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。 + * 示例 2: + * 输入:strs = ["10", "0", "1"], m = 1, n = 1 + * 输出:2 + * 解释:最大的子集是 {"0", "1"} ,所以答案是 2 。 * * @Auther: zhunn * @Date: 2020/11/6 14:54 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java index 2e025c5..69a28a4 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java @@ -4,6 +4,19 @@ /** * https://leetcode-cn.com/problems/target-sum/solution/huan-yi-xia-jiao-du-ke-yi-zhuan-huan-wei-dian-xing/ + * 494. 目标和 + * 给定一个非负整数数组,a1, a2, ..., an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。 + * 返回可以使最终数组和为目标数 S 的所有添加符号的方法数。 + * 示例: + * 输入:nums: [1, 1, 1, 1, 1], S: 3 + * 输出:5 + * 解释: + * -1+1+1+1+1 = 3 + * +1-1+1+1+1 = 3 + * +1+1-1+1+1 = 3 + * +1+1+1-1+1 = 3 + * +1+1+1+1-1 = 3 + * 一共有5种方法让最终目标和为3。 * * @Auther: zhunn * @Date: 2020/11/6 16:03 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java index 55af139..876d2e6 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java @@ -6,6 +6,23 @@ * https://leetcode-cn.com/problems/coin-change-2/solution/ling-qian-dui-huan-iihe-pa-lou-ti-wen-ti-dao-di-yo/ * https://leetcode-cn.com/problems/coin-change-2/solution/dong-tai-gui-hua-wan-quan-bei-bao-wen-ti-by-liweiw/ * 官方解答:https://leetcode-cn.com/problems/coin-change-2/solution/ling-qian-dui-huan-ii-by-leetcode/ + * 518. 零钱兑换 II + * 给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 + * 示例 1: + * 输入: amount = 5, coins = [1, 2, 5] + * 输出: 4 + * 解释: 有四种方式可以凑成总金额: + * 5=5 + * 5=2+2+1 + * 5=2+1+1+1 + * 5=1+1+1+1+1 + * 示例 2: + * 输入: amount = 3, coins = [2] + * 输出: 0 + * 解释: 只用面额2的硬币不能凑成总金额3。 + * 示例 3: + * 输入: amount = 10, coins = [10] + * 输出: 1 * * @Auther: zhunn * @Date: 2020/11/5 9:52 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java index 9ef8984..5062535 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test53/Solution.java @@ -3,6 +3,13 @@ import org.junit.Test; /** + * 53. 最大子序和 + * 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + * 示例: + * 输入: [-2,1,-3,4,-1,2,1,-5,4] + * 输出: 6 + * 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。 + * * @Auther: zhunn * @Date: 2020/11/4 18:56 * @Description: 最大子序和:1-动态规划;2-动态规划优化空间 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java index c487aae..e4502aa 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test62/Solution.java @@ -3,6 +3,22 @@ import org.junit.Test; /** + * 62. 不同路径 + * 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 + * 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 + * 问总共有多少条不同的路径? + * 示例 1: + * 输入: m = 3, n = 2 + * 输出: 3 + * 解释: + * 从左上角开始,总共有 3 条路径可以到达右下角。 + * 1. 向右 -> 向右 -> 向下 + * 2. 向右 -> 向下 -> 向右 + * 3. 向下 -> 向右 -> 向右 + * 示例 2: + * 输入: m = 7, n = 3 + * 输出: 28 + * * @Auther: zhunn * @Date: 2020/11/5 16:05 * @Description: 不同路径:1-动态规划 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java index 1131243..fd245b5 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java @@ -4,6 +4,16 @@ /** * https://leetcode-cn.com/problems/minimum-path-sum/solution/zui-xiao-lu-jing-he-dong-tai-gui-hua-gui-fan-liu-c/ + * 64. 最小路径和 + * 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 + * 说明:每次只能向下或者向右移动一步。 + * 示例 1: + * 输入:grid = [[1,3,1],[1,5,1],[4,2,1]] + * 输出:7 + * 解释:因为路径 1→3→1→1→1 的总和最小。 + * 示例 2: + * 输入:grid = [[1,2,3],[4,5,6]] + * 输出:12 * * @Auther: zhunn * @Date: 2020/11/5 11:33 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java index 4a9de71..ff2ee30 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java @@ -3,6 +3,24 @@ import org.junit.Test; /** + * 70. 爬楼梯 + * 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 + * 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? + * 注意:给定 n 是一个正整数。 + * 示例 1: + * 输入: 2 + * 输出: 2 + * 解释: 有两种方法可以爬到楼顶。 + * 1. 1 阶 + 1 阶 + * 2. 2 阶 + * 示例 2: + * 输入: 3 + * 输出: 3 + * 解释: 有三种方法可以爬到楼顶。 + * 1. 1 阶 + 1 阶 + 1 阶 + * 2. 1 阶 + 2 阶 + * 3. 2 阶 + 1 阶 + * //////////////////////////////////////////// * 不难发现,这个问题可以被分解为一些包含最优子结构的子问题,即它的最优解可以从其子问题的最优解来有效地构建,我们可以使用动态规划来解决这一问题。 * 第 i 阶可以由以下两种方法得到: * 在第(i−1) 阶后向上爬 1 阶。 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java index 81bdc13..10efb69 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java @@ -4,6 +4,21 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/solution/dong-tai-gui-hua-by-liweiwei1419-6/ + * 714. 买卖股票的最佳时机含手续费 + * 给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。 + * 你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。 + * 返回获得利润的最大值。 + * 注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。 + * 示例 1: + * 输入: prices = [1, 3, 2, 8, 4, 9], fee = 2 + * 输出: 8 + * 解释: 能够达到的最大利润: + * 在此处买入 prices[0] = 1 + * 在此处卖出 prices[3] = 8 + * 在此处买入 prices[4] = 4 + * 在此处卖出 prices[5] = 9 + * 总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8. + * * @Auther: zhunn * @Date: 2020/11/3 22:04 * @Description: 买卖股票的最佳时机含手续费:1-动态规划,2-动态规划-优化空间 diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java index bc22da5..0d50af4 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java @@ -5,6 +5,28 @@ /** * 官方:https://leetcode-cn.com/problems/edit-distance/solution/bian-ji-ju-chi-by-leetcode-solution/ * https://leetcode-cn.com/problems/edit-distance/solution/zi-di-xiang-shang-he-zi-ding-xiang-xia-by-powcai-3/ + * 72. 编辑距离 + * 给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 + * 你可以对一个单词进行如下三种操作: + * 插入一个字符 + * 删除一个字符 + * 替换一个字符 + * 示例 1: + * 输入:word1 = "horse", word2 = "ros" + * 输出:3 + * 解释: + * horse -> rorse (将 'h' 替换为 'r') + * rorse -> rose (删除 'r') + * rose -> ros (删除 'e') + * 示例 2: + * 输入:word1 = "intention", word2 = "execution" + * 输出:5 + * 解释: + * intention -> inention (删除 't') + * inention -> enention (将 'i' 替换为 'e') + * enention -> exention (将 'n' 替换为 'x') + * exention -> exection (将 'n' 替换为 'c') + * exection -> execution (插入 'u') * * @Auther: zhunn * @Date: 2020/11/5 15:09 diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java index 501c198..5a9ed32 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java @@ -6,6 +6,30 @@ /** * https://leetcode-cn.com/problems/lru-cache/ + * 146. LRU缓存机制 + * 运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制 。 + * 实现 LRUCache 类: + * LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存 + * int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。 + * void put(int key, int value) 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。 + * 进阶:你是否可以在 O(1) 时间复杂度内完成这两种操作? + * 示例: + * 输入 + * ["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"] + * [[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]] + * 输出 + * [null, null, null, 1, null, -1, null, -1, 3, 4] + * 解释 + * LRUCache lRUCache = new LRUCache(2); + * lRUCache.put(1, 1); // 缓存是 {1=1} + * lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} + * lRUCache.get(1); // 返回 1 + * lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3} + * lRUCache.get(2); // 返回 -1 (未找到) + * lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} + * lRUCache.get(1); // 返回 -1 (未找到) + * lRUCache.get(3); // 返回 3 + * lRUCache.get(4); // 返回 4 * * @Auther: zhunn * @Date: 2020/11/08 14:47 diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java b/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java index cc4a6ca..241ec93 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java @@ -2,6 +2,16 @@ /** * https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/shu-ju-jie-gou-she-ji-zhi-shi-xian-trie-qian-zhui-/ + * 208. 实现 Trie (前缀树) + * 实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 + * 示例: + * Trie trie = new Trie(); + * trie.insert("apple"); + * trie.search("apple"); // 返回 true + * trie.search("app"); // 返回 false + * trie.startsWith("app"); // 返回 true + * trie.insert("app"); + * trie.search("app"); // 返回 true * * @Auther: zhunn * @Date: 2020/11/08 14:46 diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java index 950f88e..d5f1073 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java @@ -4,6 +4,40 @@ import org.junit.Test; /** + * 48. 旋转图像 + * 给定一个 n × n 的二维矩阵表示一个图像。 + * 将图像顺时针旋转 90 度。 + * 说明: + * 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。 + * 示例 1: + * 给定 matrix = + * [ + * [1,2,3], + * [4,5,6], + * [7,8,9] + * ], + * 原地旋转输入矩阵,使其变为: + * [ + * [7,4,1], + * [8,5,2], + * [9,6,3] + * ] + * 示例 2: + * 给定 matrix = + * [ + * [ 5, 1, 9,11], + * [ 2, 4, 8,10], + * [13, 3, 6, 7], + * [15,14,12,16] + * ], + * 原地旋转输入矩阵,使其变为: + * [ + * [15,13, 2, 5], + * [14, 3, 4, 1], + * [12, 6, 8, 9], + * [16, 7,10,11] + * ] + * * @Auther: zhunn * @Date: 2020/9/16 18:22 * @Description: 顺时针旋转图像90° diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java index 23e0c73..5c64f07 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java @@ -1,6 +1,18 @@ package com.chen.algorithm.znn.frequency.test7; /** + * 7. 整数反转 + * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 + * 示例 1: + * 输入: 123 + * 输出: 321 + * 示例 2: + * 输入: -123 + * 输出: -321 + * 示例 3: + * 输入: 120 + * 输出: 21 + * * @Auther: zhunn * @Date: 2020/9/16 18:20 * @Description: 整数反转 diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java index 74b609c..f38eeb8 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java @@ -1,6 +1,20 @@ package com.chen.algorithm.znn.frequency.test9; /** + * 9. 回文数 + * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 + * 示例 1: + * 输入: 121 + * 输出: true + * 示例 2: + * 输入: -121 + * 输出: false + * 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。 + * 示例 3: + * 输入: 10 + * 输出: false + * 解释: 从右向左读, 为 01 。因此它不是一个回文数。 + * * @Auther: zhunn * @Date: 2020/9/16 18:22 * @Description: 回文数 diff --git a/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java b/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java index a4c4814..9799995 100644 --- a/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/greedy/test122/Solution.java @@ -4,25 +4,30 @@ /** * https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/tan-xin-suan-fa-by-liweiwei1419-2/ - * - * @Auther: zhunn - * @Date: 2020/11/2 13:50 - * @Description: 买卖股票的最佳时机 II:1-贪心算法;2-动态规划 - * 1、题意: - * 你可以尽可能地完成更多的交易(多次买卖一支股票) + * 122. 买卖股票的最佳时机 II + * 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 + * 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 * 示例 1: * 输入: [7,1,5,3,6,4] * 输出: 7 * 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 - *   随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 + * 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 * 示例 2: * 输入: [1,2,3,4,5] * 输出: 4 * 解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 - *   注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 - *   因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 - * 2、简述题意:(手里只能持有一支股票,可以买卖多次,必须在再次购买前出售掉之前的股票) + * 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 + * 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 + * 示例 3: + * 输入: [7,6,4,3,1] + * 输出: 0 + * 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 + * + * @Auther: zhunn + * @Date: 2020/11/2 13:50 + * @Description: 买卖股票的最佳时机 II:1-贪心算法;2-动态规划 + * 简述题意:(手里只能持有一支股票,可以买卖多次,必须在再次购买前出售掉之前的股票) */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java index 6783ca7..c8d8445 100644 --- a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java @@ -3,6 +3,19 @@ import org.junit.Test; /** + * 55. 跳跃游戏 + * 给定一个非负整数数组,你最初位于数组的第一个位置。 + * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 + * 判断你是否能够到达最后一个位置。 + * 示例 1: + * 输入: [2,3,1,1,4] + * 输出: true + * 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 + * 示例 2: + * 输入: [3,2,1,0,4] + * 输出: false + * 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 + * * @Auther: zhunn * @Date: 2020/11/2 14:51 * @Description: 跳跃游戏:1-贪心算法;2-动态规划 @@ -11,6 +24,7 @@ public class Solution { /** * 1-贪心算法 + * * @param nums * @return */ @@ -30,6 +44,7 @@ public boolean canJump(int[] nums) { /** * 2-动态规划 + * * @param nums * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java index 4d94f7e..49b4f62 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java @@ -7,6 +7,17 @@ import java.util.List; /** + * 15. 三数之和 + * 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 + * 注意:答案中不可以包含重复的三元组。 + * 示例: + * 给定数组 nums = [-1, 0, 1, 2, -1, -4], + * 满足要求的三元组集合为: + * [ + * [-1, 0, 1], + * [-1, -1, 2] + * ] + * * @Auther: zhunn * @Date: 2020/10/26 14:35 * @Description: 三数之和:排序+双指针 diff --git a/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java index 956be63..0be7f6f 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java @@ -8,6 +8,20 @@ import java.util.List; /** + * 18. 四数之和 + * 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 + * 注意: + * 答案中不可以包含重复的四元组。 + * 示例: + * 给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 + *

+ * 满足要求的四元组集合为: + * [ + * [-1, 0, 0, 1], + * [-2, -1, 1, 2], + * [-2, 0, 0, 2] + * ] + * * @Auther: zhunn * @Date: 2020/10/26 15:09 * @Description: 四数之和:类比三数之和方法 diff --git a/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java index e5c3ccd..d848147 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test242/Solution.java @@ -3,6 +3,15 @@ import org.junit.Test; /** + * 242. 有效的字母异位词 + * 给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 + * 示例 1: + * 输入: s = "anagram", t = "nagaram" + * 输出: true + * 示例 2: + * 输入: s = "rat", t = "car" + * 输出: false + * * @Author: zhunn * @Date: 2020-10-22 22:12 * @Description: 有效的字母异位词。哈希表 diff --git a/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java index 5c618c8..2f5d641 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test49/Solution.java @@ -5,6 +5,17 @@ import java.util.*; /** + * 49. 字母异位词分组 + * 给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 + * 示例: + * 输入: ["eat", "tea", "tan", "ate", "nat", "bat"] + * 输出: + * [ + * ["ate","eat","tea"], + * ["nat","tan"], + * ["bat"] + * ] + * * @Auther: zhunn * @Date: 2020/10/26 11:19 * @Description: 字母异位词分组 diff --git a/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java index cbc3430..1ddb706 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java @@ -5,6 +5,15 @@ import java.util.PriorityQueue; /** + * 215. 数组中的第K个最大元素 + * 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 + * 示例 1: + * 输入: [3,2,1,5,6,4] 和 k = 2 + * 输出: 5 + * 示例 2: + * 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 + * 输出: 4 + * * @Auther: zhunn * @Date: 2020/10/26 16:55 * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 diff --git a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java index eb56510..0959cfe 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java @@ -5,6 +5,15 @@ import java.util.*; /** + * 347. 前 K 个高频元素 + * 给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 + * 示例 1: + * 输入: nums = [1,1,1,2,2,3], k = 2 + * 输出: [1,2] + * 示例 2: + * 输入: nums = [1], k = 1 + * 输出: [1] + * * @Auther: zhunn * @Date: 2020/11/08 15:25 * @Description: 前 K 个高频元素:PriorityQueue-小根堆 diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java index 057e6fc..e659efc 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java @@ -6,6 +6,25 @@ import java.util.Set; /** + * 141. 环形链表 + * 给定一个链表,判断链表中是否有环。 + * 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。 + * 如果链表中存在环,则返回 true 。 否则,返回 false 。 + * 进阶: + * 你能用 O(1)(即,常量)内存解决此问题吗? + * 示例 1: + * 输入:head = [3,2,0,-4], pos = 1 + * 输出:true + * 解释:链表中有一个环,其尾部连接到第二个节点。 + * 示例 2: + * 输入:head = [1,2], pos = 0 + * 输出:true + * 解释:链表中有一个环,其尾部连接到第一个节点。 + * 示例 3: + * 输入:head = [1], pos = -1 + * 输出:false + * 解释:链表中没有环。 + * * @Auther: zhunn * @Date: 2020/10/23 16:26 * @Description: 环形链表一:判断链表是否有环 @@ -15,6 +34,7 @@ public class Solution { /** * 2-快慢指针 + * * @param head * @return */ @@ -39,6 +59,7 @@ public boolean hasCycle1(ListNode head) { /** * 1-哈希表 + * * @param head * @return */ @@ -62,6 +83,7 @@ public boolean hasCycle2(ListNode head) { /** * 1-哈希表简易版 + * * @param head * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java index 0964ccd..7acd023 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java @@ -7,6 +7,25 @@ import java.util.Set; /** + * 142. 环形链表 II + * 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 + * 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。 + * 说明:不允许修改给定的链表。 + * 进阶: + * 你是否可以使用 O(1) 空间解决此题? + * 示例 1: + * 输入:head = [3,2,0,-4], pos = 1 + * 输出:返回索引为 1 的链表节点 + * 解释:链表中有一个环,其尾部连接到第二个节点。 + * 示例 2: + * 输入:head = [1,2], pos = 0 + * 输出:返回索引为 0 的链表节点 + * 解释:链表中有一个环,其尾部连接到第一个节点。 + * 示例 3: + * 输入:head = [1], pos = -1 + * 输出:返回 null + * 解释:链表中没有环。 + * * @Auther: zhunn * @Date: 2020/10/23 16:10 * @Description: 环形链表二,找出入环点 @@ -16,6 +35,7 @@ public class Solution { /** * 1-哈希表 + * * @param head * @return */ @@ -38,6 +58,7 @@ public ListNode detectCycle1(ListNode head) { /** * 2-快慢指针 + * * @param head * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java index 41aa679..de60664 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java @@ -4,6 +4,24 @@ import org.junit.Test; /** + * 160. 相交链表 + * 编写一个程序,找到两个单链表相交的起始节点。 + * 如下面的两个链表: + * 在节点 c1 开始相交。 + * 示例 1: + * 输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 + * 输出:Reference of the node with value = 8 + * 输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 + * 示例 2: + * 输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 + * 输出:Reference of the node with value = 2 + * 输入解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。 + * 示例 3: + * 输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 + * 输出:null + * 输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 + * 解释:这两个链表不相交,因此返回 null。 + * * @Author: zhunn * @Date: 2020-10-22 17:40 * @Description: 相交链表 diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java index 0cf1d22..23c009e 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java @@ -7,6 +7,12 @@ import java.util.LinkedList; /** + * 19. 删除链表的倒数第N个节点 + * 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。 + * 示例: + * 给定一个链表: 1->2->3->4->5, 和 n = 2. + * 当删除了倒数第二个节点后,链表变为 1->2->3->5. + * * @Auther: zhunn * @Date: 2020/10/22 14:51 * @Description: 1、遍历length-n+1;2、栈、3、双指针法 diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java index a6d850c..ba5cae8 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test2/Solution.java @@ -4,6 +4,15 @@ import org.junit.Test; /** + * 2. 两数相加 + * 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 + * 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 + * 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 + * 示例: + * 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) + * 输出:7 -> 0 -> 8 + * 原因:342 + 465 = 807 + * * @Author: zhunn * @Date: 2020-10-20 17:43 * @Description: 两数相加 @@ -34,7 +43,7 @@ public ListNode addTwo(ListNode a, ListNode b) { carry = carry / 10; curr = curr.next; } - return result.next; + return result.next; } @Test diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java index 2e61794..35d42b7 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java @@ -4,6 +4,12 @@ import org.junit.Test; /** + * 206. 反转链表 + * 反转一个单链表。 + * 示例: + * 输入: 1->2->3->4->5->NULL + * 输出: 5->4->3->2->1->NULL + * * @Auther: zhunn * @Date: 2020/10/22 17:23 * @Description: 反转链表:1-迭代法,2-递归 @@ -27,8 +33,8 @@ public ListNode reverseList1(ListNode head) { return pre; } - public ListNode reverseList2(ListNode head){ - if(head == null || head.next == null){ + public ListNode reverseList2(ListNode head) { + if (head == null || head.next == null) { return head; } ListNode p = reverseList2(head.next); diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java index 6e170b2..cf22515 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java @@ -4,9 +4,15 @@ import org.junit.Test; /** + * 21. 合并两个有序链表 + * 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 + * 示例: + * 输入:1->2->4, 1->3->4 + * 输出:1->1->2->3->4->4 + * * @Author: zhunn * @Date: 2020-09-06 01:43 - * @Description: 并两个有序链表 + * @Description: 并两个有序链表 */ public class Solution { @@ -36,7 +42,7 @@ public ListNode mergeTwoLists(ListNode l1, ListNode l2) { } @Test - public void testCase(){ + public void testCase() { ListNode l1_1 = new ListNode(3); ListNode l1_2 = new ListNode(6); diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java index af398d4..87f62f2 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java @@ -4,6 +4,19 @@ import org.junit.Test; /** + * 24. 两两交换链表中的节点 + * 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 + * 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。 + * 示例 1: + * 输入:head = [1,2,3,4] + * 输出:[2,1,4,3] + * 示例 2: + * 输入:head = [] + * 输出:[] + * 示例 3: + * 输入:head = [1] + * 输出:[1] + * * @Auther: zhunn * @Date: 2020/10/23 10:48 * @Description: 两两交换链表中结点:1-递归,2-迭代 @@ -13,6 +26,7 @@ public class Solution { /** * 1-递归 + * * @param head * @return */ @@ -28,6 +42,7 @@ public ListNode swapPairs1(ListNode head) { /** * 2-迭代 + * * @param head * @return */ @@ -55,6 +70,7 @@ public ListNode swapPairs2(ListNode head) { /** * 2-迭代(操作head) + * * @param head * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java index 4ea6f68..6e667e2 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java @@ -3,6 +3,15 @@ import com.chen.algorithm.znn.linkedlist.ListNode; /** + * 25. K 个一组翻转链表 + * 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 + * k 是一个正整数,它的值小于或等于链表的长度。 + * 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 + * 示例: + * 给你这个链表:1->2->3->4->5 + * 当 k = 2 时,应当返回: 2->1->4->3->5 + * 当 k = 3 时,应当返回: 3->2->1->4->5 + * * @Auther: zhunn * @Date: 2020/10/24 17:23 * @Description: K个一组翻转链表 @@ -11,6 +20,7 @@ public class Solution { /** * 官网解法 + * * @param head * @param k * @return @@ -64,8 +74,12 @@ public ListNode reverseKGroup1(ListNode head, int k) { ListNode end = dummy; while (end.next != null) { - for (int i = 0; i < k && end != null; i++){end = end.next;} - if (end == null) {break;} + for (int i = 0; i < k && end != null; i++) { + end = end.next; + } + if (end == null) { + break; + } ListNode start = pre.next; ListNode next = end.next; end.next = null; diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java index 9ea3411..cdfc5ce 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java @@ -3,6 +3,15 @@ import com.chen.algorithm.znn.linkedlist.ListNode; /** + * 83. 删除排序链表中的重复元素 + * 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。 + * 示例 1: + * 输入: 1->1->2 + * 输出: 1->2 + * 示例 2: + * 输入: 1->1->2->3->3 + * 输出: 1->2->3 + * * @Author: zhunn * @Date: 2020-10-08 02:19 * @Description: 删除排序链表中的重复元素 diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java index 867ab33..78a28fd 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java @@ -4,6 +4,14 @@ import org.junit.Test; /** + * 92. 反转链表 II + * 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 + * 说明: + * 1 ≤ m ≤ n ≤ 链表长度。 + * 示例: + * 输入: 1->2->3->4->5->NULL, m = 2, n = 4 + * 输出: 1->4->3->2->5->NULL + * * @Auther: zhunn * @Date: 2020/10/24 17:23 * @Description: 反转链表二:1-双指针,2-删除结点递推 @@ -25,6 +33,7 @@ private ListNode reverseN(ListNode head, int n) { /** * 1-双指针 + * * @param head * @param m * @param n @@ -55,27 +64,28 @@ public ListNode reverseBetween1(ListNode head, int m, int n) { /** * 2-删除结点递推 + * * @param head * @param m * @param n * @return */ - public ListNode reverseBetween2(ListNode head, int m, int n){ - if(head == null || head.next == null){ + public ListNode reverseBetween2(ListNode head, int m, int n) { + if (head == null || head.next == null) { return head; } ListNode dummy = new ListNode(-1); dummy.next = head; ListNode pre = dummy; - for(int i =0;i 返回 -3. + * minStack.pop(); + * minStack.top(); --> 返回 0. + * minStack.getMin(); --> 返回 -2. + * * @Auther: zhunn * @Date: 2020/10/26 18:20 * @Description: 最小栈 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java index be03ebe..dcec18d 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test20/Solution.java @@ -7,6 +7,28 @@ import java.util.Stack; /** + * 20. 有效的括号 + * 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。 + * 有效字符串需满足: + * 左括号必须用相同类型的右括号闭合。 + * 左括号必须以正确的顺序闭合。 + * 注意空字符串可被认为是有效字符串。 + * 示例 1: + * 输入: "()" + * 输出: true + * 示例 2: + * 输入: "()[]{}" + * 输出: true + * 示例 3: + * 输入: "(]" + * 输出: false + * 示例 4: + * 输入: "([)]" + * 输出: false + * 示例 5: + * 输入: "{[]}" + * 输出: true + * * @Auther: zhunn * @Date: 2020/10/27 14:18 * @Description: 有效的括号 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java b/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java index 91311e4..8473d13 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java @@ -4,6 +4,17 @@ import java.util.Queue; /** + * 225. 用队列实现栈 + * 使用队列实现栈的下列操作: + * push(x) -- 元素 x 入栈 + * pop() -- 移除栈顶元素 + * top() -- 获取栈顶元素 + * empty() -- 返回栈是否为空 + * 注意: + * 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。 + * 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。 + * 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。 + * * @Auther: zhunn * @Date: 2020/10/26 22:20 * @Description: 用两个队列实现一个栈, 官方解法 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java index 831ee36..b79ef8d 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java @@ -5,6 +5,19 @@ import java.util.Stack; /** + * 227. 基本计算器 II + * 实现一个基本的计算器来计算一个简单的字符串表达式的值。 + * 字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。 + * 示例 1: + * 输入: "3+2*2" + * 输出: 7 + * 示例 2: + * 输入: " 3/2 " + * 输出: 1 + * 示例 3: + * 输入: " 3+5 / 2 " + * 输出: 5 + * * @Auther: zhunn * @Date: 2020/10/27 11:11 * @Description: 基本计算II diff --git a/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java index 6815a3f..96fa76b 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java @@ -3,6 +3,32 @@ import java.util.Stack; /** + * 232. 用栈实现队列 + * 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作(push、pop、peek、empty): + * 实现 MyQueue 类: + * void push(int x) 将元素 x 推到队列的末尾 + * int pop() 从队列的开头移除并返回元素 + * int peek() 返回队列开头的元素 + * boolean empty() 如果队列为空,返回 true ;否则,返回 false + * 说明: + * 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 + * 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。 + * 进阶: + * 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。 + * 示例: + * 输入: + * ["MyQueue", "push", "push", "peek", "pop", "empty"] + * [[], [1], [2], [], [], []] + * 输出: + * [null, null, null, 1, 1, false] + * 解释: + * MyQueue myQueue = new MyQueue(); + * myQueue.push(1); // queue is: [1] + * myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue) + * myQueue.peek(); // return 1 + * myQueue.pop(); // return 1, queue is [2] + * myQueue.empty(); // return false + * * @Auther: zhunn * @Date: 2020/10/26 17:36 * @Description: 用栈实现队列 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java index 9b35dc3..b180f34 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java @@ -7,6 +7,24 @@ import java.util.LinkedList; /** + * 239. 滑动窗口最大值 + * 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 + * 返回滑动窗口中的最大值。 + * 进阶: + * 你能在线性时间复杂度内解决此题吗? + * 示例: + * 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 + * 输出: [3,3,5,5,6,7] + * 解释: + * 滑动窗口的位置 最大值 + * --------------- ----- + * [1 3 -1] -3 5 3 6 7 3 + * 1 [3 -1 -3] 5 3 6 7 3 + * 1 3 [-1 -3 5] 3 6 7 5 + * 1 3 -1 [-3 5 3] 6 7 5 + * 1 3 -1 -3 [5 3 6] 7 6 + * 1 3 -1 -3 5 [3 6 7] 7 + * * @Auther: zhunn * @Date: 2020/10/27 14:32 * @Description: 滑动窗口最大值 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java index 301a38e..af1aab6 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java @@ -9,6 +9,22 @@ /** * https://leetcode-cn.com/problems/next-greater-element-i/solution/xia-yi-ge-geng-da-yuan-su-i-by-leetcode/ + * 496. 下一个更大元素 I + * 给定两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。 + * nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。 + * 示例 1: + * 输入: nums1 = [4,1,2], nums2 = [1,3,4,2]. + * 输出: [-1,3,-1] + * 解释: + * 对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。 + * 对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。 + * 对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。 + * 示例 2: + * 输入: nums1 = [2,4], nums2 = [1,2,3,4]. + * 输出: [3,-1] + * 解释: + * 对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。 + * 对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出 -1 。 * * @Auther: zhunn * @Date: 2020/11/08 15:25 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java index 73556ca..24f4972 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java @@ -5,6 +5,25 @@ import java.util.PriorityQueue; /** + * 703. 数据流中的第 K 大元素 + * 设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。 + * 请实现 KthLargest 类: + * KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。 + * int add(int val) 返回当前数据流中第 k 大的元素。 + * 示例: + * 输入: + * ["KthLargest", "add", "add", "add", "add", "add"] + * [[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]] + * 输出: + * [null, 4, 5, 5, 8, 8] + * 解释: + * KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]); + * kthLargest.add(3); // return 4 + * kthLargest.add(5); // return 5 + * kthLargest.add(10); // return 5 + * kthLargest.add(9); // return 8 + * kthLargest.add(4); // return 8 + * * @Auther: zhunn * @Date: 2020/10/26 16:55 * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 diff --git a/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java index a8a64f4..00febea 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java @@ -3,6 +3,17 @@ import org.junit.Test; /** + * 14. 最长公共前缀 + * 编写一个函数来查找字符串数组中的最长公共前缀。 + * 如果不存在公共前缀,返回空字符串 ""。 + * 示例 1: + * 输入: ["flower","flow","flight"] + * 输出: "fl" + * 示例 2: + * 输入: ["dog","racecar","car"] + * 输出: "" + * 解释: 输入不存在公共前缀。 + * * @Auther: zhunn * @Date: 2020/10/27 15:51 * @Description: 最长公共前缀 diff --git a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java index bcecef0..8e1fae4 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java @@ -6,6 +6,22 @@ import java.util.Map; /** + * 3. 无重复字符的最长子串 + * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 + * 示例 1: + * 输入: "abcabcbb" + * 输出: 3 + * 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 + * 示例 2: + * 输入: "bbbbb" + * 输出: 1 + * 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 + * 示例 3: + * 输入: "pwwkew" + * 输出: 3 + * 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 + * 请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 + * * @Auther: zhunn * @Date: 2020/10/27 16:02 * @Description: 无重复字符的最长子串 diff --git a/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java index 92ed699..48b88bb 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java @@ -3,6 +3,9 @@ import org.junit.Test; /** + * 415. 字符串相加 + * 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。 + * * @Auther: zhunn * @Date: 2020/10/27 16:03 * @Description: 字符串相加 diff --git a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java index e0f1162..a2a487b 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java @@ -3,6 +3,16 @@ import org.junit.Test; /** + * 5. 最长回文子串 + * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 + * 示例 1: + * 输入: "babad" + * 输出: "bab" + * 注意: "aba" 也是一个有效答案。 + * 示例 2: + * 输入: "cbbd" + * 输出: "bb" + * * @Auther: zhunn * @Date: 2020/10/27 16:02 * @Description: 最长回文子串: diff --git a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java index 63aad2c..6f2ec19 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java @@ -7,6 +7,21 @@ import java.util.Queue; /** + * 101. 对称二叉树 + * 给定一个二叉树,检查它是否是镜像对称的。 + * 例如,二叉树 [1,2,2,3,4,4,3] 是对称的。 + * 1 + * / \ + * 2 2 + * / \ / \ + * 3 4 4 3 + * 但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的: + * 1 + * / \ + * 2 2 + * \ \ + * 3 3 + * * @Auther: zhunn * @Date: 2020/10/29 11:03 * @Description: 对称二叉树:1-递归,2-迭代 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java index 56c1f8c..494cc96 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java @@ -10,6 +10,22 @@ import java.util.Queue; /** + * 102. 二叉树的层序遍历 + * 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。 + * 示例: + * 二叉树:[3,9,20,null,null,15,7], + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + * 返回其层次遍历结果: + * [ + * [3], + * [9,20], + * [15,7] + * ] + * * @Auther: zhunn * @Date: 2020/10/28 13:52 * @Description: 二叉树的层序遍历:1-BFS实现 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java index 78f15ca..5d252f9 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test103/Solution.java @@ -10,6 +10,21 @@ /** * https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal/solution/jiao-ti-shi-yong-zhan-jian-dan-shi-xian-ju-chi-xin/ + * 103. 二叉树的锯齿形层次遍历 + * 给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 + * 例如: + * 给定二叉树 [3,9,20,null,null,15,7], + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + * 返回锯齿形层次遍历如下: + * [ + * [3], + * [20,9], + * [15,7] + * ] * * @Auther: zhunn * @Date: 2020/10/28 15:03 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java index 07debed..847192b 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java @@ -7,6 +7,19 @@ import java.util.Queue; /** + * 104. 二叉树的最大深度 + * 给定一个二叉树,找出其最大深度。 + * 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。 + * 说明: 叶子节点是指没有子节点的节点。 + * 示例: + * 给定二叉树 [3,9,20,null,null,15,7], + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + * 返回它的最大深度 3 。 + * * @Auther: zhunn * @Date: 2020/10/29 17:57 * @Description: 二叉树的最大深度:1-递归;2-广度优先搜索(BFS-层次遍历) diff --git a/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java index aeb5c08..0ce20d0 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java @@ -7,6 +7,22 @@ import java.util.*; /** + * 107. 二叉树的层次遍历 II + * 给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) + * 例如: + * 给定二叉树 [3,9,20,null,null,15,7], + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + * 返回其自底向上的层次遍历为: + * [ + * [15,7], + * [9,20], + * [3] + * ] + * * @Auther: zhunn * @Date: 2020/10/28 15:50 * @Description: 二叉树的层次遍历II diff --git a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java index 5f119ba..6299d12 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java @@ -7,6 +7,17 @@ import java.util.Queue; /** + * 111. 二叉树的最小深度 (需要看leetcode题上面的图) + * 给定一个二叉树,找出其最小深度。 + * 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 + * 说明:叶子节点是指没有子节点的节点。 + * 示例 1: + * 输入:root = [3,9,20,null,null,15,7] + * 输出:2 + * 示例 2: + * 输入:root = [2,null,3,null,4,null,5,null,6] + * 输出:5 + * * @Auther: zhunn * @Date: 2020/10/29 18:40 * @Description: 二叉树的最小深度:1-深度优先搜索(DFS),即递归;2-广度优先搜索(BFS) @@ -16,6 +27,7 @@ public class Solution { /** * 1-深度优先搜索(DFS),即递归 * 叶子结点都为空,需要走到叶子结点,当一个结点为空一个结点不为空时,说明叶子结点在不为空的那个节点,返回不为空 + * * @param root * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java index d7b20fd..867014b 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java @@ -8,6 +8,21 @@ import java.util.Queue; /** + * 112. 路径总和 + * 给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。 + * 说明: 叶子节点是指没有子节点的节点。 + * 示例: + * 给定如下二叉树,以及目标和 sum = 22, + * + * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ \ + * 7 2 1 + * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 + * * @Auther: zhunn * @Date: 2020/11/08 15:25 * @Description: 路径总和:1-递归;2-广度优先搜索 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java index 6186b6f..60d7c6f 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java @@ -6,6 +6,25 @@ import java.util.*; /** + * 113. 路径总和 II + * 给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 + * 说明: 叶子节点是指没有子节点的节点。 + * 示例: + * 给定如下二叉树,以及目标和 sum = 22, + * + * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ / \ + * 7 2 5 1 + * 返回: + * [ + * [5,4,11,2], + * [5,8,4,5] + * ] + * * @Auther: zhunn * @Date: 2020/10/28 10:11 * @Description: 路径之和 II,二叉树中和为某一值的路径:1-深度优先搜索;2-广度优先搜索 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java index a3aeb29..9b3e80c 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java @@ -9,6 +9,9 @@ import java.util.Stack; /** + * 144. 二叉树的前序遍历 + * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 + * * @Auther: zhunn * @Date: 2020/10/28 16:25 * @Description: 二叉树的前序遍历:1-递归;2-迭代 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java index 4e2ed22..b66ce26 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java @@ -7,6 +7,9 @@ import java.util.*; /** + * 145. 二叉树的后序遍历 + * 给定一个二叉树,返回它的 后序 遍历。 + * * @Auther: zhunn * @Date: 2020/10/28 10:28 * @Description: 二叉树的后序遍历:1-递归;2-迭代(时间复杂度和空间复杂度都是O(n)) @@ -38,6 +41,7 @@ private void postorder(TreeNode root, List res) { /** * 2-迭代法,两个栈实现 + * * @param root * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java index 5e7ef4d..4eea1f8 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java @@ -8,6 +8,18 @@ import java.util.Queue; /** + * 199. 二叉树的右视图 + * 给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。 + * 示例: + * 输入: [1,2,3,null,5,null,4] + * 输出: [1, 3, 4] + * 解释: + * 1 <--- + * / \ + * 2 3 <--- + * \ \ + * 5 4 <--- + * * @Auther: zhunn * @Date: 2020/10/28 17:41 * @Description: 二叉树的右视图:1-广度优先搜索;2-深度优先搜索 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java index a9a870a..c881503 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java @@ -10,6 +10,21 @@ /** * https://leetcode-cn.com/problems/invert-binary-tree/solution/dong-hua-yan-shi-liang-chong-shi-xian-226-fan-zhua/ + * 226. 翻转二叉树 + * 翻转一棵二叉树。 + * 示例: + * 输入: + * 4 + * / \ + * 2 7 + * / \ / \ + * 1 3 6 9 + * 输出: + * 4 + * / \ + * 7 2 + * / \ / \ + * 9 6 3 1 * * @Auther: zhunn * @Date: 2020/10/28 17:58 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java index 6401cc8..56770c0 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test235/Solution.java @@ -4,6 +4,19 @@ import org.junit.Test; /** + * 235. 二叉搜索树的最近公共祖先 (需要看leetcode题上面的图) + * 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 + * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5] + * 示例 1: + * 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 + * 输出: 6 + * 解释: 节点 2 和节点 8 的最近公共祖先是 6。 + * 示例 2: + * 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 + * 输出: 2 + * 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。 + * * @Auther: zhunn * @Date: 2020/10/29 15:02 * @Description: 二叉搜索树的最近公共祖先 @@ -26,7 +39,7 @@ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { @Test public void test() { TreeNode left = new TreeNode(1); - TreeNode right = new TreeNode(7, new TreeNode(6), new TreeNode(20)); + TreeNode right = new TreeNode(7, new TreeNode(6), new TreeNode(20)); TreeNode root = new TreeNode(3, left, right); TreeNode res = lowestCommonAncestor(root, left, right); diff --git a/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java index a5ae70e..494c956 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java @@ -9,6 +9,19 @@ import java.util.Set; /** + * 236. 二叉树的最近公共祖先 (需要看leetcode题上面的图) + * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4] + * 示例 1: + * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 + * 输出: 3 + * 解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 + * 示例 2: + * 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 + * 输出: 5 + * 解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 + * * @Auther: zhunn * @Date: 2020/10/29 15:29 * @Description: 二叉树的最近公共祖先:1-递归;2-存储父节点 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java index c8bdd69..18acc40 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java @@ -4,6 +4,25 @@ import org.junit.Test; /** + * 437. 路径总和 III + * 给定一个二叉树,它的每个结点都存放着一个整数值。 + * 找出路径和等于给定数值的路径总数。 + * 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。 + * 二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。 + * 示例: + * root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 + * 10 + * / \ + * 5 -3 + * / \ \ + * 3 2 11 + * / \ \ + * 3 -2 1 + * 返回 3。和等于 8 的路径有: + * 1. 5 -> 3 + * 2. 5 -> 2 -> 1 + * 3. -3 -> 11 + * * @Auther: zhunn * @Date: 2020/11/08 15:25 * @Description: 路径总和 III diff --git a/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java index 467231d..791db20 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java @@ -5,6 +5,26 @@ import org.junit.Test; /** + * 538. 把二叉搜索树转换为累加树(需要看leetcode题上面的图) + * 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 + * 提醒一下,二叉搜索树满足下列约束条件: + * 节点的左子树仅包含键 小于 节点键的节点。 + * 节点的右子树仅包含键 大于 节点键的节点。 + * 左右子树也必须是二叉搜索树。 + * 注意:本题和 1038: https://leetcode-cn.com/problems/binary-search-tree-to-greater-sum-tree/ 相同 + * 示例 1: + * 输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8] + * 输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8] + * 示例 2: + * 输入:root = [0,null,1] + * 输出:[1,null,1] + * 示例 3: + * 输入:root = [1,0,2] + * 输出:[3,3,2] + * 示例 4: + * 输入:root = [3,2,4,1] + * 输出:[7,9,4,10] + * * @Auther: zhunn * @Date: 2020/10/29 11:39 * @Description: 把二叉搜索树转换成累加树 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java index 53ae92e..569739e 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test543/Solution.java @@ -5,6 +5,18 @@ import org.junit.Test; /** + * 543. 二叉树的直径 + * 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。 + * 示例 : + * 给定二叉树 + * + * 1 + * / \ + * 2 3 + * / \ + * 4 5 + * 返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。 + * * @Auther: zhunn * @Date: 2020/10/29 14:26 * @Description: 二叉树的直径: = 左子树的深度+右子树的深度 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java index 9a42724..6a0dbd5 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java @@ -5,6 +5,26 @@ import org.junit.Test; /** + * 617. 合并二叉树 + * 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。 + * 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。 + * 示例 1: + * 输入: + * Tree 1 Tree 2 + * 1 2 + * / \ / \ + * 3 2 1 3 + * / \ \ + * 5 4 7 + * 输出: + * 合并后的树: + * 3 + * / \ + * 4 5 + * / \ \ + * 5 4 7 + * 注意: 合并必须从两个树的根节点开始。 + * * @Auther: zhunn * @Date: 2020/10/29 14:50 * @Description: 合并二叉树 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java index 90c28ca..a9a6410 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java @@ -10,6 +10,8 @@ /** * https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/94er-cha-shu-de-zhong-xu-bian-li-by-wulin-v/ + * 94. 二叉树的中序遍历 + * 给定一个二叉树的根节点 root ,返回它的 中序 遍历。 * * @Auther: zhunn * @Date: 2020/10/28 16:25 @@ -43,6 +45,7 @@ private void inOrder(TreeNode root, List res) { /** * 2-迭代 + * * @param root * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java index 9e79d17..c24cae5 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java @@ -3,6 +3,20 @@ import org.junit.Test; /** + * 96. 不同的二叉搜索树 + * 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? + * 示例: + * 输入: 3 + * 输出: 5 + * 解释: + * 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: + * + * 1 3 3 2 1 + * \ / / / \ \ + * 3 2 1 1 3 2 + * / / \ \ + * 2 1 2 3 + * * @Auther: zhunn * @Date: 2020/10/29 17:49 * @Description: 不同的二叉搜索树:1-动态规划 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java index 1fc6b20..179d980 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java @@ -6,6 +6,29 @@ import java.util.Stack; /** + * 98. 验证二叉搜索树 + * 给定一个二叉树,判断其是否是一个有效的二叉搜索树。 + * 假设一个二叉搜索树具有如下特征: + * 节点的左子树只包含小于当前节点的数。 + * 节点的右子树只包含大于当前节点的数。 + * 所有左子树和右子树自身必须也是二叉搜索树。 + * 示例 1: + * 输入: + * 2 + * / \ + * 1 3 + * 输出: true + * 示例 2: + * 输入: + * 5 + * / \ + * 1 4 + * / \ + * 3 6 + * 输出: false + * 解释: 输入为: [5,1,4,null,null,3,6]。 + * 根节点的值为 5 ,但是其右子节点值为 4 。 + * * @Auther: zhunn * @Date: 2020/10/29 16:35 * @Description: 验证二叉搜索树:1-递归,2-中序遍历 From d0bfd516c5de24b9914d27c9c958333b5be5d2f0 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 12 Nov 2020 17:14:06 +0800 Subject: [PATCH 26/63] tips --- src/main/java/com/chen/algorithm/znn/note | 36 +++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 69b94b5..2665814 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -1,6 +1,38 @@ -已实现的有:共223题 +已实现的有:共121题 剑指offer第2版:共75题 简单:共41题 中等:共29题 -难:共5题 \ No newline at end of file +难:共5题 + +================================================ + +复刷顺序: +第一类:1) frequency-5 + 2) bitmap-5 +-----------------------------------------第1天 + 3) sort-5 + 4) string-4 + 5) hash-4 +-----------------------------------------第2天 +第二类:6) array-18 +-----------------------------------------第3天 + 7) heap-2 + 8) stack-8 +-----------------------------------------第4天 + 9) linkedlist-11 +-----------------------------------------第5天 + 10) tree-21 +-----------------------------------------第6天 +第三类:11) recursion-2 + 12) bfs-0 + 13) dfs-1 + 14) divide-2 + 15) greedy-2 +-----------------------------------------第7天 + 16) backtrack-10 +-----------------------------------------第8天 + 17) dynamic-23 + +================================================== + From 653be0229fd5fbe30121050395db5ffcaf592592 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 12 Nov 2020 19:52:06 +0800 Subject: [PATCH 27/63] review-1 --- .../znn/bitmap/test461/Solution.java | 90 +++++++++++-------- .../znn/frequency/test146/LRUCache.java | 2 +- .../algorithm/znn/frequency/test208/Trie.java | 2 +- .../znn/frequency/test48/Solution.java | 10 ++- .../znn/frequency/test7/Solution.java | 9 +- .../znn/frequency/test9/Solution.java | 27 +++--- 6 files changed, 83 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java b/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java index 047e5d5..9ee031e 100644 --- a/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/bitmap/test461/Solution.java @@ -20,49 +20,16 @@ * * @Auther: zhunn * @Date: 2020/11/07 22:23 - * @Description: 汉明距离:1-内置位计数功能;2-移位;3-布赖恩·克尼根算法(x&(x-1)) + * @Description: 汉明距离:0-首选-位运算;1-内置位计数功能;2-移位;3-布赖恩·克尼根算法(x&(x-1)) */ public class Solution { /** - * 1-内置位计数功能 - * * @param x * @param y * @return */ public int hammingDistance(int x, int y) { - return Integer.bitCount(x ^ y); - } - - /** - * 2-移位 - * - * @param x - * @param y - * @return - */ - public int hammingDistance2(int x, int y) { - int dis = x ^ y; - int res = 0; - - while (dis != 0) { - if ((dis & 1) == 1) { - res++; - } - dis = dis >> 1; - } - return res; - } - - /** - * 3-布赖恩·克尼根算法(x&(x-1)) - * - * @param x - * @param y - * @return - */ - public int hammingDistance3(int x, int y) { int dis = x ^ y; int res = 0; while (dis != 0) { @@ -72,10 +39,59 @@ public int hammingDistance3(int x, int y) { return res; } + ///** + // * 1-内置位计数功能 + // * + // * @param x + // * @param y + // * @return + // */ + //public int hammingDistance1(int x, int y) { + // return Integer.bitCount(x ^ y); + //} + // + ///** + // * 2-移位 + // * + // * @param x + // * @param y + // * @return + // */ + //public int hammingDistance2(int x, int y) { + // int dis = x ^ y; + // int res = 0; + // + // while (dis != 0) { + // if ((dis & 1) == 1) { + // res++; + // } + // dis = dis >> 1; + // } + // return res; + //} + // + ///** + // * 3-布赖恩·克尼根算法(x&(x-1)) + // * + // * @param x + // * @param y + // * @return + // */ + //public int hammingDistance3(int x, int y) { + // int dis = x ^ y; + // int res = 0; + // while (dis != 0) { + // res++; + // dis = dis & (dis - 1); + // } + // return res; + //} + @Test public void test() { - System.out.println(hammingDistance(1, 4)); - System.out.println(hammingDistance2(1, 4)); - System.out.println(hammingDistance3(1, 4)); + System.out.println(hammingDistance(1, 7)); + //System.out.println(hammingDistance1(1, 7)); + //System.out.println(hammingDistance2(1, 7)); + //System.out.println(hammingDistance3(1, 7)); } } diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java index 5a9ed32..1a70e0f 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test146/LRUCache.java @@ -33,7 +33,7 @@ * * @Auther: zhunn * @Date: 2020/11/08 14:47 - * @Description: LRU缓存机制:哈希表 + 双向链表 + * @Description: LRU缓存机制:哈希表 + 双向链表(手动实现) */ public class LRUCache { diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java b/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java index 241ec93..a2e33b5 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test208/Trie.java @@ -20,8 +20,8 @@ public class Trie { public Trie root; - public char val; public Trie[] children = new Trie[26]; + public char val; public boolean isWord; public Trie() { diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java index d5f1073..34b9820 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test48/Solution.java @@ -44,7 +44,11 @@ */ public class Solution { - + /** + * 顺时针旋转90°,先转置再反转每一行 + * 逆时针旋转90°,先转置再反转每一列 + * @param matrix + */ public void rotate(int[][] matrix) { int n = matrix.length; @@ -64,8 +68,8 @@ public void rotate(int[][] matrix) { for (int i = 0; i < n; i++) { for (int j = 0; j < m / 2; j++) { int temp = matrix[i][j]; - matrix[i][j] = matrix[i][m - j - 1]; - matrix[i][m - j - 1] = temp; + matrix[i][j] = matrix[i][m - 1 - j]; + matrix[i][m - 1 - j] = temp; } } } diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java index 5c64f07..d1b962f 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test7/Solution.java @@ -1,5 +1,7 @@ package com.chen.algorithm.znn.frequency.test7; +import org.junit.Test; + /** * 7. 整数反转 * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。 @@ -19,7 +21,7 @@ */ public class Solution { - public static int reverse1(int x) { + public int reverse(int x) { int res = 0; while (x != 0) { res = res * 10 + x % 10; @@ -31,7 +33,8 @@ public static int reverse1(int x) { return res; } - public static void main(String[] args) { - System.out.println(reverse1(123)); + @Test + public void test() { + System.out.println(reverse(123)); } } diff --git a/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java b/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java index f38eeb8..1c7764b 100644 --- a/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/frequency/test9/Solution.java @@ -1,5 +1,7 @@ package com.chen.algorithm.znn.frequency.test9; +import org.junit.Test; + /** * 9. 回文数 * 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。 @@ -21,28 +23,29 @@ */ public class Solution { - public static boolean isPalindrome1(int x) { + public boolean isPalindrome(int x) { // 特殊情况: // 当 x < 0 时,x 不是回文数。 // 同样地,如果数字的最后一位是 0,为了使该数字为回文, // 则其第一位数字也应该是 0 // 只有 0 满足这一属性 if (x < 0 || (x != 0 && x % 10 == 0)) return false; - int rev = 0; - while (x > rev) { - rev = rev * 10 + x % 10; + int res = 0; + while (x > res) { + res = res * 10 + x % 10; x /= 10; } // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。 - return rev == x || rev / 10 == x; + return res == x || res / 10 == x; } - public static void main(String[] args) { - System.out.println(isPalindrome1(-121)); - System.out.println(isPalindrome1(0)); - System.out.println(isPalindrome1(1000)); - System.out.println(isPalindrome1(12321)); - System.out.println(isPalindrome1(1221)); - System.out.println(isPalindrome1(1231)); + @Test + public void test() { + System.out.println(isPalindrome(-121)); + System.out.println(isPalindrome(0)); + System.out.println(isPalindrome(1000)); + System.out.println(isPalindrome(12321)); + System.out.println(isPalindrome(1221)); + System.out.println(isPalindrome(1231)); } } From 032af70f960e3f872f1c9cb9dc76b466b57e4015 Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 13 Nov 2020 19:28:43 +0800 Subject: [PATCH 28/63] review-2 --- .../algorithm/znn/hash/test15/Solution.java | 9 +++--- .../algorithm/znn/hash/test18/Solution.java | 1 + src/main/java/com/chen/algorithm/znn/note | 1 + .../chen/algorithm/znn/sort/ChoiceSort.java | 6 +++- .../chen/algorithm/znn/sort/QuickSort.java | 1 + .../algorithm/znn/string/test14/Solution.java | 7 +++-- .../algorithm/znn/string/test3/Solution.java | 9 ++++-- .../znn/string/test415/Solution.java | 5 ++-- .../algorithm/znn/string/test5/Solution.java | 28 +++++++++++-------- 9 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java index 49b4f62..9b88a2c 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test15/Solution.java @@ -7,6 +7,7 @@ import java.util.List; /** + * https://leetcode-cn.com/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/ * 15. 三数之和 * 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 * 注意:答案中不可以包含重复的三元组。 @@ -117,10 +118,10 @@ public List> threeSum2(int[] nums) { Arrays.sort(nums); int len = nums.length; for (int i = 0; i < len; i++) { - if (nums[i] > 0) { // 第一个数大于0,后面的数是递增的,不会有等于0的组合,直接返回结果 + if (nums[i] > 0) { // 剪枝,第一个数大于0,后面的数是递增的,不会有等于0的组合,直接返回结果 return ans; } - if (i > 0 && nums[i] == nums[i - 1]) { // 去重 + if (i > 0 && nums[i] == nums[i - 1]) { // 剪枝,去重 continue; } int L = i + 1; @@ -129,10 +130,10 @@ public List> threeSum2(int[] nums) { int sum = nums[i] + nums[L] + nums[R]; if (sum == 0) { ans.add(Arrays.asList(nums[i], nums[L], nums[R])); - while (L < R && nums[L] == nums[L + 1]) { // 去重 + while (L < R && nums[L] == nums[L + 1]) { // 剪枝去重 L++; } - while (L < R && nums[R] == nums[R - 1]) { // 去重 + while (L < R && nums[R] == nums[R - 1]) { // 剪枝去重 R--; } L++; diff --git a/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java b/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java index 0be7f6f..24311d9 100644 --- a/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/hash/test18/Solution.java @@ -8,6 +8,7 @@ import java.util.List; /** + * https://leetcode-cn.com/problems/4sum/solution/si-shu-zhi-he-by-leetcode-solution/ * 18. 四数之和 * 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。 * 注意: diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 2665814..1c23313 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -33,6 +33,7 @@ 16) backtrack-10 -----------------------------------------第8天 17) dynamic-23 +-----------------------------------------第9天 ================================================== diff --git a/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java b/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java index 561f561..aa928c5 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/ChoiceSort.java @@ -21,13 +21,17 @@ public int[] choiceSort(int[] nums) { int len = nums.length; for (int i = 0; i < len - 1; i++) { // 循环不变量:[0, i) 有序,且该区间里所有元素就是最终排定的样子 - int minIndex = i; // 选择无序区间 [i, len - 1] 里最小的元素的索引,交换到下标 i,即为排序部分的开头 + int minIndex = i; // 选择无序区间 [i, len - 1] 里最小的元素的索引,交换到下标 i,即未排序部分的开头 for (int j = i + 1; j < len; j++) { if (nums[j] < nums[minIndex]) { minIndex = j; } } + if (i == minIndex) { // 索引相同,不交换 + continue; + } + // 交换 int temp = nums[i]; nums[i] = nums[minIndex]; diff --git a/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java b/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java index 4dc493e..31caa1d 100644 --- a/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java +++ b/src/main/java/com/chen/algorithm/znn/sort/QuickSort.java @@ -43,6 +43,7 @@ private int partition(int[] nums, int low, int hight) { } nums[hight] = nums[low]; } + //System.out.println(low==hight); nums[low] = pivotValue; return low; } diff --git a/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java index 00febea..7c5b938 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test14/Solution.java @@ -3,6 +3,7 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/longest-common-prefix/solution/hua-jie-suan-fa-14-zui-chang-gong-gong-qian-zhui-b/ * 14. 最长公共前缀 * 编写一个函数来查找字符串数组中的最长公共前缀。 * 如果不存在公共前缀,返回空字符串 ""。 @@ -28,11 +29,11 @@ public String longestCommonPrefix(String[] strs) { String prefix = strs[0]; for (int i = 1; i < strs.length; i++) { - while (!strs[i].startsWith(prefix)) { - if (prefix.length() == 0) { + while (!strs[i].startsWith(prefix)) { // 如果不包含此前缀,缩小前缀继续比对 + if (prefix.length() == 0) { // 如果前缀长度已缩小为0,仍没有符合的,直接返回空串 return ""; } - prefix = prefix.substring(0, prefix.length() - 1); + prefix = prefix.substring(0, prefix.length() - 1); // 缩小前缀 } } return prefix; diff --git a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java index 8e1fae4..7745116 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java @@ -3,9 +3,12 @@ import org.junit.Test; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /** + * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/hua-jie-suan-fa-3-wu-zhong-fu-zi-fu-de-zui-chang-z/ * 3. 无重复字符的最长子串 * 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 * 示例 1: @@ -24,7 +27,7 @@ * * @Auther: zhunn * @Date: 2020/10/27 16:02 - * @Description: 无重复字符的最长子串 + * @Description: 无重复字符的最长子串:滑动窗口 */ public class Solution { @@ -43,8 +46,8 @@ public int lengthOfLongestSubstring(String s) { start = Math.max(start, map.get(c)); } - ans = Math.max(ans, end - start + 1); - map.put(c, end + 1); + ans = Math.max(ans, end - start + 1); // [start,end]区间内不存在重复字符 + map.put(c, end + 1); // value值为字符位置+1,加1标识从字符位置后一个才开始不重复 } return ans; } diff --git a/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java index 48b88bb..b24882d 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test415/Solution.java @@ -3,6 +3,7 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/add-strings/solution/zi-fu-chuan-xiang-jia-by-leetcode-solution/ * 415. 字符串相加 * 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。 * @@ -13,10 +14,10 @@ public class Solution { public String addStrings(String num1, String num2) { - if (num1 == null) { + if (num1 == null || num1.length() == 0) { return num2; } - if (num2 == null) { + if (num2 == null || num2.length() == 0) { return num1; } diff --git a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java index a2a487b..1715567 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java @@ -3,6 +3,8 @@ import org.junit.Test; /** + * 官方解法:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/ + * https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/ * 5. 最长回文子串 * 给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 * 示例 1: @@ -26,9 +28,9 @@ public class Solution { * * @param s * @return x 表示增量,子串长度, - * 状态转移方程:dp[i][j]表示从i到j的字符串 表示字符串 s 的第 i 到 j 个字母组成的串 + * 状态转移方程:dp[i][j]表示字符串 s 的第 i 到 j 个字母组成的串是否是回文串 */ - public String longestPalindrome1(String s) { + public String longestPalindrome(String s) { if (s == null || s.length() < 2) { return s; } @@ -37,19 +39,23 @@ public String longestPalindrome1(String s) { String ans = ""; boolean[][] dp = new boolean[n][n]; for (int x = 0; x < n; x++) { - for (int i = 0; i + x < n; i++) { + for (int i = 0; i + x < n; i++) { //x 表示增量,子串长度, int j = i + x; - if (x == 0) { + if (x == 0) { //增量是0 dp[i][j] = true; - } else if (x == 1) { + } else if (x == 1) { //增量是1,只有两个字符 dp[i][j] = (s.charAt(i) == s.charAt(j)); } else { - dp[i][j] = (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j)); + dp[i][j] = (dp[i + 1][j - 1] && s.charAt(i) == s.charAt(j)); // 判断c aba c是否是回文串,需判断aba是否是回文串以及左右两边的字符是否相等 } - if (dp[i][j] && x + 1 > ans.length()) { - ans = s.substring(i, i + x + 1); + if (dp[i][j] && j - i + 1 > ans.length()) { // i到j组成的串是回文串,并且回文串的长度是否大于之前的回文串长度 + ans = s.substring(i, j + 1); } + + //if (dp[i][j] && x + 1 > ans.length()) { // 可以将j-i+1替换成x+1,i+x+1替换成j+1,都表示回文串的长度 + // ans = s.substring(i, i + x + 1); + //} } } return ans; @@ -89,9 +95,9 @@ private int expandAroundCenter(String s, int left, int right) { @Test public void test() { System.out.println("123456".substring(0, 3)); - System.out.println(longestPalindrome1("dcacdefd")); - System.out.println(longestPalindrome1("babad")); - System.out.println(longestPalindrome1("cbbd")); + System.out.println(longestPalindrome("dcacdefd")); + System.out.println(longestPalindrome("babad")); + System.out.println(longestPalindrome("cbbd")); } } From 95794c60b9af86d36b1544667352dfec78ebacd2 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 16 Nov 2020 18:51:05 +0800 Subject: [PATCH 29/63] review-2 --- .../znn/array/offer/test29/Solution.java | 9 ++++--- .../algorithm/znn/array/test1/Solution.java | 16 ++++++----- .../algorithm/znn/array/test240/Solution.java | 14 ++++++++++ .../algorithm/znn/array/test56/Solution.java | 27 ++++++++++++++++++- 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java index 0574b23..0942064 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java @@ -1,5 +1,7 @@ package com.chen.algorithm.znn.array.offer.test29; +import org.junit.Test; + import java.util.Arrays; /** @@ -18,7 +20,7 @@ */ public class Solution { - public static int[] spiralOrder(int[][] matrix) { + public int[] spiralOrder(int[][] matrix) { if (matrix.length == 0) { return new int[0]; } @@ -54,7 +56,7 @@ public static int[] spiralOrder(int[][] matrix) { return res; } - private static int[] spiralOrder1(int[][] matrix) { + public int[] spiralOrder1(int[][] matrix) { if (matrix == null || matrix.length == 0) return new int[0]; int numEle = matrix.length * matrix[0].length; @@ -87,7 +89,8 @@ private static int[] spiralOrder1(int[][] matrix) { return result; } - public static void main(String[] args) { + @Test + public void test() { int[][] matrix = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}; int[] res = spiralOrder1(matrix); System.out.println(Arrays.toString(res)); diff --git a/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java index acfc854..596dbba 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test1/Solution.java @@ -21,7 +21,7 @@ */ public class Solution { - public int[] twoSum1(int[] nums, int target) { + public int[] twoSum(int[] nums, int target) { int n = nums.length; for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { @@ -34,12 +34,16 @@ public int[] twoSum1(int[] nums, int target) { } public int[] twoSum2(int[] nums, int target) { - Map hashtable = new HashMap<>(); + if (nums == null || nums.length < 2) { + return new int[0]; + } + + Map map = new HashMap<>(); for (int i = 0; i < nums.length; ++i) { - if (hashtable.containsKey(target - nums[i])) { - return new int[]{hashtable.get(target - nums[i]), i}; + if (map.containsKey(target - nums[i])) { + return new int[]{map.get(target - nums[i]), i}; } - hashtable.put(nums[i], i); + map.put(nums[i], i); } return new int[0]; } @@ -48,7 +52,7 @@ public int[] twoSum2(int[] nums, int target) { public void testCase() { int[] array = {4, 5, 6, 7, 2}; - int[] result = twoSum1(array, 9); + int[] result = twoSum2(array, 9); System.out.println(JSON.toJSONString(result)); } diff --git a/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java index 13ae883..8d60afb 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test240/Solution.java @@ -1,5 +1,7 @@ package com.chen.algorithm.znn.array.test240; +import org.junit.Test; + /** * https://leetcode-cn.com/problems/search-a-2d-matrix-ii/solution/er-fen-fa-pai-chu-fa-python-dai-ma-java-dai-ma-by-/ * 240. 搜索二维矩阵 II @@ -71,4 +73,16 @@ public boolean searchMatrix(int[][] matrix, int target) { } + @Test + public void test() { + int[][] matrix = { + {1, 4, 7, 11, 15}, + {2, 5, 8, 12, 19}, + {3, 6, 9, 16, 22}, + {10, 13, 14, 17, 24}, + {18, 21, 23, 26, 30} + }; + System.out.println(searchMatrix(matrix, 5)); + System.out.println(searchMatrix(matrix, 20)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java index 88ff8a5..6b5572e 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; /** @@ -68,12 +69,36 @@ public int[][] merge(int[][] intervals) { return array; } + public int[][] merge1(int[][] intervals) { + if (intervals == null || intervals.length == 0) { + return null; + } + + //Arrays.sort(intervals, new Comparator() { + // @Override + // public int compare(int[] o1, int[] o2) { + // return o1[0] - o2[0]; + // } + //}); + Arrays.sort(intervals, Comparator.comparingInt(o -> o[0])); + + List merged = new ArrayList<>(); + for (int i = 0; i < intervals.length; i++) { + int L = intervals[i][0], R = intervals[i][1]; + if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < L) { + merged.add(new int[]{L, R}); + } else { + merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R); + } + } + return merged.toArray(new int[merged.size()][]); + } @Test public void testCase() { int[][] n = {{1, 3}, {2, 6}, {15, 18}, {8, 10}}; - System.out.println(JSONObject.toJSONString(merge(n))); + System.out.println(JSONObject.toJSONString(merge1(n))); } } From 22831eb67fed41536f75a8a6ad6c5cf3eb371c66 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 17 Nov 2020 15:43:34 +0800 Subject: [PATCH 30/63] review-3 --- .../algorithm/znn/array/test448/Solution.java | 56 ++++++++++++++----- .../algorithm/znn/array/test581/Solution.java | 30 +++++++--- .../algorithm/znn/array/test674/Solution.java | 11 +++- .../algorithm/znn/array/test704/Solution.java | 21 ++++--- 4 files changed, 84 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java index ccd2825..97233be 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test448/Solution.java @@ -19,35 +19,34 @@ * * @author: zhunn * @Date: 2020-10-04 00:06 - * @@Description: zhunn 找到所有数组中消失的数字 + * @@Description: zhunn 找到所有数组中消失的数字:迭代并赋值为负数 */ public class Solution { public List findDisappearedNumbers(int[] nums) { - - int temp = 0; - int nextIndex = 0; + if (nums == null || nums.length == 0) { + return null; + } for (int i = 0; i < nums.length; i++) { + if (nums[i] < 0) { + continue; + } - if (nums[i] > 0) { - temp = nums[i]; - while (temp > 0) { - nums[i] = 0; - nextIndex = nums[temp - 1]; - nums[temp - 1] = -1; - temp = nextIndex; - } + int temp = nums[i]; + while (temp > 0) { + int nextIndex = nums[temp - 1]; + nums[temp - 1] = -1; + temp = nextIndex; } } - List result = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { - if (nums[i] == 0) { + if (nums[i] > 0) { result.add(i + 1); } } @@ -55,6 +54,34 @@ public List findDisappearedNumbers(int[] nums) { return result; } + /** + * 官方解法 + * + * @param nums + * @return + */ + public List findDisappearedNumbers1(int[] nums) { + if (nums == null || nums.length == 0) { + return null; + } + + for (int i = 0; i < nums.length; i++) { + int newIndex = Math.abs(nums[i]) - 1; + if (nums[newIndex] > 0) { + nums[newIndex] *= -1; + } + } + + List result = new ArrayList<>(); + for (int i = 1; i <= nums.length; i++) { + if (nums[i - 1] > 0) { + result.add(i); + } + } + + return result; + } + @Test public void testCase() { @@ -66,5 +93,4 @@ public void testCase() { } - } diff --git a/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java index ac5bd0b..bfff8c5 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test581/Solution.java @@ -16,7 +16,7 @@ * * @author: zhunn * @Date: 2020-10-07 23:34 - * @Description: 最短无序连续子数组 + * @Description: 最短无序连续子数组:排序对比原数组 */ public class Solution { @@ -29,25 +29,41 @@ public int findUnsortedSubarray(int[] nums) { int[] snums = nums.clone(); Arrays.sort(snums); int start = snums.length, end = 0; + + for (int i = 0; i < snums.length; i++) { + if (snums[i] == nums[i]) { + continue; + } + start = Math.min(start, i); + end = Math.max(end, i); + } + return (end - start >= 0 ? end - start + 1 : 0); + } + + public int findUnsortedSubarray2(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + int[] snums = nums.clone(); + Arrays.sort(snums); + int start = snums.length, end = 0; + for (int i = 0; i < snums.length; i++) { if (snums[i] != nums[i]) { start = Math.min(start, i); end = Math.max(end, i); } } - return (end - start >= 0 ? end - start + 1 : 0); + return (end - start) < 0 ? 0 : end - start + 1; } - @Test public void testCase() { - - int[] n = {2, 6, 4, 8, 10, 9, 15}; System.out.println(findUnsortedSubarray(n)); - - + System.out.println(findUnsortedSubarray2(n)); } diff --git a/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java index b014ef3..aa60736 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test674/Solution.java @@ -24,12 +24,17 @@ public class Solution { public int findLengthOfLCIS(int[] nums) { - int res = 0, anchor = 0; + if (nums == null || nums.length == 0) { + return 0; + } + + int res = 0, start = 0; + for (int i = 0; i < nums.length; i++) { if (i > 0 && nums[i - 1] >= nums[i]) { - anchor = i; + start = i; } - res = Math.max(res, i - anchor + 1); + res = Math.max(res, i - start + 1); } return res; } diff --git a/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java index 8197937..1fce82d 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test704/Solution.java @@ -1,5 +1,7 @@ package com.chen.algorithm.znn.array.test704; +import org.junit.Test; + /** * 704. 二分查找 * 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 @@ -21,7 +23,7 @@ public class Solution { /** * 适用于升序数组,可做相应调整适用降序数组 */ - public static int bsearch(int[] array, int target) { + public int bsearch(int[] array, int target) { if (array == null || array.length == 0 /*|| target < array[0] || target > array[array.length - 1]*/) { return -1; @@ -51,7 +53,7 @@ public static int bsearch(int[] array, int target) { * 查找第一个与target相等的元素 * 当key=array[mid]时, 往左边一个一个逼近,right = mid -1; 返回left */ - public static int bsearch1(int[] array, int target) { + public int bsearch1(int[] array, int target) { if (array == null || array.length == 0 /*|| target < array[0] || target > array[array.length - 1]*/) { return -1; @@ -80,7 +82,7 @@ public static int bsearch1(int[] array, int target) { * * @return */ - public static int bsearch2(int[] array, int target) { + public int bsearch2(int[] array, int target) { if (array == null || array.length == 0 /*|| target < array[0] || target > array[array.length - 1]*/) { return -1; } @@ -123,7 +125,7 @@ public static int bsearch2(int[] array, int target) { /** * 查找第一个等于或者大于key的元素 */ - public static int bsearch3(int[] array, int target) { + public int bsearch3(int[] array, int target) { if (array == null || array.length == 0) { return -1; } @@ -143,7 +145,7 @@ public static int bsearch3(int[] array, int target) { /** * 查找第一个大于key的元素 */ - public static int bsearch4(int[] array, int target) { + public int bsearch4(int[] array, int target) { if (array == null || array.length == 0) { return -1; } @@ -163,7 +165,7 @@ public static int bsearch4(int[] array, int target) { /** * 查找最后一个等于或者小于key的元素 */ - public static int bsearch5(int[] array, int target) { + public int bsearch5(int[] array, int target) { if (array == null || array.length == 0) { return -1; } @@ -183,7 +185,7 @@ public static int bsearch5(int[] array, int target) { /** * 查找最后一个小于key的元素 */ - public static int bsearch6(int[] array, int target) { + public int bsearch6(int[] array, int target) { if (array == null || array.length == 0) { return -1; } @@ -200,9 +202,10 @@ public static int bsearch6(int[] array, int target) { return right; } - public static void main(String[] args) { + @Test + public void test() { int[] array = {1, 1, 3, 6, 6, 6, 7, 9, 17, 17}; - int index = bsearch6(array, 0); + int index = bsearch6(array, 6); System.out.println(index); } } From b1561ada082539b8a9b160099191d0b4926d2ff8 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 17 Nov 2020 17:09:45 +0800 Subject: [PATCH 31/63] note --- .../znn/linkedlist/test19/Solution.java | 2 +- .../znn/linkedlist/test21/Solution.java | 2 +- .../algorithm/znn/stack/test155/Solution.java | 17 +++++++++++++++++ .../algorithm/znn/stack/test703/Solution.java | 4 ++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java index 23c009e..015b4ee 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java @@ -15,7 +15,7 @@ * * @Auther: zhunn * @Date: 2020/10/22 14:51 - * @Description: 1、遍历length-n+1;2、栈、3、双指针法 + * @Description: 删除链表的倒数第N个节点 1、遍历length-n+1;2、栈、3、双指针法 */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java index cf22515..ebbd0cf 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java @@ -12,7 +12,7 @@ * * @Author: zhunn * @Date: 2020-09-06 01:43 - * @Description: 并两个有序链表 + * @Description: 合并两个有序链表 */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java index 437b92c..5a5aecc 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java @@ -1,5 +1,7 @@ package com.chen.algorithm.znn.stack.test155; +import org.junit.Test; + import java.util.Stack; /** @@ -55,4 +57,19 @@ public int top() { public int getMin() { return minStack.peek(); } + + @Test + public void test() { + Solution minStack = new Solution(); + minStack.push(-2); + minStack.push(0); + minStack.push(-3); + int minRes = minStack.getMin(); + System.out.println(minRes); + minStack.pop(); + int topRes = minStack.top(); + System.out.println(topRes); + int minRes2 = minStack.getMin(); + System.out.println(minRes2); + } } diff --git a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java index 24f4972..a27dc29 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java @@ -45,10 +45,10 @@ public KthLargest(int size, int[] nums) { public int add(int num) { if (queue.size() < limit) { - queue.offer(num); + queue.add(num); } else if (queue.peek() < num) { queue.poll(); - queue.offer(num); + queue.add(num); } return queue.peek(); From ddd4d3b7cec5cff21ce03ca06d40a809635c9870 Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 17 Nov 2020 18:17:10 +0800 Subject: [PATCH 32/63] note --- src/main/java/com/chen/algorithm/znn/note | 144 ++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 1c23313..91222bb 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -37,3 +37,147 @@ ================================================== + + +======================================================================================================================== +frequency +7. 整数反转 *** +9. 回文数 *** +48. 旋转图像 ???? 先转置再反转行 +146. LRU缓存机制 *** +208. 实现 Trie (前缀树) + +bitmap 位运算 +136. 只出现一次的数字 *** +191. 位1的个数 *** +231. 2的幂 *** +338. 比特位计数 *** +461. 汉明距离 *** + +sort +冒泡排序 sort/BubbleSort (n2 稳定) *** +选择排序 sort/ChoiceSort (n2 稳定) *** +插入排序 sort/InsertSort (n2 不稳定) *** +归并排序 sort/MergeSort (nlogn 稳定,非原地排序) *** +快速排序 sort/QuickSort (nlogn 不稳定)** + +string +3. 无重复字符的最长子串 *** 滑动窗口 +5. 最长回文子串 动态规划 +14. 最长公共前缀 *** +415. 字符串相加 + +hash +15. 三数之和 *** 排序+双指针 +18. 四数之和 ??? 排序+双指针 +49. 字母异位词分组 *** 排序+map +242. 有效的字母异位词 *** 哈希表 + +array +剑指 Offer 29. 顺时针打印矩阵 left right top bottom +剑指 Offer 57 - II. 和为s的连续正数序列 滑动窗口法 +1. 两数之和 +11. 盛最多水的容器 双指针 +26. 删除排序数组中的重复项 双指针,return i+1; +27. 移除元素 双指针,return i; +34. 在排序数组中查找元素的第一个和最后一个位置 二分查找 +56. 合并区间 排序 +69. x 的平方根 *** 二分法 +88. 合并两个有序数组 *** +238. 除自身以外数组的乘积 先求出左右两边的乘积再相乘 +240. 搜索二维矩阵 II 从左下角开始 +283. 移动零 双指针(方法同27题移除元素) +287. 寻找重复数 排序迭代/快慢指针 +448. 找到所有数组中消失的数字 迭代并赋值为-1 +581. 最短无序连续子数组 排序迭代对比 +674. 最长连续递增序列 *** 滑动窗口 +704. 二分查找 *** + +heap/Heap +堆的基本操作:堆化,大根堆,小根堆,堆排序 +215. 数组中的第K个最大元素 *** +347. 前K个高频元素 *** + +stack/queue +20 有效的括号 *** +155. 最小栈 *** +225. 用队列实现栈 *** +227. 基本计算器 II *** +232 用栈实现队列 *** +239. 滑动窗口最大值 *** ??? +496. 下一个更大元素 I *** +703. 数据流中的第K大元素 *** + +tree +94. 二叉树的中序遍历 +144. 二叉树的前序遍历 ***** +145. 后序遍历二叉树 递归、迭代实现 +102. 二叉树的层序遍历 ***** +107. 二叉树的层次遍历 II ***** +103. 二叉树的锯齿形层次遍历 ***** +104. 二叉树的最大深度 *** +111. 二叉树的最小深度 *** +543. 二叉树的直径 +112. 路径总和 *** +113. 路径之和 II *** +437. 路径之和 III *** +101. 对称二叉树 ***** +226. 翻转二叉树 ***** +617. 合并二叉树 +199. 二叉树的右视图 ***** +96. 不同的二叉搜索树 +98. 验证二叉搜索树??? +235. 二叉搜索树的最近公共祖先 ***** +236. 二叉树的最近公共祖先 *** +538. 把二叉搜索树转换为累加树 + +recursion +汉诺塔问题 HanNuoTa +172. 阶乘后的零 *** (打印阶乘 Recursion) + +bfs + +dfs +22. 括号生成 *** + +divide +50. Pow(x, n) *** +169. 多数元素 *** + +greedy +122. 买卖股票的最佳时机 II *** +55. 跳跃游戏 + + +backtrack +36. 有效的数独 +39. 组合总和 *** +40. 组合总和 II *** +46. 全排列 *** +47. 全排列II *** +51. N皇后 *** ?? +79. 单词搜索 ???? +78. 子集 *** +90. 子集II*** +0-1背包问题 /backtrack/ZeroOneBag + +dynamic +0-1背包问题 /dynamicprogramming/ZeroOndBag3 +70. 爬楼梯 *** +120. 三角形最小路径和 *** +64. 最小路径和 *** +121、122、123、188、309、714 股票买卖系列 *** +53. 最大子序和 *** +152. 乘积最大子数组*** +300. 最长上升子序列 *** +322. 零钱兑换、 518.零钱兑换 II *** +72. 编辑距离 *** +62. 不同路径 *** +279. 完全平方数 *** +343. 整数拆分 *** +416. 分割等和子集 *** +474. 一和零 *** +494. 目标和 *** +198. 打家劫舍 *** +213. 打家劫舍 II *** +337. 打家劫舍 III *** \ No newline at end of file From 39bc7d583d168e1e60625009f4edbd9f9025d658 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 19 Nov 2020 18:48:08 +0800 Subject: [PATCH 33/63] review-4 --- .../algorithm/znn/heap/test215/Solution.java | 4 +- .../algorithm/znn/heap/test347/Solution.java | 2 +- .../test703/KthLargest.java} | 47 ++++++++----------- src/main/java/com/chen/algorithm/znn/note | 26 +++++----- .../algorithm/znn/stack/test155/Solution.java | 11 +++-- .../algorithm/znn/stack/test225/MyStack.java | 2 +- .../algorithm/znn/stack/test232/Solution.java | 17 ++++--- 7 files changed, 51 insertions(+), 58 deletions(-) rename src/main/java/com/chen/algorithm/znn/{stack/test703/Solution.java => heap/test703/KthLargest.java} (59%) diff --git a/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java index 1ddb706..9d3125f 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/heap/test215/Solution.java @@ -16,7 +16,7 @@ * * @Auther: zhunn * @Date: 2020/10/26 16:55 - * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 + * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 PriorityQueue-小根堆 */ public class Solution { @@ -39,7 +39,7 @@ public int findKthLargest1(int[] nums, int k) { } public int findKthLargest(int[] nums, int k) { - PriorityQueue queue = new PriorityQueue<>(k); + PriorityQueue queue = new PriorityQueue<>(k); //小根堆 for (int i = 0; i < nums.length; i++) { if (queue.size() < k) { queue.add(nums[i]); diff --git a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java index 0959cfe..b3e0910 100644 --- a/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/heap/test347/Solution.java @@ -31,7 +31,7 @@ public int[] topKFrequent(int[] nums, int k) { } } - //PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(map::get)); + //PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(key -> map.get(key))); PriorityQueue queue = new PriorityQueue<>(new Comparator() { @Override public int compare(Integer o1, Integer o2) { diff --git a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java b/src/main/java/com/chen/algorithm/znn/heap/test703/KthLargest.java similarity index 59% rename from src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java rename to src/main/java/com/chen/algorithm/znn/heap/test703/KthLargest.java index a27dc29..7fea049 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test703/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/heap/test703/KthLargest.java @@ -1,6 +1,4 @@ -package com.chen.algorithm.znn.stack.test703; - -import org.junit.Test; +package com.chen.algorithm.znn.heap.test703; import java.util.PriorityQueue; @@ -28,39 +26,34 @@ * @Date: 2020/10/26 16:55 * @Description: 求数组中的第K个最大元素:1-暴力;2-优先级队列 */ -public class Solution { +public class KthLargest { - class KthLargest { - private PriorityQueue queue; - private int limit; + private PriorityQueue queue; + private int limit; - public KthLargest(int size, int[] nums) { - this.limit = size; - queue = new PriorityQueue<>(limit); - for (int num : nums) { - add(num); - } + public KthLargest(int size, int[] nums) { + this.limit = size; + queue = new PriorityQueue<>(limit); + for (int num : nums) { + add(num); } + } - public int add(int num) { - - if (queue.size() < limit) { - queue.add(num); - } else if (queue.peek() < num) { - queue.poll(); - queue.add(num); - } + public int add(int num) { - return queue.peek(); + if (queue.size() < limit) { + queue.add(num); + } else if (queue.peek() < num) { + queue.poll(); + queue.add(num); } - } + return queue.peek(); + } - @Test - public void testCase() { + public static void main(String[] args) { int[] n = {3, 2, 3, 1, 2, 4, 5, 5, 6}; - KthLargest kthLargest = new KthLargest(2, n); + KthLargest kthLargest = new KthLargest(3, n); System.out.println(kthLargest.add(3)); - } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 91222bb..7589125 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -17,8 +17,8 @@ -----------------------------------------第2天 第二类:6) array-18 -----------------------------------------第3天 - 7) heap-2 - 8) stack-8 + 7) heap-3 + 8) stack-7 -----------------------------------------第4天 9) linkedlist-11 -----------------------------------------第5天 @@ -44,7 +44,7 @@ frequency 7. 整数反转 *** 9. 回文数 *** 48. 旋转图像 ???? 先转置再反转行 -146. LRU缓存机制 *** +146. LRU缓存机制 *** 双向链表 + HashMap 208. 实现 Trie (前缀树) bitmap 位运算 @@ -80,33 +80,33 @@ array 11. 盛最多水的容器 双指针 26. 删除排序数组中的重复项 双指针,return i+1; 27. 移除元素 双指针,return i; +283. 移动零 双指针(方法同27题移除元素) 34. 在排序数组中查找元素的第一个和最后一个位置 二分查找 56. 合并区间 排序 69. x 的平方根 *** 二分法 -88. 合并两个有序数组 *** +88. 合并两个有序数组 *** p1,p2,p3=p1+p2 238. 除自身以外数组的乘积 先求出左右两边的乘积再相乘 240. 搜索二维矩阵 II 从左下角开始 -283. 移动零 双指针(方法同27题移除元素) 287. 寻找重复数 排序迭代/快慢指针 -448. 找到所有数组中消失的数字 迭代并赋值为-1 +448. 找到所有数组中消失的数字 迭代并赋值为-1,最后大于0的既满足(数组中数都大于0) 581. 最短无序连续子数组 排序迭代对比 674. 最长连续递增序列 *** 滑动窗口 704. 二分查找 *** heap/Heap 堆的基本操作:堆化,大根堆,小根堆,堆排序 -215. 数组中的第K个最大元素 *** -347. 前K个高频元素 *** +215. 数组中的第K个最大元素 *** 优先级队列 PriorityQueue-小根堆,比较元素默认int的自然升序排序 +347. 前K个高频元素 *** PriorityQueue-小根堆,自定义比较器比较频次 +703. 数据流中的第K大元素 *** 优先级队列 PriorityQueue-小根堆,创建类和两个属性 limit 和 queue,构造函数构造好初始数据 stack/queue -20 有效的括号 *** -155. 最小栈 *** -225. 用队列实现栈 *** +20. 有效的括号 *** 栈+HashMap +155. 最小栈 *** 维护两个栈,增删-合理操作两个栈,获取操作相应栈 +225. 用队列实现栈 *** q2入栈,q1出栈(注意入栈逻辑) +232. 用栈实现队列 *** s1入队列,s2出队列(注意出队列逻辑) 227. 基本计算器 II *** -232 用栈实现队列 *** 239. 滑动窗口最大值 *** ??? 496. 下一个更大元素 I *** -703. 数据流中的第K大元素 *** tree 94. 二叉树的中序遍历 diff --git a/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java index 5a5aecc..925efd5 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test155/Solution.java @@ -37,25 +37,26 @@ public class Solution { public Stack minStack = new Stack<>(); public void push(Integer value) { - stack.push(value); + stack.push(value); // 元素存入基础栈 - if (minStack.isEmpty() || value < minStack.peek()) { + if (minStack.isEmpty() || value < minStack.peek()) { // 元素满足条件就存入最小栈,比最小栈栈顶元素小也存入 minStack.push(value); } } public void pop() { - if (stack.pop().equals(minStack.peek())) { + + if (stack.pop().equals(minStack.peek())) { // 删除基础栈 栈顶元素,如果最小栈栈顶元素等于被删除的元素,一并删除。 minStack.pop(); } } public int top() { - return stack.peek(); + return stack.peek(); // 取出的是基础栈的栈顶元素 } public int getMin() { - return minStack.peek(); + return minStack.peek(); // 获取的是最小栈的栈顶元素 } @Test diff --git a/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java b/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java index 8473d13..ee6536b 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test225/MyStack.java @@ -17,7 +17,7 @@ * * @Auther: zhunn * @Date: 2020/10/26 22:20 - * @Description: 用两个队列实现一个栈, 官方解法 + * @Description: 用两个队列实现一个栈, 官方解法:q2入栈,q1出栈(注意入栈逻辑) */ public class MyStack { diff --git a/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java index 96fa76b..90f92cc 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test232/Solution.java @@ -31,14 +31,18 @@ * * @Auther: zhunn * @Date: 2020/10/26 17:36 - * @Description: 用栈实现队列 + * @Description: 用栈实现队列: s1入队列,s2出队列(注意出队列逻辑) */ public class Solution { private Stack stack1 = new Stack<>(); private Stack stack2 = new Stack<>(); + private int front; public void push(Integer value) { + if (stack1.isEmpty()) { + front = value; + } stack1.push(value); } @@ -56,16 +60,11 @@ public Integer pop() { } public Integer peek() { - if (stack1.isEmpty() && stack2.isEmpty()) { - return null; + if (!stack2.isEmpty()) { + return stack2.peek(); } - if (stack2.isEmpty()) { - while (!stack1.isEmpty()) { - stack2.push(stack1.pop()); - } - } - return stack2.peek(); + return front; } public boolean empty() { From aec297d2102adba21fa74a4a947ac27e2ac48cad Mon Sep 17 00:00:00 2001 From: chenweijie Date: Mon, 23 Nov 2020 00:26:45 +0800 Subject: [PATCH 34/63] stack --- src/main/java/com/chen/algorithm/znn/note | 16 +++++++++++++++- .../algorithm/znn/stack/test227/Solution.java | 8 +++++--- .../algorithm/znn/stack/test239/Solution.java | 7 +++---- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 7589125..9039ac9 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -108,6 +108,20 @@ stack/queue 239. 滑动窗口最大值 *** ??? 496. 下一个更大元素 I *** +linkedlist +2. 两数相加 *** +21. 合并两个有序链表 *** +19. 删除链表的倒数第N个节点 *** +83. 删除排序链表中的重复元素 *** +24. 两两交换链表中的节点 *** +206. 反转链表 ******* +92. 反转链表 II +25 K 个一组翻转链表 ??? +160 相交链表 *** +141 环形链表 *** +142 环形链表 II *** +//148. 排序链表 + tree 94. 二叉树的中序遍历 144. 二叉树的前序遍历 ***** @@ -166,7 +180,7 @@ dynamic 70. 爬楼梯 *** 120. 三角形最小路径和 *** 64. 最小路径和 *** -121、122、123、188、309、714 股票买卖系列 *** +121、(122)、123、188、309、714 股票买卖系列 *** 53. 最大子序和 *** 152. 乘积最大子数组*** 300. 最长上升子序列 *** diff --git a/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java index b79ef8d..06ac6c3 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test227/Solution.java @@ -5,6 +5,7 @@ import java.util.Stack; /** + * https://leetcode-cn.com/problems/basic-calculator-ii/solution/chai-jie-fu-za-wen-ti-shi-xian-yi-ge-wan-zheng-ji-/ * 227. 基本计算器 II * 实现一个基本的计算器来计算一个简单的字符串表达式的值。 * 字符串表达式仅包含非负整数,+, - ,*,/ 四种运算符和空格 。 整数除法仅保留整数部分。 @@ -39,15 +40,15 @@ public int calculate(String s) { } Stack stack = new Stack<>(); - char sign = '+'; - int num = 0; + char sign = '+'; // 记录 num 前的符号,初始化为 + + int num = 0; // 记录算式中的数字 for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (Character.isDigit(c)) { num = num * 10 + (c - '0'); } - if ((!Character.isDigit(c) && c != ' ') || i == s.length() - 1) { + if ((!Character.isDigit(c) && c != ' ') || i == s.length() - 1) { //不只是遇到新的符号会触发入栈,当i走到了算式的尽头(i == s.size() - 1),也应该将前面的数字入栈,方便后续计算最终结果。 int pre; if (sign == '+') { stack.push(num); @@ -77,4 +78,5 @@ public void test() { System.out.println(calculate("60+20-30+5/2 ")); } + } diff --git a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java index b180f34..e9ecdec 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java @@ -7,6 +7,7 @@ import java.util.LinkedList; /** + * https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-2/ * 239. 滑动窗口最大值 * 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 * 返回滑动窗口中的最大值。 @@ -40,9 +41,7 @@ public class Solution { * @return */ public int[] maxSlidingWindow(int[] nums, int k) { - int n = nums.length; - if (n * k == 0) return new int[0]; - if (k == 1) return nums; + if (nums == null || nums.length < 2) return nums; int[] res = new int[nums.length - k + 1]; // 递减队列 @@ -70,7 +69,7 @@ public int[] maxSlidingWindow(int[] nums, int k) { } /** - * 采用双端队列存储数组下标 + * 采用双端队列存储数组下标 (推荐) * https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-2/ * * @param nums From 3ef783731cb34990a2ae09ba71d852667acc42a2 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 23 Nov 2020 19:08:23 +0800 Subject: [PATCH 35/63] note --- src/main/java/com/chen/algorithm/znn/note | 2 +- .../algorithm/znn/stack/test239/Solution.java | 132 +++++++++--------- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 9039ac9..15b9fb5 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -104,7 +104,7 @@ stack/queue 155. 最小栈 *** 维护两个栈,增删-合理操作两个栈,获取操作相应栈 225. 用队列实现栈 *** q2入栈,q1出栈(注意入栈逻辑) 232. 用栈实现队列 *** s1入队列,s2出队列(注意出队列逻辑) -227. 基本计算器 II *** +227. 基本计算器 II *** 加减直接入栈正数或负数,乘除先取出栈顶元素乘以或除以新元素,将结果入栈 239. 滑动窗口最大值 *** ??? 496. 下一个更大元素 I *** diff --git a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java index e9ecdec..2116547 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java @@ -17,14 +17,14 @@ * 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3 * 输出: [3,3,5,5,6,7] * 解释: - * 滑动窗口的位置 最大值 + * 滑动窗口的位置 最大值 * --------------- ----- * [1 3 -1] -3 5 3 6 7 3 - * 1 [3 -1 -3] 5 3 6 7 3 - * 1 3 [-1 -3 5] 3 6 7 5 - * 1 3 -1 [-3 5 3] 6 7 5 - * 1 3 -1 -3 [5 3 6] 7 6 - * 1 3 -1 -3 5 [3 6 7] 7 + * 1 [3 -1 -3] 5 3 6 7 3 + * 1 3 [-1 -3 5] 3 6 7 5 + * 1 3 -1 [-3 5 3] 6 7 5 + * 1 3 -1 -3 [5 3 6] 7 6 + * 1 3 -1 -3 5 [3 6 7] 7 * * @Auther: zhunn * @Date: 2020/10/27 14:32 @@ -45,7 +45,7 @@ public int[] maxSlidingWindow(int[] nums, int k) { int[] res = new int[nums.length - k + 1]; // 递减队列 - ArrayDeque queue = new ArrayDeque<>(); + LinkedList queue = new LinkedList<>(); for (int i = 0; i < nums.length; i++) { @@ -61,75 +61,75 @@ public int[] maxSlidingWindow(int[] nums, int k) { } // 写入当前最大值 - if (i >= k - 1) { - res[i - k + 1] = queue.peekFirst(); - } - } - return res; - } - - /** - * 采用双端队列存储数组下标 (推荐) - * https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-2/ - * - * @param nums - * @param k - * @return - */ - public int[] maxSlidingWindow1(int[] nums, int k) { - if (nums == null || nums.length < 2) return nums; - // 双向队列 保存当前窗口最大值的数组位置 保证队列中数组位置的数值按从大到小排序 - LinkedList queue = new LinkedList(); - // 结果数组 - int[] result = new int[nums.length - k + 1]; - // 遍历nums数组 - for (int i = 0; i < nums.length; i++) { - // 保证从大到小 如果前面数小则需要依次弹出,直至满足要求 - while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { - queue.pollLast(); - } - // 添加当前值对应的数组下标 - queue.addLast(i); - // 判断当前队列中队首的值是否有效 - if (queue.peek() <= i - k) { - queue.poll(); - } - // 当窗口长度为k时 保存当前窗口中最大值 if (i + 1 >= k) { - result[i + 1 - k] = nums[queue.peek()]; - } - } - return result; - } - - public int[] maxSlidingWindow2(int[] nums, int k) { - if (nums == null || nums.length < 2) { - return nums; - } - - LinkedList queue = new LinkedList<>(); - int[] res = new int[nums.length - k + 1]; - for (int i = 0; i < nums.length; i++) { - while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { - queue.pollLast(); - } - queue.addLast(i); - if (queue.peekFirst() <= i - k) { - queue.pollFirst(); - } - - if (i + 1 >= k) { - res[i + 1 - k] = nums[queue.peekFirst()]; + res[i + 1 - k] = queue.peekFirst(); } } return res; } + ///** + // * 采用双端队列存储数组下标 (推荐) + // * https://leetcode-cn.com/problems/sliding-window-maximum/solution/shuang-xiang-dui-lie-jie-jue-hua-dong-chuang-kou-2/ + // * + // * @param nums + // * @param k + // * @return + // */ + //public int[] maxSlidingWindow1(int[] nums, int k) { + // if (nums == null || nums.length < 2) return nums; + // // 双向队列 保存当前窗口最大值的数组位置 保证队列中数组位置的数值按从大到小排序 + // LinkedList queue = new LinkedList(); + // // 结果数组 + // int[] result = new int[nums.length - k + 1]; + // // 遍历nums数组 + // for (int i = 0; i < nums.length; i++) { + // // 保证从大到小 如果前面数小则需要依次弹出,直至满足要求 + // while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { + // queue.pollLast(); + // } + // // 添加当前值对应的数组下标 + // queue.addLast(i); + // // 判断当前队列中队首的值是否有效 + // if (queue.peek() <= i - k) { + // queue.poll(); + // } + // // 当窗口长度为k时 保存当前窗口中最大值 + // if (i + 1 >= k) { + // result[i + 1 - k] = nums[queue.peek()]; + // } + // } + // return result; + //} + // + //public int[] maxSlidingWindow2(int[] nums, int k) { + // if (nums == null || nums.length < 2) { + // return nums; + // } + // + // LinkedList queue = new LinkedList<>(); + // int[] res = new int[nums.length - k + 1]; + // for (int i = 0; i < nums.length; i++) { + // while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) { + // queue.pollLast(); + // } + // queue.addLast(i); + // if (queue.peekFirst() <= i - k) { + // queue.pollFirst(); + // } + // + // if (i + 1 >= k) { + // res[i + 1 - k] = nums[queue.peekFirst()]; + // } + // } + // return res; + //} + @Test public void testCase() { int[] nums = {1, 3, -1, -3, 5, 3, 2, 6, 7}; int k = 3; - System.out.println(Arrays.toString(maxSlidingWindow2(nums, k))); + System.out.println(Arrays.toString(maxSlidingWindow(nums, k))); } } From d029ab7299103bc90dd1cae15df592f5c53bcf06 Mon Sep 17 00:00:00 2001 From: zhunn Date: Wed, 25 Nov 2020 19:12:25 +0800 Subject: [PATCH 36/63] review-5 --- .../znn/linkedlist/test19/Solution.java | 4 +- .../znn/linkedlist/test206/Solution.java | 19 +++---- .../znn/linkedlist/test21/Solution.java | 20 +++----- .../znn/linkedlist/test24/Solution.java | 26 +++++----- .../znn/linkedlist/test25/Solution.java | 50 ++++++++++++++++--- .../znn/linkedlist/test83/Solution.java | 20 +++++++- .../znn/linkedlist/test92/Solution.java | 42 +++++++++------- src/main/java/com/chen/algorithm/znn/note | 20 ++++---- .../algorithm/znn/stack/test239/Solution.java | 22 ++++++++ .../algorithm/znn/stack/test496/Solution.java | 24 ++++++++- 10 files changed, 172 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java index 015b4ee..fa7bd2b 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test19/Solution.java @@ -15,7 +15,7 @@ * * @Auther: zhunn * @Date: 2020/10/22 14:51 - * @Description: 删除链表的倒数第N个节点 1、遍历length-n+1;2、栈、3、双指针法 + * @Description: 删除链表的倒数第N个节点 1、遍历length-n+1;2、栈、3、双指针法(推荐) */ public class Solution { @@ -70,7 +70,7 @@ public ListNode removeNthFromEnd2(ListNode head, int n) { } /** - * 双指针法 + * 双指针法 (推荐) * * @param head 头结点 * @param n 删除倒数第几个 diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java index 35d42b7..014b771 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test206/Solution.java @@ -12,11 +12,11 @@ * * @Auther: zhunn * @Date: 2020/10/22 17:23 - * @Description: 反转链表:1-迭代法,2-递归 + * @Description: 反转链表:1-双指针法(推荐),2-递归 */ public class Solution { - public ListNode reverseList1(ListNode head) { + public ListNode reverseList(ListNode head) { if (head == null || head.next == null) { return head; } @@ -25,8 +25,8 @@ public ListNode reverseList1(ListNode head) { ListNode curr = head; while (curr != null) { ListNode nextTemp = curr.next; - curr.next = pre; - pre = curr; + curr.next = pre; // 当前指针的next指向前一个,链表指针反转 + pre = curr; // pre和curr指针向后推进 curr = nextTemp; } @@ -50,11 +50,12 @@ public void test() { ListNode l1_2 = new ListNode(6, l1_3); ListNode l1_1 = new ListNode(7, l1_2); - ListNode result = reverseList2(l1_1); - System.out.println(result.val); - System.out.println(result.next.val); - System.out.println(result.next.next.val); - System.out.println(result.next.next.next.val); + ListNode result = reverseList(l1_1); + ListNode a = result; + while (a != null) { + System.out.println(a.val); + a = a.next; + } } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java index ebbd0cf..f4701d3 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test21/Solution.java @@ -17,28 +17,23 @@ public class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { - - - ListNode prehead = new ListNode(0); - - ListNode prev = prehead; + ListNode res = new ListNode(0); + ListNode curr = res; while (l1 != null && l2 != null) { if (l1.val <= l2.val) { - prev.next = l1; + curr.next = l1; l1 = l1.next; } else { - prev.next = l2; + curr.next = l2; l2 = l2.next; } - - prev = prev.next; + curr = curr.next; } + curr.next = l1 == null ? l2 : l1; - prev.next = l1 == null ? l2 : l1; - - return prehead.next; + return res.next; } @Test @@ -71,5 +66,4 @@ public void testCase() { } - } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java index 87f62f2..fdc1fe7 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test24/Solution.java @@ -19,7 +19,7 @@ * * @Auther: zhunn * @Date: 2020/10/23 10:48 - * @Description: 两两交换链表中结点:1-递归,2-迭代 + * @Description: 两两交换链表中结点:1-递归,2-迭代(推荐) */ public class Solution { @@ -41,7 +41,7 @@ public ListNode swapPairs1(ListNode head) { } /** - * 2-迭代 + * 2-迭代(推荐) * * @param head * @return @@ -59,11 +59,11 @@ public ListNode swapPairs2(ListNode head) { ListNode node1 = temp.next; ListNode node2 = temp.next.next; - temp.next = node2; node1.next = node2.next; - node2.next = node1; + node2.next = temp.next; //等价于 node2.next = node1; + temp.next = node2; //两两交换 画图演示,想着图写代码 - temp = node1; + temp = node1; // 临时结点往前推进 } return dummyHead.next; } @@ -87,9 +87,9 @@ public ListNode swapPairs3(ListNode head) { ListNode node1 = head; ListNode node2 = head.next; - temp.next = node2; node1.next = node2.next; - node2.next = node1; + node2.next = temp.next; + temp.next = node2; temp = node1; head = node1.next; @@ -110,12 +110,12 @@ public void test() { l1_3.next = l1_4; l1_4.next = l1_5; - ListNode result = swapPairs3(l1_1); + ListNode result = swapPairs2(l1_1); - System.out.println(result.val); - System.out.println(result.next.val); - System.out.println(result.next.next.val); - System.out.println(result.next.next.next.val); - System.out.println(result.next.next.next.next.val); + ListNode a = result; + while (a != null) { + System.out.println(a.val); + a = a.next; + } } } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java index 6e667e2..42bc0dc 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test25/Solution.java @@ -1,8 +1,10 @@ package com.chen.algorithm.znn.linkedlist.test25; import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; /** + * https://leetcode-cn.com/problems/reverse-nodes-in-k-group/solution/tu-jie-kge-yi-zu-fan-zhuan-lian-biao-by-user7208t/ * 25. K 个一组翻转链表 * 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 * k 是一个正整数,它的值小于或等于链表的长度。 @@ -14,7 +16,7 @@ * * @Auther: zhunn * @Date: 2020/10/24 17:23 - * @Description: K个一组翻转链表 + * @Description: K个一组翻转链表:1-官方解法;2-(推荐)链表分区(已翻转,待翻转,未翻转),pre,end,start=pre.next,nextTemp=end.next指针,pre和end移动指针到翻转后的start位置 */ public class Solution { @@ -66,9 +68,18 @@ private ListNode[] myReverse(ListNode head, ListNode tail) { } + /** + * 链表分区,pre,end,start,nextTemp指针(推荐) + * @param head + * @param k + * @return + */ public ListNode reverseKGroup1(ListNode head, int k) { - ListNode dummy = new ListNode(0); - dummy.next = head; + if (head == null || head.next == null) { + return head; + } + + ListNode dummy = new ListNode(0, head); ListNode pre = dummy; ListNode end = dummy; @@ -80,13 +91,14 @@ public ListNode reverseKGroup1(ListNode head, int k) { if (end == null) { break; } + ListNode start = pre.next; - ListNode next = end.next; + ListNode nextTemp = end.next; end.next = null; pre.next = reverse(start); - start.next = next; - pre = start; + start.next = nextTemp; + pre = start; end = pre; } return dummy.next; @@ -96,13 +108,35 @@ private ListNode reverse(ListNode head) { ListNode pre = null; ListNode curr = head; while (curr != null) { - ListNode next = curr.next; + ListNode nextTemp = curr.next; curr.next = pre; + pre = curr; - curr = next; + curr = nextTemp; } return pre; } + @Test + public void test() { + ListNode l1_1 = new ListNode(1); + ListNode l1_2 = new ListNode(2); + ListNode l1_3 = new ListNode(3); + ListNode l1_4 = new ListNode(4); + ListNode l1_5 = new ListNode(5); + + l1_1.next = l1_2; + l1_2.next = l1_3; + l1_3.next = l1_4; + l1_4.next = l1_5; + + ListNode result = reverseKGroup1(l1_1, 3); + + ListNode a = result; + while (a != null) { + System.out.println(a.val); + a = a.next; + } + } } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java index cdfc5ce..d499091 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test83/Solution.java @@ -1,6 +1,7 @@ package com.chen.algorithm.znn.linkedlist.test83; import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; /** * 83. 删除排序链表中的重复元素 @@ -14,7 +15,7 @@ * * @Author: zhunn * @Date: 2020-10-08 02:19 - * @Description: 删除排序链表中的重复元素 + * @Description: 删除排序链表中的重复元素:同删除排序数组中的重复元素 */ public class Solution { @@ -44,5 +45,22 @@ public ListNode deleteDuplicates(ListNode head) { return head; } + @Test + public void test() { + ListNode five = new ListNode(3); + ListNode four = new ListNode(3, five); + ListNode three = new ListNode(2, four); + ListNode two = new ListNode(1, three); + ListNode head = new ListNode(1, two); + + ListNode result = deleteDuplicates(head); + + ListNode a = result; + while (a != null) { + System.out.println(a.val); + a = a.next; + } + //System.out.println(result); + } } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java index 78a28fd..7e81c02 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test92/Solution.java @@ -1,9 +1,13 @@ package com.chen.algorithm.znn.linkedlist.test92; import com.chen.algorithm.znn.linkedlist.ListNode; +import com.chen.api.util.thread.study.chapter2.t6.CommonUtils; import org.junit.Test; +import javax.sound.midi.Soundbank; + /** + * https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/java-shuang-zhi-zhen-tou-cha-fa-by-mu-yi-cheng-zho/ * 92. 反转链表 II * 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 * 说明: @@ -14,7 +18,7 @@ * * @Auther: zhunn * @Date: 2020/10/24 17:23 - * @Description: 反转链表二:1-双指针,2-删除结点递推 + * @Description: 反转链表二:1-双指针,2-双指针头插法-删除结点递推(推荐) */ public class Solution { @@ -63,31 +67,34 @@ public ListNode reverseBetween1(ListNode head, int m, int n) { } /** - * 2-删除结点递推 + * 2-删除结点递推 (推荐) + * curr后面的元素删除,然后添加到pre的后面。也即头插法 * * @param head * @param m * @param n * @return */ - public ListNode reverseBetween2(ListNode head, int m, int n) { + public ListNode reverseBetween(ListNode head, int m, int n) { if (head == null || head.next == null) { return head; } - ListNode dummy = new ListNode(-1); - dummy.next = head; + ListNode dummy = new ListNode(-1, head); ListNode pre = dummy; + ListNode curr = dummy.next; + for (int i = 0; i < m - 1; i++) { pre = pre.next; - head = head.next; + curr = curr.next; //将curr移动到第一个要反转的节点的位置上 } for (int i = m; i < n; i++) { - ListNode nextTemp = head.next; - head.next = nextTemp.next; - nextTemp.next = pre.next; - pre.next = nextTemp; + ListNode removeNode = curr.next; + curr.next = curr.next.next; // 删除head后面的元素 + + removeNode.next = pre.next; // head后面的元素添加到pre后面 + pre.next = removeNode; } return dummy.next; } @@ -109,14 +116,13 @@ public void test() { l1_5.next = l1_6; l1_6.next = l1_7; - ListNode result = reverseBetween1(l1_1, 3, 6); + ListNode result = reverseBetween(l1_1, 3, 6); - System.out.println(result.val); - System.out.println(result.next.val); - System.out.println(result.next.next.val); - System.out.println(result.next.next.next.val); - System.out.println(result.next.next.next.next.val); - System.out.println(result.next.next.next.next.next.val); - System.out.println(result.next.next.next.next.next.next.val); + ListNode a = result; + while (a != null) { + System.out.print(a.val + " "); + a = a.next; + } + System.out.println(); } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 15b9fb5..fa03214 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -105,18 +105,18 @@ stack/queue 225. 用队列实现栈 *** q2入栈,q1出栈(注意入栈逻辑) 232. 用栈实现队列 *** s1入队列,s2出队列(注意出队列逻辑) 227. 基本计算器 II *** 加减直接入栈正数或负数,乘除先取出栈顶元素乘以或除以新元素,将结果入栈 -239. 滑动窗口最大值 *** ??? -496. 下一个更大元素 I *** +239. 滑动窗口最大值 *** ??? LinkedList双向链表队列,构建递减队列,添加,超过长度删除并写入最大值 +496. 下一个更大元素 I *** 单调栈,栈和HashMap配合实现 linkedlist -2. 两数相加 *** -21. 合并两个有序链表 *** -19. 删除链表的倒数第N个节点 *** -83. 删除排序链表中的重复元素 *** -24. 两两交换链表中的节点 *** -206. 反转链表 ******* -92. 反转链表 II -25 K 个一组翻转链表 ??? +2. 两数相加 *** 与 415. 数字型字符串相加 有异曲同工之妙 +21. 合并两个有序链表 *** while循环比对,并next +19. 删除链表的倒数第N个节点 *** 双指针法、栈、迭代len-n+1,推荐使用快慢双指针法 +83. 删除排序链表中的重复元素 *** 同26.删除排序数组中的重复元素 +24. 两两交换链表中的节点 *** 画图演示,看图写代码,声明两链表,while next和next.next都不为空 +206. 反转链表 ******* 声明双指针pre=null, curr = head;curr.next = pre(链表指针反转),最后返回pre +92. 反转链表 II 指定长度反转 双指针头插法-删除结点递推,画图演示,想图写代码 +25 K 个一组翻转链表 ??? (推荐)链表分区(已翻转,待翻转,未翻转),pre,end,start=pre.next,nextTemp=end.next指针,pre和end移动指针到翻转后的start位置 160 相交链表 *** 141 环形链表 *** 142 环形链表 II *** diff --git a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java index 2116547..55b5a68 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test239/Solution.java @@ -132,4 +132,26 @@ public void testCase() { int k = 3; System.out.println(Arrays.toString(maxSlidingWindow(nums, k))); } + + public int[] maxSlidingWindow2(int[] nums, int k) { + if (nums == null || nums.length < 2) { + return nums; + } + + int[] res = new int[nums.length - k + 1]; + LinkedList queue = new LinkedList<>(); + for (int i = 0; i < nums.length; i++) { + while (!queue.isEmpty() && nums[i] > queue.peekLast()) { + queue.pollLast(); + } + queue.addLast(nums[i]); + if (i >= k && nums[i - k] == queue.peekFirst()) { + queue.pollFirst(); + } + if (i + 1 >= k) { + res[i + 1 - k] = queue.peekFirst(); + } + } + return res; + } } diff --git a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java index af1aab6..4db5002 100644 --- a/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/stack/test496/Solution.java @@ -59,7 +59,29 @@ public int[] nextGreaterElement(int[] nums1, int[] nums2) { public void test() { int[] nums1 = {4, 1, 2}; int[] nums2 = {1, 3, 4, 2}; - int[] res = nextGreaterElement(nums1, nums2); + int[] res = nextGreaterElement2(nums1, nums2); System.out.println(Arrays.toString(res)); } + + public int[] nextGreaterElement2(int[] nums1, int[] nums2) { + Map map = new HashMap<>(); + Stack stack = new Stack<>(); + + for (int i = 0; i < nums2.length; i++) { + while (!stack.isEmpty() && nums2[i] > stack.peek()) { + map.put(stack.pop(), nums2[i]); + } + stack.push(nums2[i]); + } + + while (!stack.isEmpty()) { + map.put(stack.pop(), -1); + } + + int[] res = new int[nums1.length]; + for (int i = 0; i < nums1.length; i++) { + res[i] = map.get(nums1[i]); + } + return res; + } } From e68b7a706e4a897f974dddc13c3714afd7d79697 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 26 Nov 2020 15:16:51 +0800 Subject: [PATCH 37/63] review-linkedlist --- .../znn/linkedlist/test141/Solution.java | 20 ++++++++++++++++- .../znn/linkedlist/test142/Solution.java | 22 +++++++++++++++++-- .../znn/linkedlist/test160/Solution.java | 8 ++++--- src/main/java/com/chen/algorithm/znn/note | 6 ++--- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java index e659efc..04a06e1 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test141/Solution.java @@ -1,6 +1,7 @@ package com.chen.algorithm.znn.linkedlist.test141; import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; import java.util.HashSet; import java.util.Set; @@ -38,7 +39,7 @@ public class Solution { * @param head * @return */ - public boolean hasCycle1(ListNode head) { + public boolean hasCycle(ListNode head) { if (head == null || head.next == null) { return false; } @@ -98,4 +99,21 @@ public boolean hasCycle3(ListNode head) { return false; } + @Test + public void test() { + ListNode l1_1 = new ListNode(6); + ListNode l1_2 = new ListNode(1); + ListNode l1_3 = new ListNode(8); + ListNode l1_4 = new ListNode(7); + ListNode l1_5 = new ListNode(5); + + l1_1.next = l1_2; + l1_2.next = l1_3; + l1_3.next = l1_4; + l1_4.next = l1_5; + l1_5.next = l1_3; + + boolean result = hasCycle(l1_1); + System.out.println(result); + } } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java index 7acd023..7a1c52e 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test142/Solution.java @@ -2,6 +2,7 @@ import com.chen.algorithm.znn.linkedlist.ListNode; +import org.junit.Test; import java.util.HashSet; import java.util.Set; @@ -29,7 +30,7 @@ * @Auther: zhunn * @Date: 2020/10/23 16:10 * @Description: 环形链表二,找出入环点 - * 方法:1-哈希表,2-快慢指针 + * 方法:1-哈希表,2-快慢指针(推荐) */ public class Solution { @@ -39,7 +40,7 @@ public class Solution { * @param head * @return */ - public ListNode detectCycle1(ListNode head) { + public ListNode detectCycle(ListNode head) { if (head == null || head.next == null) { return null; } @@ -85,4 +86,21 @@ public ListNode detectCycle2(ListNode head) { return slow; } + @Test + public void test() { + ListNode l1_1 = new ListNode(6); + ListNode l1_2 = new ListNode(2); + ListNode l1_3 = new ListNode(8); + ListNode l1_4 = new ListNode(7); + ListNode l1_5 = new ListNode(5); + + l1_1.next = l1_2; + l1_2.next = l1_3; + l1_3.next = l1_4; + l1_4.next = l1_5; + l1_5.next = l1_3; + + ListNode result = detectCycle2(l1_1); + System.out.println(result.val); + } } diff --git a/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java b/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java index de60664..de27516 100644 --- a/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/linkedlist/test160/Solution.java @@ -4,6 +4,8 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/intersection-of-two-linked-lists/ + * https://leetcode-cn.com/problems/intersection-of-two-linked-lists/solution/tu-jie-xiang-jiao-lian-biao-by-user7208t/ * 160. 相交链表 * 编写一个程序,找到两个单链表相交的起始节点。 * 如下面的两个链表: @@ -24,7 +26,7 @@ * * @Author: zhunn * @Date: 2020-10-22 17:40 - * @Description: 相交链表 + * @Description: 相交链表:双指针法 */ public class Solution { @@ -40,12 +42,12 @@ public ListNode getIntersectionNode(ListNode headA, ListNode headB) { a = a == null ? headB : a.next; b = b == null ? headA : b.next; } - return b; + return a; } @Test public void test() { - ListNode l1_1 = new ListNode(4); + ListNode l1_1 = new ListNode(6); ListNode l1_2 = new ListNode(1); ListNode l1_3 = new ListNode(8); ListNode l1_4 = new ListNode(7); diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index fa03214..2d4db69 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -117,9 +117,9 @@ linkedlist 206. 反转链表 ******* 声明双指针pre=null, curr = head;curr.next = pre(链表指针反转),最后返回pre 92. 反转链表 II 指定长度反转 双指针头插法-删除结点递推,画图演示,想图写代码 25 K 个一组翻转链表 ??? (推荐)链表分区(已翻转,待翻转,未翻转),pre,end,start=pre.next,nextTemp=end.next指针,pre和end移动指针到翻转后的start位置 -160 相交链表 *** -141 环形链表 *** -142 环形链表 II *** +160 相交链表 *** 双指针法(a+c+b = b+c+a)a=链表1未相交部分,b=链表2未相交部分,c=两链表相交部分 +141 环形链表(判断链表是否有环) 1-哈希表;(推荐)2-双指针法-快慢指针 while(fast != null && fast.next != null) +142 环形链表 II ***(找出入环点) 1-哈希表;(推荐)2-快慢指针 //148. 排序链表 tree From 7d443367e1fb1ddaec791fe99aef066fea7f24cd Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 26 Nov 2020 19:44:31 +0800 Subject: [PATCH 38/63] review-tree --- src/main/java/com/chen/algorithm/znn/note | 32 +++++++++---------- .../algorithm/znn/tree/test101/Solution.java | 2 +- .../algorithm/znn/tree/test102/Solution.java | 3 +- .../algorithm/znn/tree/test144/Solution.java | 8 ++++- .../algorithm/znn/tree/test145/Solution.java | 10 +++--- .../algorithm/znn/tree/test199/Solution.java | 2 +- .../algorithm/znn/tree/test226/Solution.java | 10 +++--- .../algorithm/znn/tree/test94/Solution.java | 10 +++--- .../algorithm/znn/tree/test98/Solution.java | 2 +- 9 files changed, 43 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 2d4db69..779fa41 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -123,27 +123,27 @@ linkedlist //148. 排序链表 tree -94. 二叉树的中序遍历 -144. 二叉树的前序遍历 ***** -145. 后序遍历二叉树 递归、迭代实现 -102. 二叉树的层序遍历 ***** -107. 二叉树的层次遍历 II ***** -103. 二叉树的锯齿形层次遍历 ***** -104. 二叉树的最大深度 *** -111. 二叉树的最小深度 *** -543. 二叉树的直径 -112. 路径总和 *** -113. 路径之和 II *** -437. 路径之和 III *** -101. 对称二叉树 ***** -226. 翻转二叉树 ***** -617. 合并二叉树 -199. 二叉树的右视图 ***** +94. 二叉树的中序遍历 递归和迭代都要会,推荐迭代(一个stack实现)Stack stack = new Stack<>();(两层while循环,内层放左子树) +144. 二叉树的前序遍历 ***** 递归和迭代都要会,推荐迭代(一个stack实现)while(!stack.isEmpty()) +145. 后序遍历二叉树 递归和迭代都要会,推荐迭代(两个stack实现) +102. 二叉树的层序遍历 ***** BFS(一个queue实现)Queue queue = new LinkedList<>(); 写法同107 +107. 二叉树的层次遍历 II (自底向上的层次遍历) BFS(一个queue实现)1-使用队列存储每层元素,用栈存储每层的结果集;2-(推荐)使用java的LinkedList的性质,从上到下遍历,将新遍历的层结果集放入linkedlist的头部 +103. 二叉树的锯齿形层次遍历 ***** 使用两个stack交替迭代放值 +104. 二叉树的最大深度 *** 1-递归;2-(推荐)层次遍历+累加深度(广度优先搜索) +111. 二叉树的最小深度 *** 1-深度优先搜索,即递归;2-层次遍历,相比104题,多加一个判断,判断是否已经到叶子结点,到了直接return depth +543. 二叉树的直径 递归,左子树的深度+右子树的深度 Math.max(ans, leftDepth + rightDepth);return Math.max(leftDepth, rightDepth) + 1; +101. 对称二叉树 ***** 迭代:队列,放左右结点和右左结点 +226. 翻转二叉树 ***** 迭代:用queue层次遍历交换处理 +617. 合并二叉树 递归 +199. 二叉树的右视图 ***** 1-广度优先搜索,即层次遍历(推荐)将每一层的最后一个节点放入结果列表 96. 不同的二叉搜索树 98. 验证二叉搜索树??? 235. 二叉搜索树的最近公共祖先 ***** 236. 二叉树的最近公共祖先 *** 538. 把二叉搜索树转换为累加树 +112. 路径总和 *** +113. 路径之和 II *** +437. 路径之和 III *** recursion 汉诺塔问题 HanNuoTa diff --git a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java index 6f2ec19..66f1235 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java @@ -24,7 +24,7 @@ * * @Auther: zhunn * @Date: 2020/10/29 11:03 - * @Description: 对称二叉树:1-递归,2-迭代 + * @Description: 对称二叉树:1-递归,2-迭代(推荐) */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java index 494cc96..6de2aa9 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test102/Solution.java @@ -43,9 +43,10 @@ public List> levelOrder(TreeNode root) { return null; } - List> res = new ArrayList<>(); + List> res = new LinkedList<>(); Queue queue = new LinkedList<>(); queue.add(root); + while (!queue.isEmpty()) { int size = queue.size(); List levelList = new ArrayList<>(); diff --git a/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java index 9b3e80c..2f645c5 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test144/Solution.java @@ -14,7 +14,7 @@ * * @Auther: zhunn * @Date: 2020/10/28 16:25 - * @Description: 二叉树的前序遍历:1-递归;2-迭代 + * @Description: 二叉树的前序遍历:1-递归;2-迭代 (推荐) 两种方式都要会 */ public class Solution { @@ -43,6 +43,12 @@ private void preOrder(TreeNode root, List res) { preOrder(root.right, res); } + /** + * 2-迭代 (推荐) + * + * @param root + * @return + */ public List preorderTraversal2(TreeNode root) { if (root == null) { return null; diff --git a/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java index b66ce26..737a893 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test145/Solution.java @@ -12,7 +12,7 @@ * * @Auther: zhunn * @Date: 2020/10/28 10:28 - * @Description: 二叉树的后序遍历:1-递归;2-迭代(时间复杂度和空间复杂度都是O(n)) + * @Description: 二叉树的后序遍历:1-递归;2-(推荐)迭代(时间复杂度和空间复杂度都是O(n)) 两种方式都要会 */ public class Solution { @@ -40,7 +40,7 @@ private void postorder(TreeNode root, List res) { } /** - * 2-迭代法,两个栈实现 + * 2-迭代法,两个栈实现(推荐) * * @param root * @return @@ -52,12 +52,12 @@ public List postorderTraversal2(TreeNode root) { Stack stack1 = new Stack<>(); Stack stack2 = new Stack<>(); - stack1.push(root); + stack1.push(root); // 先放根 while (!stack1.isEmpty()) { - TreeNode node = stack1.pop(); + TreeNode node = stack1.pop(); // 出栈压入stack2的栈底 stack2.push(node); - if (node.left != null) { + if (node.left != null) { // 先入左子树,再出栈入stack2,迭代出栈就会先出 stack1.push(node.left); } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java index 4eea1f8..4746975 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java @@ -22,7 +22,7 @@ * * @Auther: zhunn * @Date: 2020/10/28 17:41 - * @Description: 二叉树的右视图:1-广度优先搜索;2-深度优先搜索 + * @Description: 二叉树的右视图:1-广度优先搜索,即层次遍历(推荐);2-深度优先搜索 */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java index c881503..f01b7d9 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java @@ -52,7 +52,7 @@ public TreeNode invertTree1(TreeNode root) { } /** - * 2-迭代 + * 2-迭代 用queue层次遍历交换处理 * * @param root * @return @@ -62,19 +62,19 @@ public TreeNode invertTree2(TreeNode root) { return root; } - Queue queue = new LinkedList<>(); + Queue queue = new LinkedList<>(); //将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素 queue.add(root); while (!queue.isEmpty()) { - TreeNode node = queue.poll(); + TreeNode node = queue.poll(); // 如果当前节点的左子树不为空,则放入队列等待后续处理 TreeNode temp = node.right; node.right = node.left; node.left = temp; - if (node.left != null) { + if (node.left != null) { //如果当前节点的左子树不为空,则放入队列等待后续处理 queue.add(node.left); } - if (node.right != null) { + if (node.right != null) { //如果当前节点的右子树不为空,则放入队列等待后续处理 queue.add(node.right); } } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java index a9a6410..1bbebd3 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java @@ -44,7 +44,7 @@ private void inOrder(TreeNode root, List res) { } /** - * 2-迭代 + * 2-迭代,栈 * * @param root * @return @@ -59,14 +59,14 @@ public List inorderTraversal2(TreeNode root) { TreeNode curr = root; while (!stack.isEmpty() || curr != null) { - while (curr != null) { + while (curr != null) { // 当前节点不为空,一直将左子树入栈 stack.push(curr); curr = curr.left; } - TreeNode temp = stack.pop(); - res.add(temp.val); - curr = temp.right; + TreeNode temp = stack.pop(); // 出栈 + res.add(temp.val); // 操作数据 + curr = temp.right; // 对出栈的节点检查是有否还有左节点,有的话继续入栈,没有的话就操作叶子节点的上一个节点 } return res; } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java index 179d980..76be91a 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java @@ -31,7 +31,7 @@ * * @Auther: zhunn * @Date: 2020/10/29 16:35 - * @Description: 验证二叉搜索树:1-递归,2-中序遍历 + * @Description: 验证二叉搜索树:1-递归,2-中序遍历(推荐) */ public class Solution { From f3ce24cab94e561a559bdf1e5776fd5bc29913c1 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 30 Nov 2020 19:03:31 +0800 Subject: [PATCH 39/63] review-tree --- src/main/java/com/chen/algorithm/znn/note | 22 +++++------ .../algorithm/znn/tree/test101/Solution.java | 32 +++++++++++++++- .../algorithm/znn/tree/test104/Solution.java | 4 +- .../algorithm/znn/tree/test107/Solution.java | 2 +- .../algorithm/znn/tree/test111/Solution.java | 6 +-- .../algorithm/znn/tree/test112/Solution.java | 20 +++++----- .../algorithm/znn/tree/test113/Solution.java | 22 +++++------ .../algorithm/znn/tree/test199/Solution.java | 14 ++++++- .../algorithm/znn/tree/test226/Solution.java | 22 +++++------ .../algorithm/znn/tree/test236/Solution.java | 13 ++++++- .../algorithm/znn/tree/test437/Solution.java | 38 +++++++++++++++---- .../algorithm/znn/tree/test538/Solution.java | 16 +++++--- .../algorithm/znn/tree/test617/Solution.java | 22 +++++------ .../algorithm/znn/tree/test94/Solution.java | 2 +- .../algorithm/znn/tree/test96/Solution.java | 17 ++++++--- .../algorithm/znn/tree/test98/Solution.java | 21 +++++----- 16 files changed, 178 insertions(+), 95 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 779fa41..2f071a2 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -130,20 +130,20 @@ tree 107. 二叉树的层次遍历 II (自底向上的层次遍历) BFS(一个queue实现)1-使用队列存储每层元素,用栈存储每层的结果集;2-(推荐)使用java的LinkedList的性质,从上到下遍历,将新遍历的层结果集放入linkedlist的头部 103. 二叉树的锯齿形层次遍历 ***** 使用两个stack交替迭代放值 104. 二叉树的最大深度 *** 1-递归;2-(推荐)层次遍历+累加深度(广度优先搜索) -111. 二叉树的最小深度 *** 1-深度优先搜索,即递归;2-层次遍历,相比104题,多加一个判断,判断是否已经到叶子结点,到了直接return depth +111. 二叉树的最小深度 *** 1-深度优先搜索,即递归;2-层次遍历,相比104题,多加一个判断,判断是否已经到叶子结点,到了直接return depth(if (node.left == null && node.right == null) ) +199. 二叉树的右视图 ***** 1-广度优先搜索,即层次遍历(推荐)将每一层的最后一个节点放入结果列表 543. 二叉树的直径 递归,左子树的深度+右子树的深度 Math.max(ans, leftDepth + rightDepth);return Math.max(leftDepth, rightDepth) + 1; 101. 对称二叉树 ***** 迭代:队列,放左右结点和右左结点 -226. 翻转二叉树 ***** 迭代:用queue层次遍历交换处理 +226. 翻转二叉树 ***** 迭代:用queue层次遍历交换处理,循环体内,每次取出一个node 617. 合并二叉树 递归 -199. 二叉树的右视图 ***** 1-广度优先搜索,即层次遍历(推荐)将每一层的最后一个节点放入结果列表 -96. 不同的二叉搜索树 -98. 验证二叉搜索树??? -235. 二叉搜索树的最近公共祖先 ***** -236. 二叉树的最近公共祖先 *** -538. 把二叉搜索树转换为累加树 -112. 路径总和 *** -113. 路径之和 II *** -437. 路径之和 III *** +96. 不同的二叉搜索树 动态规划,i为根,G(i-1)*G(n-i) 求和(1<= i <=n) +98. 验证二叉搜索树??? 中序遍历:遍历后是升序 +235. 二叉搜索树的最近公共祖先 ***** while循环判断根的值和另两个参数的大小。while (root != null) { +236. 二叉树的最近公共祖先 *** 递归 +538. 把二叉搜索树转换为累加树 递归-反序中序遍历 +112. 路径总和 *** 判断是否存在 层次遍历(BFS推荐) +113. 路径之和 II *** 返回所有路径 同112,用map把结点父节点记录下来,最后求路径反转 +437. 路径之和 III *** 不需要到叶子结点返回所有路径 两层递归 recursion 汉诺塔问题 HanNuoTa diff --git a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java index 66f1235..3bf4340 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test101/Solution.java @@ -49,7 +49,7 @@ private boolean isMirror(TreeNode root1, TreeNode root2) { } /** - * 2-迭代 + * 2-迭代(推荐) * * @param root * @return @@ -91,7 +91,35 @@ public void test() { TreeNode right2 = new TreeNode(2, right4_4, left3_3); TreeNode root = new TreeNode(1, left2, right2); - System.out.println(isSymmetric2(root)); + System.out.println(isSymmetric3(root)); } + + public boolean isSymmetric3(TreeNode root){ + return check(root,root); + } + private boolean check2(TreeNode u,TreeNode v){ + Queue queue = new LinkedList<>(); + + queue.add(u); + queue.add(v); + + while(!queue.isEmpty()){ + u = queue.poll(); + v = queue.poll(); + if(u == null && v == null){ + continue; + } + if(u == null || v == null || u.val != v.val){ + return false; + } + + queue.add(u.left); + queue.add(v.right); + + queue.add(u.right); + queue.add(v.left); + } + return true; + } } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java index 847192b..63c0409 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test104/Solution.java @@ -22,7 +22,7 @@ * * @Auther: zhunn * @Date: 2020/10/29 17:57 - * @Description: 二叉树的最大深度:1-递归;2-广度优先搜索(BFS-层次遍历) + * @Description: 二叉树的最大深度:1-递归;2-广度优先搜索(BFS-层次遍历)(推荐) */ public class Solution { @@ -37,7 +37,7 @@ public int maxDepth(TreeNode root) { } /** - * 2-广度优先搜索(层次遍历) + * 2-广度优先搜索(层次遍历)(推荐) * * @param root * @return diff --git a/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java index 0ce20d0..90d098e 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test107/Solution.java @@ -70,7 +70,7 @@ public List> levelOrderBottom(TreeNode root) { } /** - * 使用java的LinkedList的性质,从上到下遍历,将新遍历的层结果集放入linkedlist的头部 + * (推荐)使用java的LinkedList的性质,从上到下遍历,将新遍历的层结果集放入linkedlist的头部 * @param root * @return */ diff --git a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java index 6299d12..e7394f3 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java @@ -20,7 +20,7 @@ * * @Auther: zhunn * @Date: 2020/10/29 18:40 - * @Description: 二叉树的最小深度:1-深度优先搜索(DFS),即递归;2-广度优先搜索(BFS) + * @Description: 二叉树的最小深度:1-深度优先搜索(DFS),即递归;2-广度优先搜索(BFS)(推荐) */ public class Solution { @@ -60,7 +60,7 @@ public int minDepth1(TreeNode root) { } /** - * 2-广度优先搜索(BFS) + * 2-广度优先搜索(BFS)(推荐) * * @param root * @return @@ -101,7 +101,7 @@ public void test() { TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); TreeNode root = new TreeNode(3, left, right); - int res = minDepth1(left); + int res = minDepth2(left); System.out.println(res); } } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java index 867014b..709e6ac 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test112/Solution.java @@ -13,19 +13,19 @@ * 说明: 叶子节点是指没有子节点的节点。 * 示例: * 给定如下二叉树,以及目标和 sum = 22, - * - * 5 - * / \ - * 4 8 - * / / \ - * 11 13 4 - * / \ \ - * 7 2 1 + *

+ * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ \ + * 7 2 1 * 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。 * * @Auther: zhunn * @Date: 2020/11/08 15:25 - * @Description: 路径总和:1-递归;2-广度优先搜索 + * @Description: 路径总和:1-递归;2-广度优先搜索(推荐) */ public class Solution { @@ -47,7 +47,7 @@ public boolean hasPathSum(TreeNode root, int sum) { } /** - * 2-广度优先搜索 + * 2-广度优先搜索(推荐) * * @param root * @param sum diff --git a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java index 60d7c6f..79cee83 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test113/Solution.java @@ -11,23 +11,23 @@ * 说明: 叶子节点是指没有子节点的节点。 * 示例: * 给定如下二叉树,以及目标和 sum = 22, - * - * 5 - * / \ - * 4 8 - * / / \ - * 11 13 4 - * / \ / \ - * 7 2 5 1 + *

+ * 5 + * / \ + * 4 8 + * / / \ + * 11 13 4 + * / \ / \ + * 7 2 5 1 * 返回: * [ - * [5,4,11,2], - * [5,8,4,5] + * [5,4,11,2], + * [5,8,4,5] * ] * * @Auther: zhunn * @Date: 2020/10/28 10:11 - * @Description: 路径之和 II,二叉树中和为某一值的路径:1-深度优先搜索;2-广度优先搜索 + * @Description: 路径之和 II,二叉树中和为某一值的路径:1-深度优先搜索;2-广度优先搜索(推荐) * 同剑指 Offer 34 */ public class Solution { diff --git a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java index 4746975..d31a72e 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test199/Solution.java @@ -1,6 +1,8 @@ package com.chen.algorithm.znn.tree.test199; +import com.alibaba.fastjson.JSON; import com.chen.algorithm.znn.tree.TreeNode; +import org.junit.Test; import java.util.ArrayList; import java.util.LinkedList; @@ -27,7 +29,7 @@ public class Solution { /** - * 1-广度优先搜索 + * 1-广度优先搜索(推荐) * * @param root * @return @@ -84,4 +86,14 @@ private void dfs(TreeNode root, int depth) { dfs(root.right, depth); dfs(root.left, depth); } + + @Test + public void test() { + TreeNode left = new TreeNode(9); + TreeNode right = new TreeNode(20, new TreeNode(15), new TreeNode(7)); + TreeNode root = new TreeNode(3, left, right); + + List res = rightSideView(root); + System.out.println(JSON.toJSON(res)); + } } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java index f01b7d9..003d547 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test226/Solution.java @@ -14,21 +14,21 @@ * 翻转一棵二叉树。 * 示例: * 输入: - * 4 - * / \ - * 2 7 - * / \ / \ + * 4 + * / \ + * 2 7 + * / \ / \ * 1 3 6 9 * 输出: - * 4 - * / \ - * 7 2 - * / \ / \ + * 4 + * / \ + * 7 2 + * / \ / \ * 9 6 3 1 * * @Auther: zhunn * @Date: 2020/10/28 17:58 - * @Description: 翻转二叉树:1-递归;2-迭代 + * @Description: 翻转二叉树:1-递归;2-迭代(推荐) */ public class Solution { @@ -52,7 +52,7 @@ public TreeNode invertTree1(TreeNode root) { } /** - * 2-迭代 用queue层次遍历交换处理 + * 2-迭代 用queue层次遍历交换处理(推荐) * * @param root * @return @@ -65,7 +65,7 @@ public TreeNode invertTree2(TreeNode root) { Queue queue = new LinkedList<>(); //将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素 queue.add(root); while (!queue.isEmpty()) { - TreeNode node = queue.poll(); // 如果当前节点的左子树不为空,则放入队列等待后续处理 + TreeNode node = queue.poll(); // //每次都从队列中拿一个节点,并交换这个节点的左右子树 TreeNode temp = node.right; node.right = node.left; diff --git a/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java index 494c956..a516221 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test236/Solution.java @@ -9,6 +9,7 @@ import java.util.Set; /** + * https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/er-cha-shu-de-zui-jin-gong-gong-zu-xian-by-leetc-2/ * 236. 二叉树的最近公共祖先 (需要看leetcode题上面的图) * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 * 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” @@ -24,10 +25,18 @@ * * @Auther: zhunn * @Date: 2020/10/29 15:29 - * @Description: 二叉树的最近公共祖先:1-递归;2-存储父节点 + * @Description: 二叉树的最近公共祖先:1-递归(推荐);2-存储父节点 */ public class Solution { + /** + * 1-递归(推荐) + * + * @param root + * @param p + * @param q + * @return + */ public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) { return root; @@ -92,7 +101,7 @@ public void test() { TreeNode right = new TreeNode(2); TreeNode root = new TreeNode(8, left, right); - TreeNode res = lowestCommonAncestor2(root, left, right); + TreeNode res = lowestCommonAncestor1(root, left, right); System.out.println(res.val); } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java index 18acc40..3a11857 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test437/Solution.java @@ -4,6 +4,7 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/path-sum-iii/solution/437lu-jing-zong-he-iii-di-gui-fang-shi-by-ming-zhi/ * 437. 路径总和 III * 给定一个二叉树,它的每个结点都存放着一个整数值。 * 找出路径和等于给定数值的路径总数。 @@ -11,12 +12,12 @@ * 二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。 * 示例: * root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 - * 10 - * / \ - * 5 -3 - * / \ \ - * 3 2 11 - * / \ \ + * 10 + * / \ + * 5 -3 + * / \ \ + * 3 2 11 + * / \ \ * 3 -2 1 * 返回 3。和等于 8 的路径有: * 1. 5 -> 3 @@ -26,12 +27,22 @@ * @Auther: zhunn * @Date: 2020/11/08 15:25 * @Description: 路径总和 III + * 以当前节点作为头结点的路径数量 + 以当前节点的左孩子作为头结点的路径数量 + 以当前节点的右孩子作为头结点啊路径数量 */ public class Solution { public int pathSum(TreeNode root, int sum) { if (root == null) return 0; - return find(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum); + return countPath(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum); // 根结点开始或左右子树开始的所有路径之和 + } + + private int countPath(TreeNode root, int sum) { + if (root == null) { + return 0; + } + sum = sum - root.val; + int result = sum == 0 ? 1 : 0; + return result + countPath(root.left, sum) + countPath(root.right, sum); } private int find(TreeNode root, int sum) { @@ -40,6 +51,19 @@ private int find(TreeNode root, int sum) { (root.right == null ? 0 : find(root.right, sum - root.val)); } + private int paths(TreeNode root, int sum) { + if (root == null) { + return 0; + } + int res = 0; + if (root.val == sum) { + res += 1; + } + res += paths(root.left, sum - root.val); + res += paths(root.right, sum - root.val); + return res; + } + @Test public void test() { TreeNode left = new TreeNode(1, new TreeNode(3), null); diff --git a/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java index 791db20..48e69b7 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test538/Solution.java @@ -5,6 +5,7 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/convert-bst-to-greater-tree/solution/ba-er-cha-sou-suo-shu-zhuan-huan-wei-lei-jia-sh-14/ * 538. 把二叉搜索树转换为累加树(需要看leetcode题上面的图) * 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 * 提醒一下,二叉搜索树满足下列约束条件: @@ -27,19 +28,22 @@ * * @Auther: zhunn * @Date: 2020/10/29 11:39 - * @Description: 把二叉搜索树转换成累加树 + * @Description: 把二叉搜索树转换成累加树:递归-反序中序遍历 */ public class Solution { int sum = 0; public TreeNode convertBST(TreeNode root) { - if (root != null) { - convertBST(root.right); - sum += root.val; - root.val = sum; - convertBST(root.left); + if (root == null) { + return root; } + + convertBST(root.right); + sum += root.val; + root.val = sum; + convertBST(root.left); + return root; } diff --git a/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java index 6a0dbd5..c727046 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test617/Solution.java @@ -10,19 +10,19 @@ * 你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。 * 示例 1: * 输入: - * Tree 1 Tree 2 - * 1 2 - * / \ / \ - * 3 2 1 3 - * / \ \ - * 5 4 7 + * Tree 1 Tree 2 + * 1 2 + * / \ / \ + * 3 2 1 3 + * / \ \ + * 5 4 7 * 输出: * 合并后的树: - * 3 - * / \ - * 4 5 - * / \ \ - * 5 4 7 + * 3 + * / \ + * 4 5 + * / \ \ + * 5 4 7 * 注意: 合并必须从两个树的根节点开始。 * * @Auther: zhunn diff --git a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java index 1bbebd3..ac8e348 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test94/Solution.java @@ -44,7 +44,7 @@ private void inOrder(TreeNode root, List res) { } /** - * 2-迭代,栈 + * 2-迭代,栈(推荐) * * @param root * @return diff --git a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java index c24cae5..f1b6b45 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test96/Solution.java @@ -3,6 +3,11 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode-solution/ + * 思路 + * 给定一个有序序列 1⋯n,为了构建出一棵二叉搜索树,我们可以遍历每个数字 i,将该数字作为树根, + * 将 1⋯(i−1) 序列作为左子树,将 (i+1)⋯n 序列作为右子树。接着我们可以按照同样的方式递归构建左子树和右子树。 + *

* 96. 不同的二叉搜索树 * 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? * 示例: @@ -10,12 +15,12 @@ * 输出: 5 * 解释: * 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: - * - * 1 3 3 2 1 - * \ / / / \ \ - * 3 2 1 1 3 2 - * / / \ \ - * 2 1 2 3 + *

+ * 1 3 3 2 1 + * \ / / / \ \ + * 3 2 1 1 3 2 + * / / \ \ + * 2 1 2 3 * * @Auther: zhunn * @Date: 2020/10/29 17:49 diff --git a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java index 76be91a..cb3db35 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test98/Solution.java @@ -14,20 +14,20 @@ * 所有左子树和右子树自身必须也是二叉搜索树。 * 示例 1: * 输入: - * 2 - * / \ - * 1 3 + * 2 + * / \ + * 1 3 * 输出: true * 示例 2: * 输入: - * 5 - * / \ - * 1 4 - * / \ - * 3 6 + * 5 + * / \ + * 1 4 + * / \ + * 3 6 * 输出: false * 解释: 输入为: [5,1,4,null,null,3,6]。 - * 根节点的值为 5 ,但是其右子节点值为 4 。 + * 根节点的值为 5 ,但是其右子节点值为 4 。 * * @Auther: zhunn * @Date: 2020/10/29 16:35 @@ -44,6 +44,7 @@ public class Solution { public boolean isValidBST1(TreeNode root) { return isValid(root, null, null); } + private boolean isValid(TreeNode root, Integer min, Integer max) { if (root == null) { @@ -60,7 +61,7 @@ private boolean isValid(TreeNode root, Integer min, Integer max) { } /** - * 2-中序遍历:遍历后是升序,后一个值不得有小于前一个值 + * 2-中序遍历:遍历后是升序,后一个值不得有小于前一个值(推荐) * * @param root * @return From 213220b520444265d968c86971f3187f566d2f0d Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 1 Dec 2020 17:54:41 +0800 Subject: [PATCH 40/63] note --- src/main/java/com/chen/algorithm/znn/note | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 2f071a2..68d85ea 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -141,9 +141,9 @@ tree 235. 二叉搜索树的最近公共祖先 ***** while循环判断根的值和另两个参数的大小。while (root != null) { 236. 二叉树的最近公共祖先 *** 递归 538. 把二叉搜索树转换为累加树 递归-反序中序遍历 -112. 路径总和 *** 判断是否存在 层次遍历(BFS推荐) -113. 路径之和 II *** 返回所有路径 同112,用map把结点父节点记录下来,最后求路径反转 -437. 路径之和 III *** 不需要到叶子结点返回所有路径 两层递归 +112. 路径总和 *** 判断是否存在 层次遍历(BFS推荐) +113. 路径之和 II *** 返回所有路径 同112,用map把结点父节点记录下来,最后求路径反转 +437. 路径之和 III *** 不需要到叶子结点返回所有路径的数量 两层递归 recursion 汉诺塔问题 HanNuoTa From f867fb50f90ecd4fd99cb397d60ea87775be5935 Mon Sep 17 00:00:00 2001 From: zhunn Date: Wed, 2 Dec 2020 19:13:49 +0800 Subject: [PATCH 41/63] review-7 --- .../algorithm/znn/dfs/test22/Solution.java | 7 +++++- .../algorithm/znn/divide/test50/Solution.java | 24 +++++++++++++++++-- .../algorithm/znn/greedy/test55/Solution.java | 3 ++- src/main/java/com/chen/algorithm/znn/note | 14 +++++------ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java index 8d71208..46900d9 100644 --- a/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dfs/test22/Solution.java @@ -22,7 +22,7 @@ * * @Auther: zhunn * @Date: 2020/10/24 17:23 - * @Description: 括号生成:1-dfs + * @Description: 括号生成:1-dfs(推荐) */ public class Solution { @@ -33,6 +33,11 @@ public List generateParenthesis(int n) { return res; } + /** + * @param left 左边剩余的括号数 + * @param right 右边剩余的括号数 + * @param curStr 括号结果 + */ private void dfs(int left, int right, String curStr) { // 左右括号都不剩余了,递归终止 if (left == 0 && right == 0) { diff --git a/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java b/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java index e0ca4f4..b402be2 100644 --- a/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/divide/test50/Solution.java @@ -18,7 +18,7 @@ * * @Auther: zhunn * @Date: 2020/11/2 16:13 - * @Description: Pow(x, n):1-递归;2-迭代 + * @Description: Pow(x, n):1-递归;2-迭代(推荐) */ public class Solution { @@ -81,6 +81,26 @@ public double myPow2(double x, int n) { @Test public void test() { - System.out.println(myPow2(2.0, 5)); + System.out.println(myPow(2.0, 10)); + } + + public double myPow(double x, int n) { + if (n == 0) { + return 1.0; + } + if (n < 0) { + n = -n; + x = 1 / x; + } + double res = 1d; + double x_con = x; + while (n > 0) { + if (n % 2 == 1) { + res = res * x_con; + } + x_con = x_con * x_con; + n = n / 2; + } + return res; } } diff --git a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java index c8d8445..9c058bb 100644 --- a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java @@ -24,6 +24,7 @@ public class Solution { /** * 1-贪心算法 + * 倒序遍历,如果n-2下标能到达n-1下标,意味着前面只要有坐标能够到达n-2即可完成跳跃,于是末尾位置更改为n-2,这样构成一个子问题,迭代求解。 * * @param nums * @return @@ -35,7 +36,7 @@ public boolean canJump(int[] nums) { int lastPosition = nums.length - 1; for (int i = nums.length - 1; i >= 0; i--) { - if (nums[i] + i >= lastPosition) { + if (i + nums[i] >= lastPosition) { lastPosition = i; } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 68d85ea..2dd6425 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -146,21 +146,21 @@ tree 437. 路径之和 III *** 不需要到叶子结点返回所有路径的数量 两层递归 recursion -汉诺塔问题 HanNuoTa -172. 阶乘后的零 *** (打印阶乘 Recursion) +汉诺塔问题 HanNuoTa 递归,理解记忆 +172. 阶乘后的零 *** (打印阶乘 Recursion) 递归或迭代获取阶乘后结果,再取0的个数 bfs dfs -22. 括号生成 *** +22. 括号生成 *** 递归dfs,左右括号剩余数量,left>right剪枝, 左右括号数递减,字符串追加 divide -50. Pow(x, n) *** -169. 多数元素 *** +50. Pow(x, n) *** 迭代,初始条件分类讨论判断,定义res和中间x,while(n>0) +169. 多数元素 *** 1-排序;2-哈希表(推荐)放入hashmap计数,判断数量是否大于len/2 greedy -122. 买卖股票的最佳时机 II *** -55. 跳跃游戏 +122. 买卖股票的最佳时机 II *** 贪心-迭代计算只要有收益就累加到max,返回max +55. 跳跃游戏 贪心-倒序遍历,如果n-2下标能到达n-1下标,意味着前面只要有坐标能够到达n-2即可完成跳跃,于是末尾位置更改为n-2,这样构成一个子问题,迭代求解。 backtrack From 14022db8b47fc245979dc7782f76db0cbc1796ea Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 3 Dec 2020 18:51:15 +0800 Subject: [PATCH 42/63] review-8 --- .../znn/backtrack/test36/Solution.java | 12 ++++-- .../znn/backtrack/test39/Solution.java | 2 +- .../znn/backtrack/test47/Solution.java | 40 +++++++++++++++++-- .../znn/backtrack/test90/Solution.java | 8 ++-- src/main/java/com/chen/algorithm/znn/note | 25 ++++++------ 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java index 9e98f96..475f0aa 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test36/Solution.java @@ -44,7 +44,7 @@ * * @Auther: zhunn * @Date: 2020/11/3 13:54 - * @Description: 有效的数独:1-哈希数组;2-位运算数组 + * @Description: 有效的数独:1-哈希数组(没有空间要求也可以);2-位运算数组;3-二维数组(推荐) */ public class Solution { @@ -105,13 +105,19 @@ public boolean isValidSudoku2(char[][] board) { return true; } + /** + * 二维数组,第一维标识位置,第二维标识1-9数字 + * + * @param board + * @return + */ public boolean isValidSudoku1(char[][] board) { int[][] row = new int[9][10]; // 哈希表存储每一行的每个数是否出现过,默认初始情况下,每一行每一个数都没有出现过 // 整个board有9行,第二维的维数10是为了让下标有9,和数独中的数字9对应。 int[][] col = new int[9][10]; // 存储每一列的每个数是否出现过,默认初始情况下,每一列的每一个数都没有出现过 int[][] box = new int[9][10]; // 存储每一个box的每个数是否出现过,默认初始情况下,在每个box中,每个数都没有出现过。整个board有9个box。 - for (int i = 0; i < 9; i++) { - for (int j = 0; j < 9; j++) { + for (int i = 0; i < 9; i++) { //行 + for (int j = 0; j < 9; j++) {//列 if (board[i][j] == '.') { continue; } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java index b2da0fb..ff2c5ae 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test39/Solution.java @@ -43,7 +43,7 @@ public List> combinationSum(int[] candidates, int target) { } List> res = new ArrayList<>(); // 排序是剪枝的前提 - Arrays.sort(candidates); + //Arrays.sort(candidates); backtrack(0, target, candidates, new ArrayList<>(), res); return res; } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java index a872b55..f74da78 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test47/Solution.java @@ -34,17 +34,17 @@ public List> permuteUnique(int[] nums) { Arrays.sort(nums); boolean[] used = new boolean[nums.length]; - dfs(nums, nums.length, 0, used, new ArrayList<>(), res); + backtrack(0, nums.length, nums, used, new ArrayList<>(), res); return res; } - private void dfs(int[] nums, int len, int depth, boolean[] used, List curList, List> res) { + private void backtrack(int depth, int len, int[] nums, boolean[] used, List curList, List> res) { if (depth == len) { res.add(new ArrayList<>(curList)); return; } - for (int i = 0; i < len; ++i) { + for (int i = 0; i < len; i++) { if (used[i]) { continue; } @@ -57,7 +57,7 @@ private void dfs(int[] nums, int len, int depth, boolean[] used, List c curList.add(nums[i]); used[i] = true; - dfs(nums, len, depth + 1, used, curList, res); + backtrack(depth + 1, len, nums, used, curList, res); // 回溯部分的代码,和 dfs 之前的代码是对称的 used[i] = false; curList.remove(curList.size() - 1); @@ -68,5 +68,37 @@ private void dfs(int[] nums, int len, int depth, boolean[] used, List c public void testCase() { int[] nums = {1, 1, 2}; System.out.println(JSONObject.toJSONString(permuteUnique(nums))); + System.out.println(JSONObject.toJSONString(permuteUnique2(nums))); + } + + public List> permuteUnique2(int[] nums) { + if (nums == null || nums.length == 0) { + return null; + } + Arrays.sort(nums); + List> res = new ArrayList<>(); + boolean[] used = new boolean[nums.length]; + dfs(0, nums.length, nums, used, new ArrayList<>(), res); + return res; + } + + private void dfs(int depth, int len, int[] nums, boolean[] used, List curList, List> res) { + if (depth == len) { + res.add(new ArrayList<>(curList)); + return; + } + for (int i = 0; i < len; i++) { + if (used[i]) { + continue; + } + if (i > 0 && nums[i - 1] == nums[i] && !used[i - 1]) { + continue; + } + used[i] = true; + curList.add(nums[i]); + dfs(depth + 1, len, nums, used, curList, res); + curList.remove(curList.size() - 1); + used[i] = false; + } } } diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java index ee91024..64d90e6 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test90/Solution.java @@ -31,19 +31,19 @@ public class Solution { public List> subsetsWithDup(int[] nums) { List> res = new ArrayList<>(); Arrays.sort(nums); //排序 - backtrack(nums, 0, new ArrayList<>(), res); + backtrack(0, nums, new ArrayList<>(), res); return res; } - private void backtrack(int[] nums, int start, ArrayList curList, List> ans) { - ans.add(new ArrayList<>(curList)); + private void backtrack(int start, int[] nums, List curList, List> res) { + res.add(new ArrayList<>(curList)); for (int i = start; i < nums.length; i++) { //和上个数字相等就跳过 if (i > start && nums[i] == nums[i - 1]) { continue; } curList.add(nums[i]); - backtrack(nums, i + 1, curList, ans); + backtrack(i + 1, nums, curList, res); curList.remove(curList.size() - 1); } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 2dd6425..39914a3 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -9,13 +9,14 @@ 复刷顺序: 第一类:1) frequency-5 - 2) bitmap-5 + (23) 2) bitmap-5 -----------------------------------------第1天 3) sort-5 4) string-4 5) hash-4 -----------------------------------------第2天 第二类:6) array-18 + (60) -----------------------------------------第3天 7) heap-3 8) stack-7 @@ -25,7 +26,7 @@ 10) tree-21 -----------------------------------------第6天 第三类:11) recursion-2 - 12) bfs-0 + (40) 12) bfs-0 13) dfs-1 14) divide-2 15) greedy-2 @@ -159,20 +160,20 @@ divide 169. 多数元素 *** 1-排序;2-哈希表(推荐)放入hashmap计数,判断数量是否大于len/2 greedy -122. 买卖股票的最佳时机 II *** 贪心-迭代计算只要有收益就累加到max,返回max +122. 买卖股票的最佳时机 II *** 贪心-迭代计算只要有收益就累加到max,返回max; 动态规划 55. 跳跃游戏 贪心-倒序遍历,如果n-2下标能到达n-1下标,意味着前面只要有坐标能够到达n-2即可完成跳跃,于是末尾位置更改为n-2,这样构成一个子问题,迭代求解。 backtrack -36. 有效的数独 -39. 组合总和 *** -40. 组合总和 II *** -46. 全排列 *** -47. 全排列II *** -51. N皇后 *** ?? -79. 单词搜索 ???? -78. 子集 *** -90. 子集II*** +36. 有效的数独(9X9) 1-哈希数组(占用空间)2-二维数组(推荐),第一维表示位置,第二维表示1-9数字,出现过对应二维数组值置为1标识起来,下次循环等于1直接return false +39. 组合总和 *** 元素可以取多次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i) +40. 组合总和 II ***元素只能取一次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i+1);if (i > start && nums[i - 1] == nums[i])(剪枝) +46. 全排列 *** 给定数组无重复元素(结果都不可重复) 回溯法-depth、boolen[] +47. 全排列II ***给定数组有重复元素(结果都不可重复) 回溯法-先排序depth、boolen[];i > 0 && nums[i] == nums[i - 1] && !used[i - 1](剪枝) +78. 子集 *** 给定数组无重复元素(结果都不可重复) 回溯法-start,i + 1,递归方法先res.add(new ArrayList<>(curList)); +90. 子集II***给定数组有重复元素(结果都不可重复) 回溯法-先排序,剪枝 +//51. N皇后 *** ?? +79. 单词搜索 ???? 回溯法-定义boolean[][] visited;dfs(int index, char[][] board, String word, int x, int y),判断上|下|左|右 0-1背包问题 /backtrack/ZeroOneBag dynamic From c38e15c1c4ab4f2ac0d9a370af8d2bb5b48f9114 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 3 Dec 2020 19:00:44 +0800 Subject: [PATCH 43/63] note --- src/main/java/com/chen/algorithm/znn/note | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 39914a3..7046285 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -33,7 +33,7 @@ -----------------------------------------第7天 16) backtrack-10 -----------------------------------------第8天 - 17) dynamic-23 + 17) dynamic-24 -----------------------------------------第9天 ================================================== @@ -181,11 +181,19 @@ dynamic 70. 爬楼梯 *** 120. 三角形最小路径和 *** 64. 最小路径和 *** -121、(122)、123、188、309、714 股票买卖系列 *** +(股票买卖系列 start) +121、最多买卖一次 +122、最多买卖多次,不限次 +123、最多买卖两次 +188、最多买卖K次 +309、可以买卖多次,有冷冻期 +714、 可以买卖多次,一次买卖含一次手续费 +(股票买卖系列 end) 53. 最大子序和 *** 152. 乘积最大子数组*** 300. 最长上升子序列 *** -322. 零钱兑换、 518.零钱兑换 II *** +322. 零钱兑换 +518.零钱兑换 II *** 72. 编辑距离 *** 62. 不同路径 *** 279. 完全平方数 *** From dbb679d522229e1616ef1acdf94c59250d32ea59 Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 4 Dec 2020 18:17:33 +0800 Subject: [PATCH 44/63] review-9_1 --- .../algorithm/znn/backtrack/ZeroOneBag.java | 28 ++++- .../znn/dynamic/test121/Solution.java | 2 +- .../znn/dynamic/test123/Solution.java | 111 ++++++++++++------ .../znn/dynamic/test188/Solution.java | 1 + .../znn/dynamic/test309/Solution.java | 3 +- .../znn/dynamic/test322/Solution.java | 26 ++-- .../znn/dynamic/test416/Solution.java | 19 ++- .../znn/dynamic/test474/Solution.java | 21 ++-- .../znn/dynamic/test494/Solution.java | 35 +----- .../znn/dynamic/test518/Solution.java | 51 ++++---- .../znn/dynamic/test714/Solution.java | 1 + src/main/java/com/chen/algorithm/znn/note | 32 ++--- 12 files changed, 185 insertions(+), 145 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java b/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java index dffdc31..b9e2888 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/ZeroOneBag.java @@ -1,6 +1,14 @@ package com.chen.algorithm.znn.backtrack; +import org.junit.Test; + /** + * https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/ + * 作为「0-1 背包问题」,它的特点是:「每个数只能用一次」。解决的基本思路是:物品一个一个选,容量也一点一点增加去考虑,这一点是「动态规划」的思想,特别重要。 + * 在实际生活中,我们也是这样做的,一个一个地尝试把候选物品放入「背包」,通过比较得出一个物品要不要拿走。 + * + * 具体做法是:画一个 len 行,target + 1 列的表格。这里 len 是物品的个数,target 是背包的容量。len 行表示一个一个物品考虑,target + 1多出来的那 1 列,表示背包容量从 0 开始考虑。很多时候,我们需要考虑这个容量为 0 的数值。 + * * 我们有一个背包,背包总的承载重量是Wkg。现在我们有n个物品,每个物品的重量不等,并且不可分割。我们现在期望选择几件物品, * 装载到背包中。在不超过背包所能装载重量的前提下,如何让背包中物品的总重量最大? * @@ -76,21 +84,25 @@ public void bag2(int i, int cw) { * @param n n:物品个数(0-5) * @param w w:背包可承载重量(0-9) * @return + * 状态定义:第一维n表示放了几个物品,第二维w表示放或放入物品后,背包里的总重量 + * 状态转移方程: + * 思路:物品一个一个尝试,容量一点一点尝试,每个物品分类讨论的标准是:选与不选。 */ public int knapsack(int[] weight, int n, int w) { + // 状态定义:第一维表示放了几个物品,第二维表示放或放入物品后,背包里的总重量 boolean[][] states = new boolean[n][w + 1]; //默认值false states[0][0] = true; //初始化,第一行的数据要特殊处理,可以利用哨兵优化 states[0][weight[0]] = true; for (int i = 1; i < n; i++) { // 动态规划状态转移 for (int j = 0; j <= w; j++) { // 不把第i个物品放入背包 - if (states[i - 1][j] == true) { - states[i][j] = true; + if (states[i - 1][j]) { + states[i][j] = states[i - 1][j]; } } - for (int j = 0; j + weight[i] <= w; i++) { //把第i个物品放入背包 - if (states[i - 1][j] == true) { - states[i - 1][j + weight[i]] = true; + for (int j = 0; j + weight[i] <= w; j++) { //把第i个物品放入背包 + if (states[i - 1][j]) { + states[i][j + weight[i]] = true; } } } @@ -101,4 +113,10 @@ public int knapsack(int[] weight, int n, int w) { } return 0; } + + @Test + public void test() { + int cw = knapsack(items, n, w); + System.out.println(cw); + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java index 26e5481..a3e7d9d 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test121/Solution.java @@ -20,7 +20,7 @@ * * @Auther: zhunn * @Date: 2020/11/3 19:59 - * @Description: 买卖股票的最佳时机:双指针法 + * @Description: 买卖股票的最佳时机:双指针法 买入算一笔交易 * 121(最多买卖一次)、122(贪心,最多买卖多次,不限次)、123(最多买卖两次)、188(最多买卖K次)、309(可以买卖多次,有冷冻期)、714(可以买卖多次,一次买卖含一次手续费) * 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票) */ diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java index 4c47fc2..b8a1bfe 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test123/Solution.java @@ -26,74 +26,107 @@ * * @Auther: zhunn * @Date: 2020/11/3 21:06 - * @Description: 买卖股票的最佳时机 III:1-动态规划-优化空间;2-动态规划 + * @Description: 买卖股票的最佳时机 III:1-动态规划;2-动态规划-优化空间 */ public class Solution { /** - * 1-动态规划-优化空间 - * (由于今天只参考了昨天的状态,所以直接去掉第一维度不会影响状态转移的正确性) + * 1-动态规划 dp[i][j][k]: i 表示第几天(0-n),j表示交易了几次(0,1,2),k表示是否持股(0-不持股,1-持股) * * @param prices - * @return dp[i][j][k]: i 表示第几天(0-n),j表示交易了几次(0,1,2),k表示是否持股(0-不持股,1-持股) - * 此题可以用dp[j][k] 即可 + * @return */ public int maxProfit(int[] prices) { - if (prices == null || prices.length < 2) { + int len = prices.length; + if (len < 2) { return 0; } - int[][] dp = new int[3][2]; - dp[0][0] = 0; - dp[1][1] = -prices[0]; - dp[2][1] = Integer.MIN_VALUE; // 还没发生的交易,持股的时候应该初始化为负无穷 - for (int i = 1; i < prices.length; i++) { - dp[1][1] = Math.max(-prices[i], dp[1][1]); - dp[1][0] = Math.max(dp[1][1] + prices[i], dp[1][0]); - dp[2][1] = Math.max(dp[1][0] - prices[i], dp[2][1]); - dp[2][0] = Math.max(dp[2][1] + prices[i], dp[2][0]); + // 第 2 维的 0 没有意义,1 表示交易进行了 1 次,2 表示交易进行了 2 次 + // 为了使得第 2 维的数值 1 和 2 有意义,这里将第 2 维的长度设置为 3 + int[][][] dp = new int[len][3][2]; + + // 理解如下初始化 + // 第 3 维规定了必须持股,因此是 -prices[0] + dp[0][1][1] = -prices[0]; + // 还没发生的交易,持股的时候应该初始化为负无穷 + dp[0][2][1] = Integer.MIN_VALUE; + + for (int i = 1; i < len; i++) { + // 转移顺序先持股,再卖出 + dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][0] - prices[i]); + dp[i][1][0] = Math.max(dp[i - 1][1][0], dp[i - 1][1][1] + prices[i]); + dp[i][2][1] = Math.max(dp[i - 1][2][1], dp[i - 1][1][0] - prices[i]); + dp[i][2][0] = Math.max(dp[i - 1][2][0], dp[i - 1][2][1] + prices[i]); } - return Math.max(dp[1][0], dp[2][0]); + return Math.max(dp[len - 1][1][0], dp[len - 1][2][0]); } /** - * 2-动态规划 + * 2-动态规划-优化空间 + * (由于今天只参考了昨天的状态,所以直接去掉第一维度不会影响状态转移的正确性) * * @param prices - * @return + * @return dp[i][j][k]: i 表示第几天(0-n),j表示交易了几次(0,1,2),k表示是否持股(0-不持股,1-持股) + * 此题可以用dp[j][k] 即可 */ public int maxProfit2(int[] prices) { - if (prices == null || prices.length == 0) { + if (prices == null || prices.length < 2) { return 0; } - // dp[i][j] ,表示 [0, i] 区间里,状态为 j 的最大收益 - // j = 0:什么都不操作 - // j = 1:第 1 次买入一支股票 - // j = 2:第 1 次卖出一支股票 - // j = 3:第 2 次买入一支股票 - // j = 4:第 2 次卖出一支股票 - - int n = prices.length; - int[][] dp = new int[n][5]; + int[][] dp = new int[3][2]; dp[0][0] = 0; - dp[0][1] = -prices[0]; - for (int i = 0; i < n; i++) { - dp[i][3] = Integer.MIN_VALUE; - } + dp[1][1] = -prices[0]; + dp[2][1] = Integer.MIN_VALUE; // 还没发生的交易,持股的时候应该初始化为负无穷 - for (int i = 1; i < n; i++) { - dp[i][0] = 0; - dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); - dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]); - dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]); - dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]); + for (int i = 1; i < prices.length; i++) { + dp[1][1] = Math.max(dp[1][1], dp[0][0] - prices[i]); + dp[1][0] = Math.max(dp[1][0], dp[1][1] + prices[i]); + dp[2][1] = Math.max(dp[2][1], dp[1][0] - prices[i]); + dp[2][0] = Math.max(dp[2][0], dp[2][1] + prices[i]); } - return Math.max(Math.max(dp[n - 1][0], dp[n - 1][2]), dp[n - 1][4]); + return Math.max(dp[1][0], dp[2][0]); } + ///** + // * 3-动态规划 + // * + // * @param + // * @return + // */ + //public int maxProfit3(int[] prices) { + // if (prices == null || prices.length == 0) { + // return 0; + // } + // // dp[i][j] ,表示 [0, i] 区间里,状态为 j 的最大收益 + // // j = 0:什么都不操作 + // // j = 1:第 1 次买入一支股票 + // // j = 2:第 1 次卖出一支股票 + // // j = 3:第 2 次买入一支股票 + // // j = 4:第 2 次卖出一支股票 + // + // int n = prices.length; + // int[][] dp = new int[n][5]; + // dp[0][0] = 0; + // dp[0][1] = -prices[0]; + // for (int i = 0; i < n; i++) { + // dp[i][3] = Integer.MIN_VALUE; + // } + // + // for (int i = 1; i < n; i++) { + // dp[i][0] = 0; + // dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); + // dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]); + // dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]); + // dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]); + // } + // return Math.max(Math.max(dp[n - 1][0], dp[n - 1][2]), dp[n - 1][4]); + //} + @Test public void test() { int[] prices = {3, 3, 5, 0, 0, 3, 1, 4}; + System.out.println(maxProfit(prices)); System.out.println(maxProfit2(prices)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java index 09e4b2f..3c2bdc6 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test188/Solution.java @@ -152,6 +152,7 @@ public int maxProfit2(int[] prices, int k) { @Test public void test() { int[] prices = {3, 2, 6, 5, 0, 3}; + System.out.println(maxProfit(prices, 2)); System.out.println(maxProfit2(prices, 2)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java index f575b61..42f19c7 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test309/Solution.java @@ -16,7 +16,7 @@ * * @Auther: zhunn * @Date: 2020/11/3 22:03 - * @Description: 最佳买卖股票时机含冷冻期:1-动态规划;2-动态规划-优化空间 + * @Description: 最佳买卖股票时机含冷冻期:1-动态规划(推荐);2-动态规划-优化空间 */ public class Solution { @@ -84,5 +84,6 @@ public int maxProfit2(int[] prices) { public void test() { int[] prices = {1, 2, 3, 0, 2}; System.out.println(maxProfit(prices)); + System.out.println(maxProfit2(prices)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java index 82ff4d5..a2e1388 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test322/Solution.java @@ -35,23 +35,31 @@ */ public class Solution { + /** + * 动态规划-优化空间(推荐) + * + * @param coins + * @param amount + * @return + */ public int coinChange(int[] coins, int amount) { if (coins == null || coins.length == 0) { + if(amount == 0){ + return 0; + } return -1; } - int max = amount + 1; - int[] dp = new int[amount + 1]; // 给 0 占位 - Arrays.fill(dp, max); // 注意:因为要比较的是最小值,这个不可能的值就得赋值成为一个最大值 + int[] dp = new int[amount + 1]; // 状态转移方程-凑成amount数值需要的最少硬币数,给 0 占位 + Arrays.fill(dp, amount + 1); // 注意:因为要比较的是最小值,这个不可能的值就得赋值成为一个最大值 + dp[0] = 0; // 理解 dp[0] = 0 的合理性,单独一枚硬币如果能够凑出面值,符合最优子结构 - dp[0] = 0; // 理解 dp[0] = 0 的合理性,单独一枚硬币如果能够凑出面值,符合最优子结构 - for (int i = 1; i <= amount; i++) { - for (int j = 0; j < coins.length; j++) { - if (coins[j] <= i) { - dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); - } + for (int coin : coins) { + for (int i = coin; i <= amount; i++) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); } } + return dp[amount] > amount ? -1 : dp[amount]; } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java index 418cf63..242b8ae 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test416/Solution.java @@ -4,6 +4,7 @@ /** * https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/ + * https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/fen-ge-deng-he-zi-ji-by-leetcode-solution/ * 416. 分割等和子集 * 给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。 * 注意: @@ -20,7 +21,7 @@ * * @Auther: zhunn * @Date: 2020/11/5 18:27 - * @Description: 分割等和子集:1-动态规划, 0-1背包问题;2-动态规划-剪枝;3-动态规划-优化空间 + * @Description: 分割等和子集:1-动态规划, 0-1背包问题;2-动态规划-剪枝(推荐);3-动态规划-优化空间(推荐2演化到3) */ public class Solution { @@ -54,13 +55,8 @@ public boolean canPartition(int[] nums) { for (int i = 1; i < len; i++) { //再填表格后面几行 for (int j = 0; j <= target; j++) { - dp[i][j] = dp[i - 1][j]; //直接把结果从上面一行抄下来,然后再修正 - if (nums[i] == j) { - dp[i][j] = true; - continue; - } - - if (nums[i] < j) { + dp[i][j] = dp[i - 1][j]; //如果不选取nums[i],则dp[i][j]=dp[i−1][j]; + if (nums[i] <= j) { dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; } } @@ -99,9 +95,9 @@ public boolean canPartition2(int[] nums) { for (int i = 1; i < len; i++) { for (int j = 0; j <= target; j++) { - dp[i][j] = dp[i - 1][j]; + dp[i][j] = dp[i - 1][j]; //如果不选取nums[i],则dp[i][j]=dp[i−1][j]; if (nums[i] <= j) { - dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; //如果选取nums[i],则dp[i][j]=dp[i−1][j−nums[i]]。选取后j - nums[i]+nums[i]刚好等于j } if (dp[i][target]) { // 由于状态转移方程的特殊性,提前结束,可以认为是剪枝操作 @@ -154,6 +150,7 @@ public boolean canPartition3(int[] nums) { @Test public void test() { int[] nums = {1, 5, 11, 5}; - System.out.println(canPartition(nums)); + System.out.println(canPartition2(nums)); + System.out.println(canPartition3(nums)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java index 39cee04..191eed5 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test474/Solution.java @@ -24,16 +24,16 @@ */ public class Solution { - public int findMaxForm(String[] strs, int m, int n) { - int[][] dp = new int[m + 1][n + 1]; - for (String s : strs) { - int[] count = countzeroesones(s); - for (int zeroes = m; zeroes >= count[0]; zeroes--) - for (int ones = n; ones >= count[1]; ones--) - dp[zeroes][ones] = Math.max(1 + dp[zeroes - count[0]][ones - count[1]], dp[zeroes][ones]); - } - return dp[m][n]; - } + //public int findMaxForm(String[] strs, int m, int n) { + // int[][] dp = new int[m + 1][n + 1]; + // for (String s : strs) { + // int[] count = countzeroesones(s); + // for (int zeroes = m; zeroes >= count[0]; zeroes--) + // for (int ones = n; ones >= count[1]; ones--) + // dp[zeroes][ones] = Math.max(1 + dp[zeroes - count[0]][ones - count[1]], dp[zeroes][ones]); + // } + // return dp[m][n]; + //} public int[] countzeroesones(String s) { int[] cnt = new int[2]; @@ -97,6 +97,7 @@ public int findMaxForm2(String[] strs, int m, int n) { @Test public void test() { String[] strs = {"10", "0001", "111001", "1", "0"}; + System.out.println(findMaxForm1(strs, 5, 3)); System.out.println(findMaxForm2(strs, 5, 3)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java index 69a28a4..a54f3be 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test494/Solution.java @@ -98,9 +98,8 @@ public int findTargetSumWays2(int[] nums, int S) { // i(1 ~ len)表示遍历(不一定选)了 i 个元素,j(0 ~ sum) 表示它们的和 for (int i = 1; i <= len; i++) { for (int j = 0; j <= target; j++) { - if (j - nums[i - 1] < 0) { // 装不下(不选当前元素) - dp[i][j] = dp[i - 1][j]; - } else { // 可装可不装(当前元素可选可不选) + dp[i][j] = dp[i - 1][j]; // 装不下(不选当前元素) + if (nums[i - 1] <= j) { // 可装可不装(当前元素可选可不选) dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]]; } } @@ -109,35 +108,6 @@ public int findTargetSumWays2(int[] nums, int S) { return dp[len][target]; } - public int findTargetSumWays2_test(int[] nums, int S) { - int sum = 0; - for (int num : nums) { - sum += num; - } - if (((sum + S) & 1) == 1) { // 奇数 - return 0; - } - if (S > sum) { - return 0; - } - - int target = (S + sum) >> 1; - int len = nums.length; - int[][] dp = new int[len + 1][target + 1]; - dp[0][0] = 1; - - for (int i = 1; i <= len; i++) { - for (int j = 0; j <= target; j++) { - if (j < nums[i - 1]) { - 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][target]; - } - public int findTargetSumWays3(int[] nums, int S) { int sum = 0; for (int num : nums) { @@ -165,6 +135,7 @@ public int findTargetSumWays3(int[] nums, int S) { @Test public void test() { int[] nums = {1, 1, 1, 1, 1}; + System.out.println(findTargetSumWays2(nums, 3)); System.out.println(findTargetSumWays3(nums, 3)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java index 876d2e6..b9357a3 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test518/Solution.java @@ -32,6 +32,13 @@ */ public class Solution { + /** + * 推荐 + * + * @param amount + * @param coins + * @return + */ public int change(int amount, int[] coins) { if (coins == null || coins.length == 0) { if (amount == 0) { @@ -51,32 +58,32 @@ public int change(int amount, int[] coins) { return dp[amount]; } - public int change2(int amount, int[] coins) { - if (coins == null || coins.length == 0) { - if (amount == 0) { - return 1; - } - return 0; - } - - int[] dp = new int[amount + 1]; - dp[0] = 1; - - for (int coin : coins) { // 枚举硬币 - for (int x = 1; x <= amount; x++) { // 枚举金额 - if (coin > x) { - continue; // coin不能大于金额 - } - dp[x] = dp[x] + dp[x - coin]; - } - } - return dp[amount]; - } + //public int change2(int amount, int[] coins) { + // if (coins == null || coins.length == 0) { + // if (amount == 0) { + // return 1; + // } + // return 0; + // } + // + // int[] dp = new int[amount + 1]; + // dp[0] = 1; + // + // for (int coin : coins) { // 枚举硬币 + // for (int x = 1; x <= amount; x++) { // 枚举金额 + // if (coin > x) { + // continue; // coin不能大于金额 + // } + // dp[x] = dp[x] + dp[x - coin]; + // } + // } + // return dp[amount]; + //} @Test public void test() { int amount = 5; int[] coins = {1, 2, 5}; - System.out.println(change2(amount, coins)); + System.out.println(change(amount, coins)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java index 10efb69..8ad0106 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test714/Solution.java @@ -81,6 +81,7 @@ public int maxProfit2(int[] prices, int fee) { public void test() { int[] prices = {1, 3, 2, 8, 4, 9}; int fee = 2; + System.out.println(maxProfit(prices, fee)); System.out.println(maxProfit2(prices, fee)); } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 7046285..c3ecf4a 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -170,37 +170,39 @@ backtrack 40. 组合总和 II ***元素只能取一次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i+1);if (i > start && nums[i - 1] == nums[i])(剪枝) 46. 全排列 *** 给定数组无重复元素(结果都不可重复) 回溯法-depth、boolen[] 47. 全排列II ***给定数组有重复元素(结果都不可重复) 回溯法-先排序depth、boolen[];i > 0 && nums[i] == nums[i - 1] && !used[i - 1](剪枝) -78. 子集 *** 给定数组无重复元素(结果都不可重复) 回溯法-start,i + 1,递归方法先res.add(new ArrayList<>(curList)); +78. 子集 *** 给定数组无重复元素(结果都不可重复) 回溯法-start,dfs(start=i + 1),递归方法先res.add(new ArrayList<>(curList)); 90. 子集II***给定数组有重复元素(结果都不可重复) 回溯法-先排序,剪枝 //51. N皇后 *** ?? 79. 单词搜索 ???? 回溯法-定义boolean[][] visited;dfs(int index, char[][] board, String word, int x, int y),判断上|下|左|右 0-1背包问题 /backtrack/ZeroOneBag dynamic -0-1背包问题 /dynamicprogramming/ZeroOndBag3 +0-1背包问题 /dynamicprogramming/ZeroOndBag3======动态规划优化空间(滚动数组,从后往前) +416. 分割等和子集(0-1背包)数组是否能分割成两个元素和相等的子集 dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; +474. 一和零(0-1背包)(String[] strs, int m, int n) 返回 strs 的最大子集的长度,dp[i][j][k]=Math.max(dp[i-1][j][k], dp[i-1][j-cnt[0]][k-cnt[1]] + 1); +494. 目标和(0-1背包)(int[] nums, int S)可加减 (同416)dp[i][j] = dp[i-1][j]+dp[i - 1][j-nums[i-1]]; +322. 零钱兑换(完全背包)返回所需的最少的硬币个数 Math.min(dp[i], dp[i - coin] + 1);return dp[amount] > amount ? -1 : dp[amount]; +518.零钱兑换 II (完全背包)返回所有组合数 dp[x] = dp[x] + dp[x - coin];return dp[amount]; +(股票买卖系列 start)===人为规定买入股票算一笔交易,dp[i][j][k]: i 表示第几天(0-n),j表示交易了几次(0,1,2),k表示是否持股(0-不持股,1-持股) + 由于当前天只参考了昨天的状态值,因此可以考虑使用「滚动数组」。 +121、最多买卖(交易)一次 双指针法,记录最小值和利益最大值 +122、最多买卖(交易)多次,不限次 贪心-迭代计算只要有收益就累加到max,返回max; +123、最多买卖(交易)两次 初始化:dp[0][1][1] = -prices[0];dp[0][2][1] = Integer.MIN_VALUE; +188、最多买卖(交易)K次 特判k>=len/2,转122,初始化:第i天交易k次持有股票dp[i][j][1] = Integer.MIN_VALUE;(还没发生的交易)i和j都有1个位置的偏移 +309、可以买卖(交易)多次,有冷冻期 dp[i][0]: 手上不持有股票不冷冻,dp[i][1]: 手上持有股票时,dp[i][2]: 手上不持有股票冷冻 + dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]);dp[i][2] = dp[i - 1][1] + prices[i]; +714、 可以买卖(交易)多次,一次买卖含一次手续费 +(股票买卖系列 end) 70. 爬楼梯 *** 120. 三角形最小路径和 *** 64. 最小路径和 *** -(股票买卖系列 start) -121、最多买卖一次 -122、最多买卖多次,不限次 -123、最多买卖两次 -188、最多买卖K次 -309、可以买卖多次,有冷冻期 -714、 可以买卖多次,一次买卖含一次手续费 -(股票买卖系列 end) 53. 最大子序和 *** 152. 乘积最大子数组*** 300. 最长上升子序列 *** -322. 零钱兑换 -518.零钱兑换 II *** 72. 编辑距离 *** 62. 不同路径 *** 279. 完全平方数 *** 343. 整数拆分 *** -416. 分割等和子集 *** -474. 一和零 *** -494. 目标和 *** 198. 打家劫舍 *** 213. 打家劫舍 II *** 337. 打家劫舍 III *** \ No newline at end of file From b4b3ba2b83a22856c47ae43638841bdeb16ba8ab Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 7 Dec 2020 18:42:22 +0800 Subject: [PATCH 45/63] review-9_2 --- .../znn/dynamic/test120/Solution.java | 18 +++++++++++++++ .../znn/dynamic/test64/Solution.java | 6 ++--- .../znn/dynamic/test70/Solution.java | 23 +++++++++++++++++++ src/main/java/com/chen/algorithm/znn/note | 12 +++++----- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java index d0212d7..4843372 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test120/Solution.java @@ -84,6 +84,24 @@ public void testCase() { triangle.add(Arrays.asList(4, 1, 8, 3)); System.out.println(minimumTotal2(triangle)); + System.out.println(minimumTotal3(triangle)); } + + public int minimumTotal3(List> triangle) { + if (triangle == null || triangle.size() == 0) { + return 0; + } + + int n = triangle.size(); + int m = triangle.get(n - 1).size(); + int[] dp = new int[m + 1]; + + for (int i = n - 1; i >= 0; i--) { + for (int j = 0; j <= i; j++) { + dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j); + } + } + return dp[0]; + } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java index fd245b5..485e4d0 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test64/Solution.java @@ -17,12 +17,12 @@ * * @Auther: zhunn * @Date: 2020/11/5 11:33 - * @Description: 最小路径和:1-动态规划;2-动态规划-优化空间,使用原数组空间;3-动态规划-优化空间,不更改原数组(可忽略) + * @Description: 最小路径和:1-动态规划(推荐);2-动态规划-优化空间,使用原数组空间;3-动态规划-优化空间,不更改原数组(可忽略) */ public class Solution { /** - * 1-动态规划,官方解答 + * 1-动态规划,官方解答(推荐) * * @param grid * @return @@ -107,6 +107,6 @@ public int minPathSum3(int[][] grid) { public void testCase() { int[][] nums = {{1, 3, 1}, {1, 5, 1}, {4, 2, 1}}; - System.out.println(minPathSum2(nums)); + System.out.println(minPathSum(nums)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java index ff2ee30..e9b5de5 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test70/Solution.java @@ -86,5 +86,28 @@ public int climbStairs2(int n) { public void test() { int res = climbStairs2(10); System.out.println(res); + int res3 = climbStairs3(10); + System.out.println(res3); + } + + public int climbStairs3(int n) { + if (n <= 0) { + return 0; + } + if (n == 1) { + return 1; + } + if (n == 2) { + return 2; + } + + int[] dp = new int[n + 1]; + dp[0] = 0; + dp[1] = 1; + dp[2] = 2; + for (int i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + return dp[n]; } } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index c3ecf4a..da1e78d 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -193,16 +193,16 @@ dynamic dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]);dp[i][2] = dp[i - 1][1] + prices[i]; 714、 可以买卖(交易)多次,一次买卖含一次手续费 (股票买卖系列 end) -70. 爬楼梯 *** -120. 三角形最小路径和 *** -64. 最小路径和 *** +70. 爬楼梯 *** 1-迭代,2-动态规划,dp[i] = dp[i - 1] + dp[i - 2]; +120. 三角形最小路径和 *** for(int i = n - 1; i >= 0; i--);for(int j = 0; j <= i; j++);dp[j]=Math.min(dp[j],dp[j+1]) + triangle.get(i).get(j); +64. 最小路径和 *** 初始化dp[0][0] = grid[0][0];初始化第0行和第0列,for(int j=1;j Date: Tue, 8 Dec 2020 15:56:07 +0800 Subject: [PATCH 46/63] review-9_3 --- .../znn/dynamic/test198/Solution.java | 4 +-- .../znn/dynamic/test213/Solution.java | 6 ++-- .../znn/dynamic/test279/Solution.java | 4 +-- .../znn/dynamic/test300/Solution.java | 12 ++++++-- .../znn/dynamic/test343/Solution.java | 4 +-- .../znn/dynamic/test72/Solution.java | 9 +++--- src/main/java/com/chen/algorithm/znn/note | 29 +++++++++++-------- 7 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java index 30d89e3..33d78b8 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test198/Solution.java @@ -40,11 +40,11 @@ public int rob(int[] nums) { return nums[0]; } - int[] dp = new int[len]; // dp[i] 表示前 ii 间房屋能偷窃到的最高总金额 + int[] dp = new int[len]; // dp[i] 表示前 i 间房屋能偷窃到的最高总金额 dp[0] = nums[0]; dp[1] = Math.max(nums[0], nums[1]); - for (int i = 2; i < len; i++) { + for (int i = 2; i < len; i++) { // 第i间房偷dp[i - 2] + nums[i];第i间房不偷dp[i - 1] dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]); } return dp[len - 1]; diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java index 8239c61..e2cfa4a 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test213/Solution.java @@ -35,8 +35,8 @@ public int rob(int[] nums) { if (len == 1) { return nums[0]; } - return Math.max(myRob(Arrays.copyOfRange(nums, 0, len - 1)), - myRob(Arrays.copyOfRange(nums, 1, len))); + return Math.max(myRob2(Arrays.copyOfRange(nums, 0, len - 1)), + myRob2(Arrays.copyOfRange(nums, 1, len))); } @@ -64,7 +64,7 @@ private int myRob(int[] nums) { @Test public void test() { - int[] nums = {1, 2, 3, 1}; + int[] nums = {2, 3, 2}; System.out.println(rob(nums)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java index 21f442a..b854cc6 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test279/Solution.java @@ -26,7 +26,7 @@ public int numSquares(int n) { //dp[0] = 0; //题意是给定正整数,不用考虑0 for (int i = 1; i <= n; i++) { - dp[i] = i; + dp[i] = i; // 赋初始值,最多是有它本身这么多 for (int j = 1; i - j * j >= 0; j++) { dp[i] = Math.min(dp[i], dp[i - j * j] + 1); } @@ -36,6 +36,6 @@ public int numSquares(int n) { @Test public void test() { - System.out.println(numSquares(9)); + System.out.println(numSquares(12)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java index 6c1a119..7dcf298 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test300/Solution.java @@ -15,17 +15,23 @@ * * @Auther: zhunn * @Date: 2020/11/4 21:03 - * @Description: 最长上升子序列:1-动态规划;2-动态规划-优化空间(贪心+二分查找) + * @Description: 最长上升子序列:1-动态规划(推荐);2-动态规划-优化空间(贪心+二分查找) */ public class Solution { + /** + * 1-动态规划(推荐) + * + * @param nums + * @return + */ public int lengthOfLIS(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int len = nums.length; - int[] dp = new int[len]; + int[] dp = new int[len]; // dp[i]标识以nums[i]结尾的[上升子序列]的长度 Arrays.fill(dp, 1); int res = 0; @@ -43,7 +49,7 @@ public int lengthOfLIS(int[] nums) { @Test public void test() { - int[] nums = {10, 9, 2, 5, 3, 7, 101, 18}; + int[] nums = {10, 9, 2, 5, 3, 7, 8, 101, 18}; System.out.println(lengthOfLIS(nums)); } } diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java index 483a6a7..95c3aee 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test343/Solution.java @@ -3,7 +3,6 @@ import org.junit.Test; /** - * 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 * 343. 整数拆分 * 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。 * 示例 1: @@ -32,8 +31,9 @@ public int integerBreak(int n) { for (int i = 2; i <= n; i++) { for (int j = 1; j < i; j++) { - dp[i] = Math.max(dp[i], Math.max(dp[i - j] * j, (i - j) * j)); // 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j×(i−j); + // 将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j×(i−j); // 将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j×dp[i−j]。 + dp[i] = Math.max(dp[i], Math.max(dp[i - j] * j, (i - j) * j)); } } return dp[n]; diff --git a/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java b/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java index 0d50af4..4e5af7f 100644 --- a/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/dynamic/test72/Solution.java @@ -42,15 +42,15 @@ public int minDistance(String word1, String word2) { } int[][] dp = new int[m + 1][n + 1]; // 多开一行一列是为了保存边界条件,即字符长度为 0 的情况,这一点在字符串的动态规划问题中比较常见 - for (int i = 0; i < m + 1; i++) { // 边界状态初始化:当 word 2 长度为 0 时,将 word1 的全部删除 + for (int i = 0; i <= m; i++) { // 边界状态初始化:当 word 2 长度为 0 时,将 word1 的全部删除 dp[i][0] = i; } - for (int j = 0; j < n + 1; j++) { // 当 word1 长度为 0 时,就插入所有 word2 的字符 + for (int j = 0; j <= n; j++) { // 当 word1 长度为 0 时,就插入所有 word2 的字符 dp[0][j] = j; } - for (int i = 1; i < m + 1; i++) { - for (int j = 1; j < n + 1; j++) { + for (int i = 1; i <= m; i++) { + for (int j = 1; j <= n; j++) { if (word1.charAt(i - 1) == word2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1]; } else { @@ -66,5 +66,4 @@ public void test() { System.out.println(minDistance("horse", "ros")); } - } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index da1e78d..94d3db1 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -194,15 +194,20 @@ dynamic 714、 可以买卖(交易)多次,一次买卖含一次手续费 (股票买卖系列 end) 70. 爬楼梯 *** 1-迭代,2-动态规划,dp[i] = dp[i - 1] + dp[i - 2]; -120. 三角形最小路径和 *** for(int i = n - 1; i >= 0; i--);for(int j = 0; j <= i; j++);dp[j]=Math.min(dp[j],dp[j+1]) + triangle.get(i).get(j); -64. 最小路径和 *** 初始化dp[0][0] = grid[0][0];初始化第0行和第0列,for(int j=1;j= 0; i--);for(int j = 0; j <= i; j++);dp[j]=Math.min(dp[j],dp[j+1]) + triangle.get(i).get(j); +64. 最小路径和(方格子自顶向下) 初始化dp[0][0]=grid[0][0];边界初始化第0行和第0列,for(int j=1;j= 0; j++){dp[i] = Math.min(dp[i], dp[i - j * j] + 1);} +343. 整数拆分-返回最大乘积 int[] dp=new int[n+1]; dp[i] 表示将正整数 i 拆分成至少两个正整数的和之后,这些正整数的最大乘积 + for (int i = 2; i <= n; i++);for(int j = 1; j < i; j++){dp[i]=Math.max(dp[i], Math.max(dp[i-j]*j, (i-j) * j));} +72. 编辑距离 *** 边界初始化,if (word1.charAt(i - 1) == word2.charAt(j - 1)) {dp[i][j] = dp[i - 1][j - 1];}else{ + dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i][j - 1]) + 1;} +198. 打家劫舍 *** dp[i] 表示前 i 间房屋能偷窃到的最高总金额。dp[i] = Math.max(dp[i - 2]+nums[i], dp[i-1]);第i间房偷dp[i-2]+nums[i];第i间房不偷dp[i-1] +213. 打家劫舍II (环形房屋在198题的基础上,选择不偷第一家或不偷最后一家)Math.max(myRob2(Arrays.copyOfRange(nums, 0, len-1)),myRob2(Arrays.copyOfRange(nums,1,len))); +337. 打家劫舍III (二叉树房屋) 1-树的后序遍历; +(dp[0]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点不偷; dp[1]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点偷) +int[] left = dfs(root.left); int[] right = dfs(root.right);int[] res = new int[2]; +res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);res[1] = root.val + left[0] + right[0]; \ No newline at end of file From 83d128de568a0282a028c24f46cd239546614d68 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 21 Dec 2020 18:14:42 +0800 Subject: [PATCH 47/63] note --- .../java/com/chen/algorithm/znn/array/test26/Solution.java | 2 +- src/main/java/com/chen/algorithm/znn/note | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java index 1045a5a..c711688 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test26/Solution.java @@ -32,7 +32,7 @@ public int removeDuplicates(int[] nums) { int i = 0; for (int j = 0; j < nums.length; j++) { - if (nums[j] != nums[i]) { + if (nums[j] != nums[i]) { // 不相等的重新放入数组中,重新组成无重复数组 i++; nums[i] = nums[j]; } diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 94d3db1..54a2a45 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -63,8 +63,8 @@ sort 快速排序 sort/QuickSort (nlogn 不稳定)** string -3. 无重复字符的最长子串 *** 滑动窗口 -5. 最长回文子串 动态规划 +3. 无重复字符的最长子串 *** 滑动窗口,Map,start = Math.max(start, map.get(c));map.put(c, end+1);res = Math.max(res, end-start+1); +5. 最长回文子串 动态规划 dp[i][j]表示字符串 s 的第 i 到 j 个字母组成的串是否是回文串(x 表示增量,子串长度,) 14. 最长公共前缀 *** 415. 字符串相加 @@ -72,7 +72,7 @@ hash 15. 三数之和 *** 排序+双指针 18. 四数之和 ??? 排序+双指针 49. 字母异位词分组 *** 排序+map -242. 有效的字母异位词 *** 哈希表 +242. 有效的字母异位词 *** 迭代,int[] counter = new int[26];counter[s.charAt(i) - 'a']++;counter[t.charAt(i) - 'a']--;if(counter[i] != 0){return false;} array 剑指 Offer 29. 顺时针打印矩阵 left right top bottom From 1f703f9de8c5803f73c36c8c7750e93e3e54d7b5 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 21 Dec 2020 19:07:25 +0800 Subject: [PATCH 48/63] note --- src/main/java/com/chen/algorithm/znn/array/test56/Solution.java | 2 +- src/main/java/com/chen/algorithm/znn/note | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java index 6b5572e..2a8b683 100644 --- a/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/test56/Solution.java @@ -88,7 +88,7 @@ public int[][] merge1(int[][] intervals) { if (merged.size() == 0 || merged.get(merged.size() - 1)[1] < L) { merged.add(new int[]{L, R}); } else { - merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R); + merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], R); // 已经排过序,不需要比对起始值 } } return merged.toArray(new int[merged.size()][]); diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 54a2a45..bf63940 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -84,7 +84,7 @@ array 283. 移动零 双指针(方法同27题移除元素) 34. 在排序数组中查找元素的第一个和最后一个位置 二分查找 56. 合并区间 排序 -69. x 的平方根 *** 二分法 +69. x 的平方根 *** 二分法与50题Pow(x, n)相对应 88. 合并两个有序数组 *** p1,p2,p3=p1+p2 238. 除自身以外数组的乘积 先求出左右两边的乘积再相乘 240. 搜索二维矩阵 II 从左下角开始 From 580977873a12342a95a9c83769ffd57735c98f0f Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 22 Dec 2020 18:40:55 +0800 Subject: [PATCH 49/63] note --- .../com/chen/algorithm/znn/array/offer/test29/Solution.java | 4 ++-- src/main/java/com/chen/algorithm/znn/note | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java index 0942064..1f5d067 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test29/Solution.java @@ -65,11 +65,11 @@ public int[] spiralOrder1(int[][] matrix) { int left = 0, right = matrix[0].length - 1, top = 0, bottom = matrix.length - 1; while (numEle >= 1) { - for (int i = left; i <= right && numEle >= 1; i++) { + for (int i = left; i <= right && numEle >= 1; i++) { //注意边界 >=,<= result[idx++] = matrix[top][i]; numEle--; } - top++; + top++; //注意边界 >=,<=,因为这里都做了递增和递减处理,所以遍历需要带等号 for (int i = top; i <= bottom && numEle >= 1; i++) { result[idx++] = matrix[i][right]; numEle--; diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index bf63940..3524331 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -63,7 +63,7 @@ sort 快速排序 sort/QuickSort (nlogn 不稳定)** string -3. 无重复字符的最长子串 *** 滑动窗口,Map,start = Math.max(start, map.get(c));map.put(c, end+1);res = Math.max(res, end-start+1); +3. 无重复字符的最长子串(返回子串长度) 滑动窗口,Map,start = Math.max(start, map.get(c));map.put(c, end+1);res = Math.max(res, end-start+1); 5. 最长回文子串 动态规划 dp[i][j]表示字符串 s 的第 i 到 j 个字母组成的串是否是回文串(x 表示增量,子串长度,) 14. 最长公共前缀 *** 415. 字符串相加 @@ -90,7 +90,7 @@ array 240. 搜索二维矩阵 II 从左下角开始 287. 寻找重复数 排序迭代/快慢指针 448. 找到所有数组中消失的数字 迭代并赋值为-1,最后大于0的既满足(数组中数都大于0) -581. 最短无序连续子数组 排序迭代对比 +581. 最短无序连续子数组 排序迭代对比原数组 674. 最长连续递增序列 *** 滑动窗口 704. 二分查找 *** From f568e6d28606500604f497aecc9c2a1b90cd81db Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 15 Jan 2021 14:55:32 +0800 Subject: [PATCH 50/63] note --- src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java index 9c058bb..dfb39c5 100644 --- a/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/greedy/test55/Solution.java @@ -3,6 +3,7 @@ import org.junit.Test; /** + * https://leetcode-cn.com/problems/jump-game/solution/dong-tai-gui-hua-yu-tan-xin-suan-fa-jie-jue-ci-wen/ * 55. 跳跃游戏 * 给定一个非负整数数组,你最初位于数组的第一个位置。 * 数组中的每个元素代表你在该位置可以跳跃的最大长度。 From 7344bfbacc4ad3a764f9feecadc87fdd9eb84798 Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 15 Jan 2021 18:11:30 +0800 Subject: [PATCH 51/63] update --- .../java/com/chen/algorithm/znn/backtrack/test78/Solution.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java b/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java index 93c9202..1e54951 100644 --- a/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/backtrack/test78/Solution.java @@ -31,9 +31,6 @@ public class Solution { public List> subsets(int[] nums) { - if (nums == null || nums.length == 0) { - return null; - } List> res = new ArrayList<>(); backtrack(0, nums, new ArrayList<>(), res); return res; From 440218f6240cdb1576154c0cae4474a036e08b1b Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 25 Jan 2021 17:44:38 +0800 Subject: [PATCH 52/63] fix --- src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java index e7394f3..5582728 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java @@ -88,7 +88,7 @@ public int minDepth2(TreeNode root) { } if (node.left == null && node.right == null) { - return minDepth; + return minDepth + 1; } } } From 2a587af95532da13752aad605f516b8055f29f27 Mon Sep 17 00:00:00 2001 From: zhunn Date: Mon, 25 Jan 2021 17:46:54 +0800 Subject: [PATCH 53/63] note --- .../java/com/chen/algorithm/znn/tree/test111/Solution.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java index 5582728..672a5ac 100644 --- a/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/tree/test111/Solution.java @@ -88,7 +88,7 @@ public int minDepth2(TreeNode root) { } if (node.left == null && node.right == null) { - return minDepth + 1; + return minDepth; } } } @@ -101,7 +101,7 @@ public void test() { TreeNode right = new TreeNode(7, new TreeNode(15), new TreeNode(20)); TreeNode root = new TreeNode(3, left, right); - int res = minDepth2(left); + int res = minDepth2(root); System.out.println(res); } } From f8e54fd9e4dd40395072464a4310c225eaa8882a Mon Sep 17 00:00:00 2001 From: zhunn Date: Tue, 26 Jan 2021 16:58:18 +0800 Subject: [PATCH 54/63] thread --- .../chen/algorithm/znn/thread/ThreadTest.java | 43 +++++++++++ .../algorithm/znn/thread/ThreadTest2.java | 42 +++++++++++ .../algorithm/znn/thread/ThreadTest3.java | 70 +++++++++++++++++ .../algorithm/znn/thread/ThreadTest4.java | 65 ++++++++++++++++ .../algorithm/znn/thread/ThreadTest5.java | 75 +++++++++++++++++++ 5 files changed, 295 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/thread/ThreadTest.java create mode 100644 src/main/java/com/chen/algorithm/znn/thread/ThreadTest2.java create mode 100644 src/main/java/com/chen/algorithm/znn/thread/ThreadTest3.java create mode 100644 src/main/java/com/chen/algorithm/znn/thread/ThreadTest4.java create mode 100644 src/main/java/com/chen/algorithm/znn/thread/ThreadTest5.java diff --git a/src/main/java/com/chen/algorithm/znn/thread/ThreadTest.java b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest.java new file mode 100644 index 0000000..5282daa --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest.java @@ -0,0 +1,43 @@ +package com.chen.algorithm.znn.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @Auther: zhunn + * @Date: 2021/1/26 13:47 + * @Description: 仅使用volatile关键字 + */ +public class ThreadTest { + + private volatile static int count = 0; + + private volatile static boolean flag = true; + + + public static void main(String[] args) { + + // 启用线程池 + ExecutorService executorService = Executors.newCachedThreadPool(); + + // 先从0,偶数开始 + executorService.execute(() -> { + while (count <= 100) { + if (flag) { + System.out.println("偶数:" + count++); + flag = false; + } + } + }); + executorService.execute(() -> { + while (count <= 100) { + if (!flag) { + System.out.println("奇数:" + count++); + flag = true; + } + } + }); + executorService.shutdown(); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/thread/ThreadTest2.java b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest2.java new file mode 100644 index 0000000..a0073c4 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest2.java @@ -0,0 +1,42 @@ +package com.chen.algorithm.znn.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @Auther: zhunn + * @Date: 2021/1/26 13:54 + * @Description: 使用AtomicInteger + */ +public class ThreadTest2 { + private static AtomicInteger count = new AtomicInteger(0); + + private volatile static boolean flag = true; + + public static void main(String[] args) { + + // 启用线程池 + ExecutorService executorService = Executors.newCachedThreadPool(); + + // 先从0,偶数开始 + executorService.execute(() -> { + while (count.get() <= 100) { + if (flag) { + System.out.println("偶数:" + count.getAndIncrement()); + flag = false; + } + } + }); + executorService.execute(() -> { + while (count.get() <= 100) { + if (!flag) { + System.out.println("奇数:" + count.getAndIncrement()); + flag = true; + } + } + }); + executorService.shutdown(); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/thread/ThreadTest3.java b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest3.java new file mode 100644 index 0000000..9b4c79a --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest3.java @@ -0,0 +1,70 @@ +package com.chen.algorithm.znn.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * @Auther: zhunn + * @Date: 2021/1/26 13:55 + * @Description: 使用synchronized + */ +public class ThreadTest3 { + // 需要打印的资源: 0~100 + private static int count = 0; + + private static Object lock = new Object(); + + public static void main(String[] args) { + + // 启用线程池 + ExecutorService executorService = Executors.newCachedThreadPool(); + + // 先从0,偶数开始 + executorService.execute(() -> { + while (count <= 100) { + synchronized (lock) { + try { + System.out.println("偶: " + count); + count++; + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 释放奇数线程 + lock.notifyAll(); + if (count <= 100) { + try { + // 防止偶数线程继续执行 + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + }); + executorService.execute(() -> { + while (count <= 100) { + synchronized (lock) { + try { + System.out.println("奇: " + count); + count++; + } catch (Exception e) { + e.printStackTrace(); + } finally { + lock.notifyAll(); + if (count <= 100) { + try { + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + }); + executorService.shutdown(); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/thread/ThreadTest4.java b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest4.java new file mode 100644 index 0000000..e029e83 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest4.java @@ -0,0 +1,65 @@ +package com.chen.algorithm.znn.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @Auther: zhunn + * @Date: 2021/1/26 13:55 + * @Description: 使用ReentrantLock与Condition + */ +public class ThreadTest4 { + // 需要打印的资源: 0~100 + private static int count = 0; + + // 通过condition控制线程竞争 + private static final ReentrantLock lock = new ReentrantLock(); + private static final Condition condition1 = lock.newCondition(); + private static final Condition condition2 = lock.newCondition(); + + public static void main(String[] args) { + + // 启用线程池 + ExecutorService executorService = Executors.newCachedThreadPool(); + + // 先从0,偶数开始 + executorService.execute(() -> { + while (count <= 100) { + try { + lock.lock(); + System.out.println("偶: " + count); + count++; + // 把偶数线程阻塞 + condition1.await(); + // 把奇数线程唤醒 + condition2.signal(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + }); + executorService.execute(() -> { + while (count <= 100) { + try { + lock.lock(); + System.out.println("奇: " + count); + count++; + // 把偶数线程唤醒 + condition1.signal(); + // 把奇数线程阻塞 + condition2.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + }); + executorService.shutdown(); + } + +} diff --git a/src/main/java/com/chen/algorithm/znn/thread/ThreadTest5.java b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest5.java new file mode 100644 index 0000000..6a20a02 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/thread/ThreadTest5.java @@ -0,0 +1,75 @@ +package com.chen.algorithm.znn.thread; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @Auther: zhunn + * @Date: 2021/1/26 13:56 + * @Description: 仅使用ReentrantLock + */ +public class ThreadTest5 { + // 需要打印的资源: 0~100 + private static int count = 0; + + // 是否执行打印的标志 + private static volatile boolean flag = false; + + // 通过加锁控制线程竞争 + private static final ReentrantLock lock = new ReentrantLock(); + + public static void main(String[] args) { + + // 启用线程池 + ExecutorService executorService = Executors.newCachedThreadPool(); + + // 先从0,偶数开始 + executorService.execute(() -> { + while (count <= 100) { + if (!flag) { + try { + lock.lock(); + System.out.println("偶: " + count); + count++; + // 只有flag变为true了,此线程才不会接着执行,将争夺权给奇数线程 + flag = true; + } finally { + lock.unlock(); + } + } else { + // 防止线程空转 + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }); + executorService.execute(() -> { + while (count <= 100) { + // 当偶数线程执行后flag变为true,此线程可以执行了 + if (flag) { + try { + lock.lock(); + System.out.println("奇: " + count); + count++; + // 让出CPU + flag = false; + } finally { + lock.unlock(); + } + } else { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }); + executorService.shutdown(); + } + +} From 03a54ec270b03ae5327d69a6691371c0eeacfb77 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 28 Jan 2021 16:32:25 +0800 Subject: [PATCH 55/63] note --- .../java/com/chen/algorithm/znn/string/test3/Solution.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java index 7745116..f9fa4f1 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java @@ -39,8 +39,8 @@ public int lengthOfLongestSubstring(String s) { Map map = new HashMap<>(); int ans = 0; int n = s.length(); - - for (int start = 0, end = 0; end < n; end++) { + int start = 0; + for (int end = 0; end < n; end++) { char c = s.charAt(end); if (map.containsKey(c)) { start = Math.max(start, map.get(c)); From ec46f81e1ecd80ed92fa61e95e5e812bc572864e Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 28 Jan 2021 16:51:40 +0800 Subject: [PATCH 56/63] string --- .../algorithm/znn/string/test5/Solution.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java index 1715567..31e742d 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test5/Solution.java @@ -20,6 +20,7 @@ * @Description: 最长回文子串: * 1-动态规划;时间复杂度:O(n2),空间复杂度:O(n2) * 2-中心扩展算法;时间复杂度:O(n2),空间复杂度:O(1) + * 3-判断字符串是否是回文串;时间复杂度:O(n),空间复杂度:O(1) */ public class Solution { @@ -92,12 +93,40 @@ private int expandAroundCenter(String s, int left, int right) { return right - left - 1; } + /** + * 3-判断字符串是否是回文串 + * + * @param s + * @return + */ + public boolean isPalindrome(String s) { + if (s == null || s.length() == 0) { + return false; + } + + int len = s.length(); + int j = len - 1; + for (int i = 0; i < len / 2; i++) { + char head = s.charAt(i); + char tail = s.charAt(j); + if (head != tail) { + return false; + } + j--; + } + return true; + } + @Test public void test() { System.out.println("123456".substring(0, 3)); System.out.println(longestPalindrome("dcacdefd")); System.out.println(longestPalindrome("babad")); System.out.println(longestPalindrome("cbbd")); + System.out.println("---------------"); + System.out.println(isPalindrome("12345")); + System.out.println(isPalindrome("12321")); + System.out.println(isPalindrome("1221")); } } From 444670a9b4a6cba7b8edce6240b27571f06479e1 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Mon, 1 Feb 2021 23:43:18 +0800 Subject: [PATCH 57/63] array --- .../com/chen/algorithm/znn/array/offer/test57/Solution.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java index 9d6e985..6dd3524 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java @@ -66,7 +66,7 @@ public int[][] findContinuousSequence(int target) { int sum = 0; List res = new ArrayList<>(); - while (left <= target / 2) { + while (left <= target / 2) { // 假设窗口左边界i=target/2, i+1=target/2 +1,那么i + (i+1) = target+1,即最小的窗口的元素之和就已经比target大了,所以当i>=target/2时不可能有一个窗口长度>=2的答案。 这也归因于本题的特殊要求:答案数组至少包含两个元素。 如果没有上述要求,那么在i>=target/2的范围内还存在当i == target时的结果,窗口长度==1。 if (sum < target) { sum += right; right++; From 46ec69b85a7123dc493732d42eff0fc8031a0c6f Mon Sep 17 00:00:00 2001 From: chenweijie Date: Tue, 2 Feb 2021 00:00:15 +0800 Subject: [PATCH 58/63] array --- .../com/chen/algorithm/znn/array/offer/test57/Solution.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java index 6dd3524..201c775 100644 --- a/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/array/offer/test57/Solution.java @@ -75,7 +75,7 @@ public int[][] findContinuousSequence(int target) { left++; } else { int[] arr = new int[right - left]; - for (int i = left; i < right; i++) { + for (int i = left; i < right; i++) { // 因为当sum=target的时候,此时sum加的是j,而j此时又进行了++操作,相当于j右移了一下,不在sum计算范围内,所以是左闭右开 arr[i - left] = i; } res.add(arr); From 149e13c7501ff6250c77e23feea87b0b83fdbfbc Mon Sep 17 00:00:00 2001 From: chenweijie Date: Tue, 2 Feb 2021 21:53:05 +0800 Subject: [PATCH 59/63] string --- .../algorithm/znn/string/test3/Solution.java | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java index f9fa4f1..94d9da1 100644 --- a/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java +++ b/src/main/java/com/chen/algorithm/znn/string/test3/Solution.java @@ -3,9 +3,7 @@ import org.junit.Test; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; /** * https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/hua-jie-suan-fa-3-wu-zhong-fu-zi-fu-de-zui-chang-z/ @@ -31,6 +29,11 @@ */ public class Solution { + /** + * 返回子串长度 + * @param s + * @return + */ public int lengthOfLongestSubstring(String s) { if (s == null || s.length() == 0) { return 0; @@ -52,10 +55,38 @@ public int lengthOfLongestSubstring(String s) { return ans; } + /** + * 返回子串 + * @param s + * @return + */ + public String getSubString(String s) { + if (s == null || s.length() == 0) { + return s; + } + Map map = new HashMap<>(); + int start = 0; + String sub = ""; + for (int end = 0; end < s.length(); end++) { + char c = s.charAt(end); + if (map.containsKey(c)) { + start = Math.max(start, map.get(c)); + } + + if (sub.length() < end - start + 1) { + sub = s.substring(start, end + 1); + } + map.put(c, end + 1); + } + return sub; + } + @Test public void test() { System.out.println(lengthOfLongestSubstring("abcabcbb")); System.out.println(lengthOfLongestSubstring("bbbbb")); System.out.println(lengthOfLongestSubstring("pwwkew")); + System.out.println(getSubString("pwwkew")); + } } From d1bd797138ac90674158cc21f6ee7bd65e9e6f4b Mon Sep 17 00:00:00 2001 From: chenweijie Date: Tue, 2 Feb 2021 22:52:55 +0800 Subject: [PATCH 60/63] array --- .../znn/array/test1712/Solution.java | 15 ++++++ .../algorithm/znn/array/test561/Solution.java | 46 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/array/test1712/Solution.java create mode 100644 src/main/java/com/chen/algorithm/znn/array/test561/Solution.java diff --git a/src/main/java/com/chen/algorithm/znn/array/test1712/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test1712/Solution.java new file mode 100644 index 0000000..9c4b1ae --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test1712/Solution.java @@ -0,0 +1,15 @@ +package com.chen.algorithm.znn.array.test1712; + +/** + * https://leetcode-cn.com/problems/ways-to-split-array-into-three-subarrays/ + * 我们称一个分割整数数组的方案是 好的,当它满足: + * + * 数组被分成三个 非空连续子数组,从左至右分别命名为left,mid,right。 + * left中元素和小于等于mid中元素和,mid中元素和小于等于right中元素和。 + * 给你一个 非负 整数数组nums,请你返回好的 分割 nums方案数目。由于答案可能会很大,请你将结果对 109+ 7取余后返回。 + * + * + * + */ +public class Solution { +} diff --git a/src/main/java/com/chen/algorithm/znn/array/test561/Solution.java b/src/main/java/com/chen/algorithm/znn/array/test561/Solution.java new file mode 100644 index 0000000..6e9190b --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/array/test561/Solution.java @@ -0,0 +1,46 @@ +package com.chen.algorithm.znn.array.test561; + +import org.junit.Test; + +import java.util.Arrays; + +/** + * https://leetcode-cn.com/problems/array-partition-i/solution/shu-zu-chai-fen-i-by-leetcode/ + * 给定长度为2n的整数数组 nums ,你的任务是将这些数分成n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到n 的 min(ai, bi) 总和最大。 + * 返回该 最大总和 。 + * 示例 1: + * 输入:nums = [1,4,3,2] + * 输出:4 + * 解释:所有可能的分法(忽略元素顺序)为: + * 1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3 + * 2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3 + * 3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4 + * 所以最大总和为 4 + * + * @Auther: zhunn + * @Date: 2020/11/5 18:46 + * @Description: 数组拆分 I + */ +public class Solution { + + public int arrayPairSum(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + //初始一个结果 + int sum = 0; + //对数组进行升序排序 + Arrays.sort(nums); + //循环数组,选择索引为0、2、4、6、8...这样可以保证获取每两个元素的最小值 + for (int i = 0; i < nums.length; i += 2) { + sum += nums[i]; //将最小值加起来 + } + return sum; + } + + @Test + public void test() { + int[] nums = new int[]{1, 4, 3, 2}; + System.out.println(arrayPairSum(nums)); + } +} From c3d0bcc7f2e033d05423075df25ff23a9d252028 Mon Sep 17 00:00:00 2001 From: zhunn Date: Thu, 18 Feb 2021 18:50:12 +0800 Subject: [PATCH 61/63] note --- src/main/java/com/chen/algorithm/znn/note | 65 +++++++++++++++++++++-- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 3524331..8cc37db 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -166,8 +166,8 @@ greedy backtrack 36. 有效的数独(9X9) 1-哈希数组(占用空间)2-二维数组(推荐),第一维表示位置,第二维表示1-9数字,出现过对应二维数组值置为1标识起来,下次循环等于1直接return false -39. 组合总和 *** 元素可以取多次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i) -40. 组合总和 II ***元素只能取一次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i+1);if (i > start && nums[i - 1] == nums[i])(剪枝) +39. 组合总和 *** 元素无重复可以取多次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i) +40. 组合总和 II ***元素有重复只能取一次(结果都不可重复) 回溯法-先排序,递归然后循环并剪枝,最后回溯dfs(start=i+1);if (i > start && nums[i - 1] == nums[i])(剪枝) 46. 全排列 *** 给定数组无重复元素(结果都不可重复) 回溯法-depth、boolen[] 47. 全排列II ***给定数组有重复元素(结果都不可重复) 回溯法-先排序depth、boolen[];i > 0 && nums[i] == nums[i - 1] && !used[i - 1](剪枝) 78. 子集 *** 给定数组无重复元素(结果都不可重复) 回溯法-start,dfs(start=i + 1),递归方法先res.add(new ArrayList<>(curList)); @@ -210,4 +210,63 @@ dynamic 337. 打家劫舍III (二叉树房屋) 1-树的后序遍历; (dp[0]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点不偷; dp[1]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点偷) int[] left = dfs(root.left); int[] right = dfs(root.right);int[] res = new int[2]; -res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);res[1] = root.val + left[0] + right[0]; \ No newline at end of file +res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);res[1] = root.val + left[0] + right[0]; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +2021年flag: + +衣食住行 + +工作(工作内容、业务方向、技术成长包括其他方面成长,知识面以及语言组织能力和沟通能力;学习计划) +生活(衣+美妆、食、住房、兴趣爱好) +健康(运动、可与兴趣爱好结合起来) +旅游(旅游计划+拍照记录vlog,归为生活的一部分) +家庭(隶属于生活) + + + +study plan +技术书籍:10本 +非技术书籍:5本 + + +期望收货:技术方面,技术稳固扎实了,用于实践后有一定的成长 +非技术方面,语言组织能力、沟通表达能力、分析业务问题能力 + +知识面扩展、技术成长、语言组织能力以及沟通表达能力提高、看待问题的视角更宽更高(尤其是业务方面问题)、 +理财能力提高、生活方面技能(厨艺、美妆、服装搭配甚至自己裁剪制作衣服(提高DIY动手能力)、 +旅游拍照技能+制作vlog技能、培养一个兴趣爱好,技能锻炼身体保持健康又能放松身心) + From bd82a5861a69ad0d3d3ccd45ca8f11a9ac9e4475 Mon Sep 17 00:00:00 2001 From: zhunn Date: Fri, 19 Feb 2021 10:11:30 +0800 Subject: [PATCH 62/63] note --- src/main/java/com/chen/algorithm/znn/note | 59 ----------------------- 1 file changed, 59 deletions(-) diff --git a/src/main/java/com/chen/algorithm/znn/note b/src/main/java/com/chen/algorithm/znn/note index 8cc37db..5d3cf38 100644 --- a/src/main/java/com/chen/algorithm/znn/note +++ b/src/main/java/com/chen/algorithm/znn/note @@ -211,62 +211,3 @@ dynamic (dp[0]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点不偷; dp[1]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点偷) int[] left = dfs(root.left); int[] right = dfs(root.right);int[] res = new int[2]; res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);res[1] = root.val + left[0] + right[0]; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -2021年flag: - -衣食住行 - -工作(工作内容、业务方向、技术成长包括其他方面成长,知识面以及语言组织能力和沟通能力;学习计划) -生活(衣+美妆、食、住房、兴趣爱好) -健康(运动、可与兴趣爱好结合起来) -旅游(旅游计划+拍照记录vlog,归为生活的一部分) -家庭(隶属于生活) - - - -study plan -技术书籍:10本 -非技术书籍:5本 - - -期望收货:技术方面,技术稳固扎实了,用于实践后有一定的成长 -非技术方面,语言组织能力、沟通表达能力、分析业务问题能力 - -知识面扩展、技术成长、语言组织能力以及沟通表达能力提高、看待问题的视角更宽更高(尤其是业务方面问题)、 -理财能力提高、生活方面技能(厨艺、美妆、服装搭配甚至自己裁剪制作衣服(提高DIY动手能力)、 -旅游拍照技能+制作vlog技能、培养一个兴趣爱好,技能锻炼身体保持健康又能放松身心) - From 09fc9f8f2bfb3047b974c3a6d3421ecbe47e90a1 Mon Sep 17 00:00:00 2001 From: chenweijie Date: Wed, 10 Mar 2021 21:50:53 +0800 Subject: [PATCH 63/63] note --- .../com/chen/algorithm/znn/InterviewTest.java | 128 +++++++ ...70\351\235\242\350\257\225\351\242\230.md" | 118 +++++++ ...50\346\204\217\344\272\213\351\241\271.md" | 322 ++++++++++++++++++ 3 files changed, 568 insertions(+) create mode 100644 src/main/java/com/chen/algorithm/znn/InterviewTest.java create mode 100644 "src/main/java/com/chen/algorithm/znn/\345\220\204\345\205\254\345\217\270\351\235\242\350\257\225\351\242\230.md" create mode 100644 "src/main/java/com/chen/algorithm/znn/\351\235\242\350\257\225\346\263\250\346\204\217\344\272\213\351\241\271.md" diff --git a/src/main/java/com/chen/algorithm/znn/InterviewTest.java b/src/main/java/com/chen/algorithm/znn/InterviewTest.java new file mode 100644 index 0000000..5b4ce13 --- /dev/null +++ b/src/main/java/com/chen/algorithm/znn/InterviewTest.java @@ -0,0 +1,128 @@ +package com.chen.algorithm.znn; + + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class InterviewTest { + + /* + [ +{id:1, name:xx1, pid:0}, +{id:2, name:xx2, pid:0}, +{id:3, name:xx3, pid:1}, +{id:4, name:xx4, pid:3}, +{id:5, name:xx5, pid:4}, +] + */ + + class Node{ + private int id; + private String name; + private int pid; + private List children; + public Node(){} + public Node(int pid){ + this.pid = pid; + } + + public Node(int id,String name, int pid){ + this.id = id; + this.name = name; + this.pid = pid; + } + } + + public Node getNode(List nodeList){ + if(nodeList == null || nodeList.size() == 0){ + return null; + } + Map> nodeMap = new HashMap<>(); + Map originNodeMap = new HashMap<>(); + + for(int i =0;i{ + Node fNode = originNodeMap.get(pid); + if(fNode == null){ + fNode = new Node(pid,"xxxpid",-1); + if(root.children == null){ + root.children = Arrays.asList(fNode); + }else{ + root.children.add(fNode); + } + } + fNode.children = nodeMap.get(pid); + }); + return root; + } + + @Test + public void test(){ + +// [ +// {id:1, name:xx1, pid:0}, +// {id:2, name:xx2, pid:0}, +// {id:3, name:xx3, pid:1}, +// {id:4, name:xx4, pid:3}, +// {id:5, name:xx5, pid:4}, +//] + System.out.println(isHuiwen("12321")); + } + + public boolean isPalling(String s){ + if(s == null || s.length() == 0){ + return false; + } + + int len = s.length(); + boolean[][] dp = new boolean[len][len]; + for(int x = 0;x积累什么?积累工作中遇到的问题,踩过的坑,以及知识的亮点运用。 + +2->思考什么?skiplist,对于自己的工作以及未来规划多梳理多总结并及时调整变动。梳理近阶段工作,总结学习到了什么,收获了什么,有哪些方面成长,又有哪些方面的不足。 + +3->如何系统的学习,看相关的书籍同时看源码,动手操作写demo尽可能应用到实际项目中。) + +二、1、项目设计细节,项目难点有哪些?项目目前还需要优化的点有哪些? + +2、框架相关的题。注重实际项目中使用情况,关注你在实际项目中是否很好的灵活的使用了。为什么这样使用,是否关注了框架这样设计的好处,你是否用对了。 + +3、问组件的原理及设计,问什么这样设计,这样设计的好处以及为了解决什么问题,进而关联到系统设计及场景设计题。通过这个分析你实际项目经验是否足够丰富,同时考察逻辑思维以及表达能力 + +4、实际开发中,除了功能实现,是否会考虑服务或接口的可用性,稳定性,考虑到最坏情况,(考虑到服务的要求是什么,需要高并发、高性能、高可用)服务宕机如何避免,如果宕机了如何快速恢复并修复期间丢失的数据等。 + +其实就是需要对开发这个服务了如指掌,了解到它的方方面面。针对服务相对应的指标去衡量它。 + +5、线上紧急问题相关,解决过哪些大事故或线上问题,如何解决的?给出一个线上问题的场景题,问如何定位和排查,而后如何解决。 + +6、平时都怎么去学习提升自己技术的?最近看了哪些书,举例说明(举mysql的掘金小册,dubbo相关的官方文档)最近在梳理知识点以及在公司做的项目,做一些总结与思考,准备去面试,最近系统看的书比较少。会问通过这些书或技术文档收获了什么,来以此验证你是否真正看了这些书。 + +7、优缺点:会问一些性格方面的问题,优缺点:优点:对工作比较负责,做事情比较专注,细致认真,为人处世都比较靠谱。缺点:说话比较直,话比较少,比较慢热,说话锻炼表达能力以及语言组织能力,这方面没有达到我的预期。2.如何处理同事之间矛盾,如何处理与产品或上级领导之间的需求冲突等。3.有哪些兴趣爱好,平时业余时间都做些什么? + +8、未来的职业规划,近3年(稳固现有常见的技术,关注新技术,多做事情,多思考,关注跟人沟通打交道这方面的技巧为做管理层储备。),近5年的规划(往管理方向去走,做业务leader)。(对于所面的岗位的业务是否有了解过,通过这个问题来了解你对公司此岗位的意向是否大。) + + + +各公司三面情况总结: + +小米三面:会问算法题,以及项目设计相关的题,对没有标准答案的题,尽量思考清楚之后,清晰表达出来自己的想法,尽量多说一些有价值有技术含量的信息。面试官想要的可能是你的清晰的思路,从此看出来你解决问题的能力,同时能落地,能写出来。 + +58三面:项目挂了会触发什么问题,如何保证项目的稳定性,如何定位及紧急修复问题,以及后续数据恢复处理。对面的岗位的业务是否有了解,通过这个问题来了解你对公司此岗位的意向是否大。 + +贝壳三面(四面):平时都怎么去学习提升自己技术的?最近看了哪些书,举例说明(举mysql的掘金小册,dubbo相关的官方文档)最近在梳理知识点以及在公司做的项目,准备去面试,系统看的书比较少。会问通过这些书或技术文档收获了什么,来以此验证你是否真正看了这些书。 + +鲸算科技三面:1.会问一些性格方面的问题,优缺点:优点:对工作比较负责,做事情比较专注,细致认真,为人处世都比较靠谱。缺点:。2.如何处理同事之间矛盾,如何处理与产品或上级领导之间的需求冲突等。3.有哪些兴趣爱好,平时业余时间都做些什么? + +火花思维三面:交叉面的二面,1.问一些技术,以及设计方面的题;2.未来期望做什么样的业务,会有怎样的规划。 + +跟谁学三面:1.大的方向的场景设计题,注重你的思路是否清晰,思考问题的思维方式是否恰当,关注你技术的广度。2.平时怎么进行技术提升的,需要举出具体的例子,最近看了哪些书?可以举例说出来,不只是技术方面的书。3.未来的职业规划,近3年,近5年的规划。4.有可能会问到一些框架或者组件的设计,他们为何如此设计,这样设计的好处以及为了解决什么问题。 + +三面自我总结:同二面自我总结 + + +