双指针算法思想
双指针是一种常用的算法思想,通常用于在数组或链表等数据结构中解决一些问题。双指针技巧通过使用两个指针来遍历数据结构,从而在一次遍历中解决问题,避免使用额外的数据结构,从而降低时间复杂度和空间复杂度。
常见的两种类型:快慢指针和左右指针。
快慢指针
快慢指针一般用于解决链表相关的问题。快指针每次移动两步,慢指针每次移动一步。通过快慢指针的遍历,可以找到链表的中间节点、判断链表是否有环、寻找链表倒数第 k 个节点等问题。
左右指针
左右指针一般用于解决数组或字符串相关的问题。左指针从数组的最左边开始,右指针从数组的最右边开始,然后向中间移动。通过左右指针的遍历,可以找到满足某种条件的子数组或子字符串,比如两数之和、反转数组、滑动窗口等问题。
双指针应用实例
题目:移除元素
方法一:左右指针+交换值(图解如下)

复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)
- 时间复杂度: O ( n ) O(n) O(n)
该函数使用了双指针技巧来移除数组中等于给定值 val 的元素。双指针方法可以将数组中所有等于 val 的元素移动到数组的末尾,并返回新数组的长度。
在最坏情况下,如果数组中所有元素都等于 val,那么需要遍历整个数组,时间复杂度是 O ( n ) O(n) O(n),其中 n 是数组的长度。
- 空间复杂度: O ( 1 ) O(1) O(1)
该函数只使用了常量级别的额外空间来存储变量和常数。没有使用与输入规模成比例的额外数据结构。因此,空间复杂度是 O ( 1 ) O(1) O(1)。
Go代码
func removeElement(nums []int, val int) int {
length := len(nums)
left, right := 0, length-1
for left<=right {
if nums[left]==val && nums[right]!= val {
nums[left], nums[right] = nums[right], nums[left]
left++
right--
}
if nums[left] != val {
left++
}
if nums[right] == val {
right--
}
}
return left
}
方法二:快慢指针+覆盖值(图解如下)
fast指针用于遍历数组,slow指针用于标记新数组的边界。当fast指针找到一个不等于val的元素时,将其复制到slow指针所在的位置,并递增slow指针。这样,slow指针之前的元素就构成了新数组。

复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)
Go代码
func removeElement(nums []int, val int) int {
length := len(nums)
slow, fast := 0, 0
for ; fast<length; fast++ {
if nums[fast] != val {
nums[slow] = nums[fast]
slow++
}
}
return slow
}
双指针算法思想及应用实例

本文介绍了双指针算法的两种主要类型——快慢指针和左右指针,以及它们在解决数组和链表问题中的应用。通过示例题目和Go代码展示了如何运用这两种方法实现不同功能,如移除元素、删除有序数组中的重复项、轮转数组等,同时分析了时间复杂度和空间复杂度。


最低0.47元/天 解锁文章
666

被折叠的 条评论
为什么被折叠?



