二分搜索
二分搜索的经典写法(默认元素从小小到大排列)。需要注意的三点:
- 循环退出条件,注意是low,high初始化都是可选范围内的最left和最right的数,
且low <= high,而不是 low < high。 - mid 的取值,mid := low + (high-low)>>1
- low 和 high 的更新。low = mid + 1,high = mid - 1。
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 个基本变种(以下都是默认元素都是从小到大排序):
查找第一个与 target 相等的元素,时间复杂度 O(logn)
查找最后一个与 target 相等的元素,时间复杂度 O(logn)
查找第一个大于等于 target 的元素,时间复杂度 O(logn)
查找最后一个小于等于 target 的元素,时间复杂度 O(logn)
// 二分查找第一个与 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
}
排序算法
包括 快排、堆排和归并排
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def random_partition(nums, l, r):
pivot = random.randint(l,r)
nums[r], nums[pivot] = nums[pivot], nums[r]
j = l - 1
for i in range(l, r):
if nums[i] < nums[r]:
j += 1
nums[i], nums[j] = nums[j], nums[i]
j += 1
nums[r], nums[j] = nums[j], nums[r]
return j
def quick_sort(nums, l, r):
if l > r:
return
mid = random_partition(nums, l, r)
quick_sort(nums, l, mid-1)
quick_sort(nums, mid+1, r)
quick_sort(nums, 0, len(nums) - 1)
return nums
def build_heap(nums):
for i in range(len(nums)-1, -1, -1):
heapify(nums, i, len(nums))
def heapify(nums, root, length):
p = root
while p * 2 + 1 < length:
l, r = p * 2 + 1, p * 2 + 2
if r < length and nums[l] < nums[r]:
nxt = r
else:
nxt = l
if nums[nxt] > nums[p]:
nums[nxt], nums[p] = nums[p], nums[nxt]
p = nxt
else:
return
build_heap(nums)
for i in range(len(nums)-1, 0, -1):
nums[0], nums[i] = nums[i], nums[0]
heapify(nums, 0, i)
return nums
def merge(nums, l, r):
if l == r:
return
mid = (l + r) // 2
merge(nums, l, mid)
merge(nums, mid+1, r)
tmp = []
i, j = l, mid+1
while i <= mid or j <= r:
if i > mid or (j <= r and nums[i] > nums[j]):
tmp.append(nums[j])
j += 1
else:
tmp.append(nums[i])
i += 1
nums[l:r+1] = tmp
merge(nums, 0, len(nums)-1)
return nums