数组的特点就是长度已知可以直接索引找到,这样就可以两头开工,将时间从O(n)降低到O(log2N),这里的策略即左右手指针
数组也有缺点,就是他移动起来费劲,单个节点或者某一连续区域的移动,不能有链表那种从链条中断开再接上的方式,当然也必然不能一个直接和某个节点交换位置这本身不符合要求。对于移动就需要有一些策略,来提高效率。比如快慢有效指针,快的探路,慢的只保留有效的。这样就能避免内部移动带来O(n)的代价,从而导致整体代价为O(n2)。
除了上文左右手提速,快慢有效指针避免降速以外,链表中常常需要考虑空指针,对于数组就是要考虑数组越界。
双指针之快、慢有效指针
删除有序数组中的重复项(26)
这个题目其实就是从头往后找,然后进行操作处理,但是数组移动,不好移动,所以用快慢有效指针。
慢指针指向下一个存放的Index,快指针找到有效的。对于本题而言
慢指针指向下一个存放的位置,快指针找到最后一个不重复的值的索引,比如 1 1 2 则是找到1
题目:26. 删除有序数组中的重复项
func removeDuplicates(nums []int) int {
slow := 0
fast := 0
for fast < len(nums) {
// 找到一个要放的值
for fast < len(nums)-1 && nums[fast] == nums[fast+1] { // 这里需要思考一下是用fast和fast-1还是用fast和fast+1
// 用fast+1需要修改fast < len(nums),用fast-1 也不太行,而且根据1 1 2 肯定是要index1和index2比,此时fast=1,所以要用fast和fast+1比较
// 最后一个必然要用,所以修改判断条件即可
fast++
}
if fast < len(nums) {
nums[slow] = nums[fast]
slow++
fast++
}
}
return slow // 这里slow-1是真实有效的Index,而长度等于真实Index+1
}
移除元素(27)
题目:27. 移除元素
这个思路也一样,也是快慢有效指针节省移动时间
func removeElement(nums []int, val int) int {
slow := 0
fast := 0
for fast < len(nums) {
for fast < len(nums) && nums[fast] == val { // 这里需要具体手动推演一下,没啥问题
fast++
}
if fast < len(nums) {
nums[slow] = nums[fast]
slow++
fast++ // 这里要注意,所以还是要把例子带入写的代码
}
}
return slow
}
移动零(283)
题目:283. 移动零
这里也是快慢有效指针节省移动时间,其实和移除元素一样,只不过要把0放在后面,用移除元素,将最后的值赋值为0就是本题的答案
func moveZeroes(nums []int) {
count := removeElement(nums, 0)
for i := count; i < len(nums); i++ {
nums[i] = 0
}
return
}
func removeElement(nums []int, val int) int {
slow := 0
fast := 0
for fast < len(nums) {
for fast < len(nums) && nums[fast] == val { // 这里需要具体手动推演一下,没啥问题
fast++
}
if fast < len(nums) {
nums[slow] = nums[fast]
slow++
fast++ // 这里要注意,所以还是要把例子带入写的代码
}
}
return slow
}
合并两个有序数组(88)
本题和归并排序还不一样,本题是合并到nums1上,又预留了坑位,这里主要考察从后开始操作数组的这个思路。
从nums1的最后开始,将nums1和nums2较大的值放到nums1这个指针上,最后如果nums2还有,那就直接赋值过去。
本题的快慢有效指针在哪呢?对于nums1来说,快指针就是p1,不断和p2进行比较,慢有效指针就是tail它索引的位置是下一个数据的坑位。
题目:88. 合并两个有序数组
func merge(nums1 []int, m int, nums2 []int, n int) {
tail := len(nums1) - 1
p1 := m - 1
p2 := n - 1
for p1 >= 0 && p2 >= 0 {
if nums1[p1] >= nums2[p2] {
nums1[tail] = nums1[p1]
p1--
} else {
nums1[tail] = nums2[p2]
p2--
}
tail--
}
if p2 >= 0 {
copy(nums1[:tail+1], nums2[:p2+1])
}
}