From 7887ac0e172fd0e17c217a4a404cd6b1e05ff5d6 Mon Sep 17 00:00:00 2001 From: YDZ Date: Sun, 22 Sep 2019 18:42:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=8C=E5=88=86=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=20tips?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/README.md b/README.md index 0da364f2..a4470a79 100644 --- a/README.md +++ b/README.md @@ -1800,6 +1800,129 @@ func updateMatrix_BFS(matrix [][]int) [][]int { ## Binary Search +![]() + +- 二分搜索的经典写法。需要注意的三点: + 1. 循环退出条件,注意是 low <= high,而不是 low < high。 + 2. mid 的取值,mid := low + (high-low)>>1 + 3. low 和 high 的更新。low = mid + 1,high = mid - 1。 + +```go +func binarySearchMatrix(nums []int, target int) int { + low, high := 0, len(nums)-1 + for low <= high { + mid := low + (high-low)>>1 + if nums[mid] == target { + return mid + } else if nums[mid] > target { + high = mid - 1 + } else { + low = mid + 1 + } + } + return -1 +} +``` + +- 二分搜索的变种写法。有 4 个基本变种: + 1. 查找第一个与 target 相等的元素,时间复杂度 O(logn) + 2. 查找最后一个与 target 相等的元素,时间复杂度 O(logn) + 3. 查找第一个大于等于 target 的元素,时间复杂度 O(logn) + 4. 查找最后一个小于等于 target 的元素,时间复杂度 O(logn) + +```go +// 二分查找第一个与 target 相等的元素,时间复杂度 O(logn) +func searchFirstEqualElement(nums []int, target int) int { + low, high := 0, len(nums)-1 + for low <= high { + mid := low + ((high - low) >> 1) + if nums[mid] > target { + high = mid - 1 + } else if nums[mid] < target { + low = mid + 1 + } else { + if (mid == 0) || (nums[mid-1] != target) { // 找到第一个与 target 相等的元素 + return mid + } + high = mid - 1 + } + } + return -1 +} + +// 二分查找最后一个与 target 相等的元素,时间复杂度 O(logn) +func searchLastEqualElement(nums []int, target int) int { + low, high := 0, len(nums)-1 + for low <= high { + mid := low + ((high - low) >> 1) + if nums[mid] > target { + high = mid - 1 + } else if nums[mid] < target { + low = mid + 1 + } else { + if (mid == len(nums)-1) || (nums[mid+1] != target) { // 找到最后一个与 target 相等的元素 + return mid + } + low = mid + 1 + } + } + return -1 +} + +// 二分查找第一个大于等于 target 的元素,时间复杂度 O(logn) +func searchFirstGreaterElement(nums []int, target int) int { + low, high := 0, len(nums)-1 + for low <= high { + mid := low + ((high - low) >> 1) + if nums[mid] >= target { + if (mid == 0) || (nums[mid-1] < target) { // 找到第一个大于等于 target 的元素 + return mid + } + high = mid - 1 + } else { + low = mid + 1 + } + } + return -1 +} + +// 二分查找最后一个小于等于 target 的元素,时间复杂度 O(logn) +func searchLastLessElement(nums []int, target int) int { + low, high := 0, len(nums)-1 + for low <= high { + mid := low + ((high - low) >> 1) + if nums[mid] <= target { + if (mid == len(nums)-1) || (nums[mid+1] > target) { // 找到最后一个小于等于 target 的元素 + return mid + } + low = mid + 1 + } else { + high = mid - 1 + } + } + return -1 +} +``` + +- 在基本有序的数组中用二分搜索。经典解法可以解,变种写法也可以写,常见的题型,在山峰数组中找山峰,在旋转有序数组中找分界点。第 33 题,第 81 题,第 153 题,第 154 题,第 162 题,第 852 题 + +```go +func peakIndexInMountainArray(A []int) int { + low, high := 0, len(A)-1 + for low < high { + mid := low + (high-low)>>1 + // 如果 mid 较大,则左侧存在峰值,high = m,如果 mid + 1 较大,则右侧存在峰值,low = mid + 1 + if A[mid] > A[mid+1] { + high = mid + } else { + low = mid + 1 + } + } + return low +} +``` + + | Title | Solution | Difficulty | Time | Space |收藏| | ----- | :--------: | :----------: | :----: | :-----: | :-----: | |[50. Pow(x, n)](https://leetcode.com/problems/powx-n)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0050.%20Pow(x%2C%20n))| Medium | O(log n)| O(1)||