Leetcode 双指针

定义

双指针的题,即利用两个指针去遍历数组。往往涉及到有序的范围,可以通过左右的加减来减少暴力遍历的次数。

一. 盛最多水的容器

给你 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,
垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可
以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

在这里插入图片描述
思路:

设置双指针 i,j 分别位于容器壁两端,根据规则移动指针(后续说明),并且更新面积最大值 res,直到 i == j 时返回 res

解答:

class Solution:
    def maxArea(self, height: List[int]) -> int:
        length = len(height)
        i, j = 0, length - 1
        res_max = min(height[i],height[j]) * (j - i)
        for k in range(length-2):
            if height[i] <= height[j]:
                i += 1
            else:
                j -= 1
            temp_max = min(height[i] , height[j]) * (j - i)
            res_max = max(temp_max,res_max)
        return res_max

二.三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
    [-1, 0, 1],   [-1, -1, 2]
]

思路:

1. 特判,对于数组长度 n,如果数组为 null 或者数组长度小于 3,返回 []。
2. 对数组进行排序。
3. 遍历排序后数组:
    若 nums[i]>0nums[i]>0:因为已经排序好,所以后面不可能有三个数加和等于 0,直接返回结果。
    对于重复元素:跳过,避免出现重复解
    令左指针 L=i+1 ,右指针 R=n-1,当 L<R 时,执行循环:
        当 nums[i]+nums[L]+nums[R]==0    nums[i]+nums[L]+nums[R]==0,执行循环,判断左界和右界是否和下一位置重复,去除重复解。并同时将 L,RL,R 移到下一位置,寻找新的解
        若和大于 0,说明 nums[R]nums[R] 太大,RR 左移
        若和小于 0,说明 nums[L]nums[L] 太小,LL 右移

解答:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        '''
        # 1、固定k值
            #  跳过k值为正的数  
            # i+1的值和k相等跳过
        # 2、设置双指针
            # 2.1 如果三者之和大于0
                # R -1
            # 2.2 如果三者之和小于0
                # L + 1
            # 2.3 如果三者之和等于0
                # 跳过R和L值相等的。
                # 同时R和L的值分别-1、+1         
        '''
        nums.sort()
        length, res = len(nums), []
        if length < 3:
            return res
        for i, k in enumerate(nums):
            if i > 0 and k == nums[i - 1]:
                continue
            L, R = i + 1, length - 1
            while L < R:
                L_n, R_n = nums[L], nums[R]
                temp_sum = sum([k, L_n, R_n])
                if temp_sum > 0:
                    R -= 1
                elif temp_sum < 0:
                    L += 1
                else:
                    res.append([k, L_n, R_n])
                    while L < R and L_n == nums[L + 1]:
                        L += 1
                    while L < R and R_n == nums[R - 1]:
                        R -= 1

                    L += 1
                    R -= 1
        return res

四数之和

在三数和的基础上新增一个for。
class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        length, res = len(nums), []
        if length < 4:
            return []

        for x in range(length - 3):
            m = nums[x]
            if (x > 0 and m == nums[x - 1]) or (m + sum(nums[length - 3:]) < target):
                continue

            if sum(nums[x:x + 4]) > target:
                break

            for i in range(x + 1, length - 2):
                k = nums[i]
                if (i > x + 1 and k == nums[i - 1]) or (m + k + sum(nums[length - 2:]) < target):
                    continue

                if m + sum(nums[i:i + 3]) > target:
                    break

                L, R = i + 1, length - 1
                while L < R:
                    L_n, R_n = nums[L], nums[R]
                    temp_sum = sum([k, L_n, R_n, m])
                    if temp_sum > target:
                        R -= 1
                    elif temp_sum < target:
                        L += 1
                    else:
                        res.append([m, k, L_n, R_n])
                        while L < R and L_n == nums[L + 1]:
                            L += 1

                        L += 1
                        
                        while L < R and R_n == nums[R - 1]:
                            R -= 1
                        R -= 1
        return res

三.删除排序数组中的重复项

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 1:
给定数组 nums = [1,1,2], 
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。 

示例 2:
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

解答:

# 普通解答
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        for index,n in enumerate(nums,0):
            temp_list = nums[index+1:]
            for i in range(temp_list.count(n)):
                temp_list.remove(n)
            nums[:]=nums[:index+1]+temp_list

        return len(nums)
# 双指针
class Solution:
    def removeDuplicates(self, nums) -> int:
        if len(nums) <= 1:
            return len(nums)
        i, j = 0, 1
        while j < len(nums):
            if nums[i] == nums[j]:
                nums.pop(j)
            else:
                j += 1
                i = j - 1
        return j

字符串翻转或轮转数组

给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

解答

# 方法一
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        length = len(nums)
        if k > length:
            k = k % length
    
        for i in range(k):
            nums.insert(0, nums.pop())


# 方法二
class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        length = len(nums)
        if k > length:
            k = k % length
    
        def reverse(i, j):
            while i < j:
                nums[i], nums[j] = nums[j], nums[i]
                i += 1
                j -= 1
    
        # [7, 6, 5, 4, 3, 2, 1]
        # [5, 6, 7, 4, 3, 2, 1]
	    # [5, 6, 7, 1, 2, 3, 4]
        reverse(0, length - 1)
        reverse(0, k - 1)
        reverse(k, length - 1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值