From b5dc4022bcc4e6e13e9193255b2d7d3087463b7e Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Mon, 6 Mar 2023 15:59:27 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/hot100/T21_SearchRange.java | 124 ++++++++++++++++++ .../leecode/hot100/T22_CombinationSum.java | 64 +++++++++ .../com/markilue/leecode/hot100/T23_Trap.java | 112 ++++++++++++++++ .../markilue/leecode/hot100/T24_Permute.java | 60 +++++++++ .../markilue/leecode/hot100/T25_Rotate.java | 68 ++++++++++ 5 files changed, 428 insertions(+) create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T21_SearchRange.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T22_CombinationSum.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T23_Trap.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T24_Permute.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/hot100/T25_Rotate.java diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T21_SearchRange.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T21_SearchRange.java new file mode 100644 index 0000000..ee2edde --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T21_SearchRange.java @@ -0,0 +1,124 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-06 10:04 + *@Description: + * TODO 力扣34题 在排序数组中查找元素的第一个和最后一个位置: + * 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 + * 如果数组中不存在目标值 target,返回 [-1, -1]。 + * 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 + *@Version: 1.0 + */ +public class T21_SearchRange { + + @Test + public void test() { + int[] nums = {8, 8, 8, 8, 8, 8}; + int target = 8; + System.out.println(Arrays.toString(searchRange(nums, target))); + } + + + @Test + public void test1() { + int[] nums = {5, 7, 7, 8, 8, 10}; + int target = 6; + System.out.println(Arrays.toString(searchRange(nums, target))); + } + + @Test + public void test2() { + int[] nums = {2, 2}; + int target = 3; + System.out.println(Arrays.toString(searchRange(nums, target))); + } + + /** + * 思路:本质上就是二分查找查找多个相同值的位置 + * 速度击败100% 内存击败30.39% 0ms + * @param nums + * @param target + * @return + */ + public int[] searchRange(int[] nums, int target) { + if (nums.length == 0) { + return new int[]{-1, -1}; + } + + int start = 0; + int end = nums.length - 1; + int mid = 0; + + while (start <= end) { + mid = start + ((end - start) >> 1); + + if (nums[mid] < target) { + start = mid + 1; + } else if (nums[mid] > target) { + end = mid - 1; + } else { + //找到了 + break; + } + } + + if (start > end) { + return new int[]{-1, -1};//没找到 + } else { + int left = mid; + int right = mid; + while (left > 0 && nums[left - 1] == nums[mid]) { + left--; + } + while (right < nums.length - 1 && nums[right + 1] == nums[mid]) { + right++; + } + return new int[]{left, right}; + } + + + } + + + /** + * 评论区的简洁写法 + * @param nums + * @param target + * @return + */ + public int[] searchRange1(int[] nums, int target) { + if (nums.length == 0) { + return new int[]{-1, -1}; + } + + int start = 0; + int end = nums.length - 1; + int mid = 0; + + while (start <= end) { + mid = start + ((end - start) >> 1); + + if (nums[mid] == target) { + int left = mid; + int right = mid; + while (left > 0 && nums[left - 1] == nums[mid]) ++left; + while (right < nums.length - 1 && nums[right + 1] == nums[mid]) --right; + return new int[]{left, right}; + } else if (nums[mid] < target) { + start = mid + 1; + }else { + end=mid-1; + } + } + return new int[]{-1, -1};//没找到 + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T22_CombinationSum.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T22_CombinationSum.java new file mode 100644 index 0000000..fdebf7e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T22_CombinationSum.java @@ -0,0 +1,64 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-06 10:29 + *@Description: + * TODO 力扣39题 组合总和: + * 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。 + * candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 + * 对于给定的输入,保证和为 target 的不同组合数少于 150 个。 + *@Version: 1.0 + */ +public class T22_CombinationSum { + + @Test + public void test() { + int[] candidates = {2, 3, 6, 7}; + int target = 7; + System.out.println(combinationSum(candidates, target)); + } + + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + + + /** + * 回溯,注意树枝去重和树层去重方式 + * 速度击败75.99% 内存击败83.16% 可能数sum没有使用回溯的方式写,稍微有点慢 + * @param candidates + * @param target + * @return + */ + public List> combinationSum(int[] candidates, int target) { + Arrays.sort(candidates); + backtracking(candidates, target, 0,0); + return result; + } + + public void backtracking(int[] candidates, int target, int sum,int start) { + if (sum == target) { + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = start; i < candidates.length && sum + candidates[i] <= target; i++) {//加上start树枝去重 + //从这个杜绝sum>target + if (i > 0 && candidates[i] == candidates[i - 1]) { + continue;//树层去重 + } + cur.add(candidates[i]); + backtracking(candidates, target, sum + candidates[i],i); + cur.remove(cur.size() - 1); + + } + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T23_Trap.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T23_Trap.java new file mode 100644 index 0000000..c449c85 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T23_Trap.java @@ -0,0 +1,112 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-06 10:48 + *@Description: + * TODO 力扣42题 接雨水: + * 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 + *@Version: 1.0 + */ +public class T23_Trap { + + @Test + public void test() { + int[] height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; + System.out.println(trap2(height)); + } + + + /** + * 思路:先尝试动态规划法 + * 分别从两边进行动态规划,分别寻找考虑两边的最大值 + * 速度击败78.21% 内存击败82.6% 1ms + * @param height + * @return + */ + public int trap(int[] height) { + + int[] left = new int[height.length]; + left[0] = height[0]; + for (int i = 1; i < height.length; i++) { + left[i] = Math.max(height[i], left[i - 1]);//本质上就是记录从左看的最大值 + } + int[] right = new int[height.length];//记录从右看的最大 + right[right.length - 1] = height[height.length - 1]; + for (int i = height.length - 2; i >= 0; i--) { + right[i] = Math.max(height[i], right[i + 1]); + } + + //通过分别从左和右看的最大值来判断当前位置所接的雨水量 + int sum = 0; + for (int i = 0; i < right.length; i++) { + //当前位置的雨水量 取决于 从左和右看中的最小值 + sum += Math.min(left[i], right[i]) - height[i]; + } + + return sum; + + } + + + /** + * 思路:先尝试双指针法 + * 分别从两边进行规划指针,谁小谁往对方方向走 + * TODO 本人的正确应该是纯属凑巧(不可借鉴) + * 速度击败78.21% 内存击败47.5% 1ms + * @param height + * @return + */ + public int trap1(int[] height) { + + int left = 0; + int right = height.length - 1; + int leftMax = height[left]; + int rightMax = height[right]; + int sum = 0; + + for (int i = 0; i < height.length; i++) { + leftMax = Math.max(height[left], leftMax); + rightMax = Math.max(height[right], rightMax); + //当前位置的雨水量取决于左右两边最小的那个 + sum += Math.min(leftMax, rightMax) - height[i]; + if (leftMax < rightMax) { + left++; + } else { + right--; + } + } + return sum; + + + } + + + /** + * 官方的左右指针法:浅优化(每次循环少判断一次) + * @param height + * @return + */ + public int trap2(int[] height) { + int ans = 0; + int left = 0, right = height.length - 1; + int leftMax = 0, rightMax = 0; + while (left < right) { + leftMax = Math.max(leftMax, height[left]); + rightMax = Math.max(rightMax, height[right]); + if (height[left] < height[right]) { + //如果左边的小,那么左边的水一定可以蓄起来,那么就计算左边的水 + ans += leftMax - height[left]; + ++left; + } else { + ans += rightMax - height[right]; + --right; + } + } + return ans; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T24_Permute.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T24_Permute.java new file mode 100644 index 0000000..2259407 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T24_Permute.java @@ -0,0 +1,60 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-06 11:34 + *@Description: + * TODO 力扣46题 全排列: + * 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 + *@Version: 1.0 + */ +public class T24_Permute { + + @Test + public void test() { + int[] nums = {1, 2, 3}; + System.out.println(permute(nums)); + } + + + List cur = new ArrayList<>(); + List> result = new ArrayList<>(); + + /** + * 核心就是需要知道哪些位置用过,哪些位置没有用过 + * 速度击败100% 内存击败69.64% 1ms + * @param nums + * @return + */ + public List> permute(int[] nums) { + + boolean[] used = new boolean[nums.length]; + backtracking(nums, used); + return result; + + } + + public void backtracking(int[] nums, boolean[] used) { + if (cur.size() == nums.length) { + result.add(new ArrayList<>(cur)); + return; + } + + for (int i = 0; i < nums.length; i++) { + if (!used[i]) { + used[i] = true; + cur.add(nums[i]); + backtracking(nums, used); + used[i] = false; + cur.remove(cur.size() - 1); + } + } + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/hot100/T25_Rotate.java b/Leecode/src/main/java/com/markilue/leecode/hot100/T25_Rotate.java new file mode 100644 index 0000000..1f148a3 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/hot100/T25_Rotate.java @@ -0,0 +1,68 @@ +package com.markilue.leecode.hot100; + +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.hot100 + *@Author: markilue + *@CreateTime: 2023-03-06 11:42 + *@Description: + * TODO 力扣48题 旋转图像: + * 给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 + * 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 + *@Version: 1.0 + */ +public class T25_Rotate { + + @Test + public void test() { + int[][] matrix = {{5,1,9,11}, {2,4,8,10}, {13,3,6,7},{15,14,12,16}}; + rotate(matrix); + for (int[] ints : matrix) { + System.out.println(Arrays.toString(ints)); + } + } + + /** + * 思路:这题跟螺旋数组那题很像:都是寻找循环不变量 + * 速度击败100% 内存击败67.68% 0ms + * @param matrix + */ + public void rotate(int[][] matrix) { + + //i为层 + for (int i = 0; i < matrix.length / 2; i++) { + int row = i;//row方向移动 + int col = i;//col方向移动 + + int row1 = i;//需要复制的row方向 + int col1 = matrix.length - 1 - i;//需要复制的col方向 + int[] last = new int[matrix.length - 1 - i];//记录上次的位置 + + for (int index = 0; col < matrix.length - 1 - i; col++, row1++) { + last[index++] = matrix[row1][col1]; + matrix[row1][col1] = matrix[row][col]; + } + + for (int index = 0; col1 > i; col1--) { + int temp = matrix[row1][col1]; + matrix[row1][col1] = last[index]; + last[index++] = temp; + } + + for (int index = 0; row1 > i; row1--) { + int temp = matrix[row1][col1]; + matrix[row1][col1] = last[index]; + last[index++] = temp; + } + + for (int index = 0; col1 < matrix.length - 1 - i; col1++) { + matrix[row1][col1] = last[index++]; + } + } + + } +}