数组双指针之快慢有效指针

数组的特点就是长度已知可以直接索引找到,这样就可以两头开工,将时间从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])
	}
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值