在解题时,双指针的思想常常可以帮助我们优化解法的时间空间复杂度。接下来,我将通过两道LeetCode的题来给大家讲解双指针的使用方法。
文章目录
- 题目1:Two Sum
- 题目2:Three Sum
- 双指针思想的总结
题目1:Two Sum
题目描述:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
解题思路:我们可以初始化两个指针分别指向数组的起始点和终点,如果两个指针所指的值之和大于target,则移动尾指针使得总和减小;如果两者相加小于target,则移动头指针使得总和增大。不断循环此过程,直到找到相加等于target的两个数,然后返回它们的下标。
代码实现:
def twoSum(nums, target):nums = enumerate(nums)nums = sorted(nums, key=lambda x:x[1])l, r = 0, len(nums)-1while l < r:if nums[l][1]+nums[r][1] == target:return [nums[l][0], nums[r][0]]elif nums[l][1]+nums[r][1] < target:l += 1else:r -= 1
题目2:Three Sum
题目描述:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
解题思路:先将数组排序,然后遍历数组,对于每个元素,我们可以设置双指针分别指向该元素的后一位和数组的最后一位,如果三个数之和等于0,则记录下来;如果三个数之和小于0,则移动头指针;如果大于0,则移动尾指针。
代码实现:
def threeSum(nums):nums.sort()res, k = [], 0for k in range(len(nums) - 2):if nums[k] > 0: break # 1.因为j>i>k, 所以如果nums[k] > 0那么后续不可能有三个数和为0if k > 0 and nums[k] == nums[k - 1]: continue # 2.避免出现重复结果i, j = k + 1, len(nums) - 1while i < j: # 3.双指针循环s = nums[k] + nums[i] + nums[j]if s < 0:i += 1while i < j and nums[i] == nums[i - 1]: i += 1 # 4.避免出现重复结果elif s > 0:j -= 1while i < j and nums[j] == nums[j + 1]: j -= 1 # 5.避免出现重复结果else:res.append([nums[k], nums[i], nums[j]])i += 1j -= 1while i < j and nums[i] == nums[i - 1]: i += 1 # 6.避免出现重复结果while i < j and nums[j] == nums[j + 1]: j -= 1 # 7.避免出现重复结果return res
双指针思想的总结
双指针是一种多用于解决数组/链表问题的简单却非常巧妙的思想。它的主要思路是用两个指针,一个快一个慢或者一个在前一个在后去遍历数据,帮我们降低时间复杂度,解决问题。它常常被应用于以下几种情况:
- 两数之和/三数之和等问题:在已经排序的数组中用两个指针分别从头和尾向中间扫描,寻找满足条件的元素。
- 链表中寻找中间节点或者是判断链表是否存在环等问题:通过一个快指针(一次移动两格)和一个慢指针(一次移动一格)在遍历的过程中找到解。
- 归并排序中的合并操作:分别使用两个指针指向两个待归并的有序数组的头部,每次选取小的放入结果中,并移动选中的那个数组的指针。
使用双指针,我们可以在许多情况下将时间复杂度从原来的O(n^2)降低到O(n)。同时,双指针的理念也可以适用于多指针的情况,帮助我们解决更复杂的问题。在日常的编程实践中,我们可以多尝试和利用双指针的思想来解决问题。