文章目录
q23 合并k个排序链表
题目传送门
题解
使用分治的思想去解决,即归并排序。因为有k个链表,所以遍历这个链表数组,然后逐个排序即可。
func mergeKLists(lists []*ListNode) *ListNode {
if len(lists) == 0 {
return nil
}
if len(lists) == 1 {
return lists[0]
}
var L *ListNode
L = mergeList(lists[0], lists[1])
for i := 2; i < len(lists); i++ {
L = mergeList(L, lists[i])
}
return L
}
func mergeList(L1, L2 *ListNode) *ListNode {
L := &ListNode{}
curr := L
var next *ListNode
for L1 != nil && L2 != nil {
if L1.Val < L2.Val {
next = L1.Next
curr.Next = L1
L1.Next = nil
L1 = next
} else {
next = L2.Next
curr.Next = L2
L2.Next = nil
L2 = next
}
curr = curr.Next
}
if L1 != nil {
curr.Next = L1
}
if L2 != nil {
curr.Next = L2
}
return L.Next
}
q33 搜索旋转排序数组
题目传送门
题解
这道题中,数组不是全局有序,而是局部有序,但是仍然可以使用二分来解决。
可以发现我们旋转数组的时候,一定有一部分的数组是有序的,比如示例中:数组变成了 [4, 5, 6] 和 [7, 0, 1, 2] 两个部分,其中左边 [4, 5, 6] 这个部分的数组是有序的。
所以在循环时我们可以查看被mid分开的两边,哪边是有序的,并判断target是否在有序的这边,如果不在有序的这边,那就一定在另一边。通过这个思路最终得到答案。
func search(nums []int, target int) int {
n := len(nums)
if n == 0 {
return -1
}
if n == 1 {
if target == nums[0] {
return 0
} else {
return -1
}
}
l, r := 0, n - 1
for l <= r {
mid := (l + r) / 2
if nums[mid] == target {
return mid
}
// 如果左边有序
if nums[0] <= nums[mid] {
// 如果target恰好在左边区间
if nums[0] <= target && target < nums[mid] {
r = mid - 1
} else {
l = mid + 1
}
// 如果右边有序
} else {
// 如果target恰好在右边区间
if nums[mid] < target && target <= nums[n - 1] {
l = mid + 1
} else {
r = mid - 1
}
}
}
return -1
}
q34 在排序数组中查找元素的第一个和最后一个位置
题目传送门
题解
首先使用二分找到值为target的下标midIndex,然后以midIndex为中点,左右寻找target的左右边界。
func searchRange(nums []int, target int) []int {
l, r, midIndex, n := 0, len(nums) - 1, -1, len(nums)
for l <= r {
mid := (l + r) / 2
if nums[mid] == target {
midIndex = mid
break
}
if nums[mid] < target && target <= nums[n - 1] {
l = mid + 1
} else {
r = mid - 1
}
}
if midIndex == -1 {
return []int{-1, -1}
}
start, end := 0, 0
for i := midIndex; i >= 0; i--{
if nums[i] == target {
start = i
} else {
break
}
}
for i := midIndex; i <= n - 1; i++{
if nums[i] == target {
end = i
} else {
break
}
}
return []int{start, end}
}