* 链接:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/ */ +//二刷不会 public class FindMin { + /** * 判断区间是否已经有序 * @@ -50,4 +52,57 @@ public class FindMin { return nums[left]; } + public int findMax(int[] nums) { + int left = 0, right = nums.length - 1; + // 当区间尚未缩到只剩一个元素 + while (left < right) { + // 如果当前区间已经是严格升序(没有经过旋转),那么最大值就是区间末尾 + if (nums[left] < nums[right]) { + return nums[right]; + } + int mid = left + (right - left) / 2; + // 如果 nums[mid] 比 nums[left] 大,说明 [left…mid] 是严格升序的, + // 这段的最大值就是 nums[mid],而且全局上一定存在比 nums[mid] 更小的元素在右边 + // ——但是我们要找的是最大值,此时候,要把搜索区间缩到 [mid…right] + if (nums[mid] > nums[left]) { + left = mid; + } + // 否则,nums[mid] ≤ nums[left],说明旋转点(最大值)在 [left…mid-1] 里 + else { + right = mid - 1; + } + } + // 最终 left == right,指向的就是最大值 + return nums[left]; + } + + private int findMinIndex(int[] nums) { + int left = 0, right = nums.length - 1; + while (left < right) { + // 如果当前区间完全有序 + if (nums[left] < nums[right]) { + return left; + } + int mid = left + (right - left) / 2; + if (nums[mid] >= nums[left]) { + // [left…mid] 单调,最小值一定在 mid+1…right + left = mid + 1; + } else { + // mid 在左侧的旋转段里,min 可能就是 mid + right = mid; + } + } + return left; + } + + /** + * 用一次二分找到最小值,然后取它左边的元素作为最大值 + */ + public int findMax2(int[] nums) { + int n = nums.length; + int pivot = findMinIndex(nums); + // pivot 左边的元素是最大值 + return nums[(pivot - 1 + n) % n]; + } + } diff --git a/src/main/java/binary_search/Search.java b/src/main/java/binary_search/Search.java index 0eca099..c02eec0 100644 --- a/src/main/java/binary_search/Search.java +++ b/src/main/java/binary_search/Search.java @@ -13,35 +13,57 @@ package binary_search; * 链接:https://leetcode.cn/problems/search-in-rotated-sorted-array/ */ //不会 +//二刷不会 public class Search { + + /** + * 在旋转排序数组 nums 中查找目标值 target + * @param nums 旋转排序后的数组 + * @param target 目标值 + * @return 目标值在数组中的下标,如果不存在则返回 -1 + */ public int search(int[] nums, int target) { int n = nums.length; + // 数组为空时,直接返回 -1 if (n == 0) { return -1; } + // 数组长度为 1,直接判断唯一元素是否为 target if (n == 1) { return nums[0] == target ? 0 : -1; } + + // 双指针定义搜索区间 [l, r] int l = 0, r = n - 1; + // 进入二分查找 while (l <= r) { - int mid = (l + r) / 2; + // 防止 (l + r) 溢出,计算中点 + int mid = l + (r - l) / 2; + // 如果中点即为目标,直接返回 if (nums[mid] == target) { return mid; } + + // 判断哪一段是单调升序的: + // 如果 nums[0] <= nums[mid],说明从索引 0 到 mid 是升序的 if (nums[0] <= nums[mid]) { + // 如果 target 在这段升序区间内,则向左继续搜索,否则搜索右半区 if (nums[0] <= target && target < nums[mid]) { - r = mid - 1; + r = mid - 1; // 缩小右边界 } else { - l = mid + 1; + l = mid + 1; // 移动左边界 } } else { + // 否则,右半区 [mid, n-1] 是升序的 + // 如果 target 在右半区范围内,则向右继续搜索,否则搜索左半区 if (nums[mid] < target && target <= nums[n - 1]) { - l = mid + 1; + l = mid + 1; // 移动左边界 } else { - r = mid - 1; + r = mid - 1; // 缩小右边界 } } } + // 未找到目标,返回 -1 return -1; } } diff --git a/src/main/java/binary_search/SearchInsert.java b/src/main/java/binary_search/SearchInsert.java index 332ce54..487de63 100644 --- a/src/main/java/binary_search/SearchInsert.java +++ b/src/main/java/binary_search/SearchInsert.java @@ -12,7 +12,10 @@ package binary_search; * 链接:https://leetcode.cn/problems/search-insert-position/ */ //第一道二分法的题,不熟练 +// 二刷会做 public class SearchInsert { + + public int searchInsert(int[] nums, int target) { int left = 0, right = nums.length - 1; while (left <= right) { diff --git a/src/main/java/binary_search/SearchMatrix.java b/src/main/java/binary_search/SearchMatrix.java index feb5054..43fe9e6 100644 --- a/src/main/java/binary_search/SearchMatrix.java +++ b/src/main/java/binary_search/SearchMatrix.java @@ -14,6 +14,7 @@ package binary_search; * 链接:https://leetcode.cn/problems/search-a-2d-matrix/ */ +//二刷会做 public class SearchMatrix { public boolean searchMatrix(int[][] matrix, int target) { int r=matrix.length; diff --git a/src/main/java/binary_search/SearchRange.java b/src/main/java/binary_search/SearchRange.java index 6d6af24..0de1f88 100644 --- a/src/main/java/binary_search/SearchRange.java +++ b/src/main/java/binary_search/SearchRange.java @@ -11,6 +11,7 @@ package binary_search; * 链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/ */ +//二刷不会高效方法 public class SearchRange { //极端情况下不是O(log n) public int[] searchRange(int[] nums, int target) { @@ -46,19 +47,33 @@ public class SearchRange { } private int findLeft(int[] nums, int target) { + // 搜索区间为 [left, right] int left = 0, right = nums.length - 1; + // 用来记录 target 最左出现的位置,初始为 -1 表示未找到 int index = -1; + + // 当搜索区间有效时,继续二分 while (left <= right) { + // 计算中点,写法能避免 (left+right) 溢出 int mid = left + (right - left) / 2; + + // 如果中点元素 >= target,说明左边可能还存在 target if (nums[mid] >= target) { + // 收缩右边界到 mid - 1,继续在左半区查找 right = mid - 1; } else { + // nums[mid] < target,说明 target 只能出现在右半区 left = mid + 1; } + + // 如果在 mid 处发现了 target,就更新 index 为 mid + // 但不立即返回,因为还要继续向左看看是否还有更左的 target if (nums[mid] == target) { index = mid; } } + + // 循环结束后,index 要么是最左的 target 位置,要么仍为 -1(没找到) return index; } diff --git a/src/test/java/array/MaxSubArrayTest.java b/src/test/java/array/MaxSubArrayTest.java index 0055491..6ee1aad 100644 --- a/src/test/java/array/MaxSubArrayTest.java +++ b/src/test/java/array/MaxSubArrayTest.java @@ -2,7 +2,7 @@ package array; import org.junit.Test; -import static org.junit.Assert.*; +import java.util.Arrays; public class MaxSubArrayTest { diff --git a/src/test/java/binary_search/SearchTest.java b/src/test/java/binary_search/SearchTest.java new file mode 100644 index 0000000..1d7f5bd --- /dev/null +++ b/src/test/java/binary_search/SearchTest.java @@ -0,0 +1,10 @@ +package binary_search; + +import junit.framework.TestCase; + +public class SearchTest extends TestCase { + + public void testSearch() { + + } +} \ No newline at end of file