leetcode双指针问题总结 Python

目录

1. 二分查找

2. 有序数组中寻找两个数和等于某数

3. 两数平方和

4. 翻转字符串中的元音字符

5. 判断是否为回文字符串(最多可以删除一个字符)

6. 归并两个有序数组

7. 判断链表是否有环

8. 最长子序列


1. 二分查找

从有序数组 nums 中查找等于 v 的索引

示例:

输入:nums=[1,3,6,8,9], v=3

输出:1

二分查找表面上非常简单,但是实际编程还是有几个点需要注意,否则极易出现 bug。如果我们处理的是连续数值,那就容易的多,但本题目是离散整数值,所以需要注意当左指针 left 与右指针 right 相差仅仅为 1 时的处理,处理办法就是分别在左值和右值上加一和减一。

def fun(nums, v):
    left = 0
    right = len(nums) - 1
    while left <= right:          # 注意加入等号
        mid = (left + right) // 2
        if nums[mid] > v: 
            right = mid - 1       # 注意需要 -1
        elif nums[mid] < v:
            left = mid + 1        # 注意需要 +1
        else:
            return mid
    return None

2. 有序数组中寻找两个数和等于某数

给你一个下标从 1 开始的整数数组 numbers ,该数组已按非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。你可以假设每个输入只对应唯一的答案 ,而且你不可以重复使用相同的元素。

示例:

输入:numbers = [2,7,11,15], target = 9

输出:[1,2]   解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 

def twoSum(numbers, target):
    low, high = 0, len(numbers)-1
    while low < high:
        sum = numbers[low] + numbers[high]
        if sum == target:
            return [low+1, high+1]
        if sum > target:
            high -= 1
        else:
            low += 1
    return [-1, -1]

3. 两数平方和

给定一个非负整数 c ,你要判断是否存在两个整数 a 和 b,使得 a^2 + b^2 = c

示例:

输入:c = 5

输出:true   解释:1 * 1 + 2 * 2 = 5

在 python 中开根号有三种方式,math.sqrt()、cmath.sqrt()、pow(,),推荐使用最后一种的内置函数。

def judgeSquareSum(c):
    low = 0
    high = int(pow(c, 0.5))
    while low < high:
        res = pow(low, 2) + pow(high, 2)
        if res == c:
            return True
        elif res > c:
            high -= 1
        else:
            low += 1
    return False

4. 翻转字符串中的元音字符

给你一个字符串 s ,仅反转字符串中的所有元音字母,并返回结果字符串。

元音字母包括 'a'、'e'、'i'、'o'、'u',且可能以大小写两种形式出现不止一次。

示例 :

输入:s = "hello"

输出:"holle"

在 python 中字符串不支持 a,b=b,a 所以需要提前将字符串转换为 List。

def reverseVowels(s):
    left, right = 0, len(s)-1
    vowel = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']
    s_list = list(s)
    while left < right:
        if s_list[left] in vowel and s_list[right] in vowel:
            s_list[left], s_list[right] = s_list[right], s_list[left]
            left +=1
            right -= 1
        if s[left] not in vowel:
            left +=1
        if s[right] not in vowel:
            right -= 1
    return "".join(s_list)

5. 判断是否为回文字符串(最多可以删除一个字符)

给你一个字符串 s,最多可以从中删除一个字符。请你判断 s 是否能成为回文字符串:如果能,返回 true ;否则,返回 false 。

示例:

输入:s = "aba"

输出:true

def validPalindrome(s):

    def check(s, low, high):
        while low < high:
            if s[low] == s[high]:
                low += 1
                high -= 1
            else:
                return False
        return True

    low = 0
    high = len(s) - 1
    while low < high:
        if s[low] == s[high]:
            low += 1
            high -= 1
        else:
            if check(s, low, high-1) or check(s, low+1, high):
                return True
            return False
    return True

6. 归并两个有序数组

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3

输出:[1,2,2,3,5,6]

解释:需要合并 [1,2,3] 和 [2,5,6] 。 合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

def merge(nums1, m, nums2, n):
    p1, p2 = m - 1, n - 1
    tail = m + n - 1
    while p1 >= 0 and p2 >= 0:
        if nums1[p1] > nums2[p2]:
            nums1[tail] = nums1[p1]
            p1 -= 1
        else:
            nums1[tail] = nums2[p2]
            p2 -=1
        tail -= 1
    while p1 >= 0:
        nums1[tail] = nums1[p1]
        p1 -= 1
        tail -= 1
    while p2 >= 0:
        nums1[tail] = nums2[p2]
        p2 -=1
        tail -= 1

7. 判断链表是否有环

给你一个链表的头节点 head ,判断链表中是否有环。

该问题有两个思路,第一个思路是搭建一个哈希表存储访问过的每一个 node 的地址,然后每访问一个 node,就检查一遍哈希表。第二个思路是快慢指针,如果链表有环那快慢指针一定会相遇。这两个思路都需要解决同一个问题即怎么判断两个 node 是同一个 node,leetcode 原生代码是推荐使用 == 运算法直接判断,但是这样判断只能说明两个 node 的值相等,不能保证是同一个 node,所以还是推荐使用 id() 函数比较 node 的地址。哈希表在运算时间上有优势,双指针在所用内存上有优势。

def hasCycle(head):
    if head == None:
        return False
    slow, fast = head, head
    while fast != None and fast.next != None:
        slow = slow.next
        fast = fast.next.next
        if id(fast) == id(slow):  # 原生代码是 fast == slow
            return True
    return False

8. 最长子序列

给你一个字符串 s 和一个字符串数组 dictionary ,找出并返回 dictionary 中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。如果答案不止一个,返回长度最长且字母序最小的字符串。如果答案不存在,则返回空字符串。

示例:

输入:s = "abpcplea", dictionary = ["ale","apple","monkey","plea"]

输出:"apple"

def findLongestWord(s, dictionary):
    def fun(s, target):
        len_s, len_target = len(s), len(target)
        p1, p2 = 0, 0
        while p1 < len_s and p2 < len_target:
            if s[p1] == target[p2]:
                p2 += 1
            p1 += 1
        return p2 == len_target

    res = ""
    for target in dictionary:
        if fun(s, target):
            if len(target) > len(res):
                res = target
            elif len(target) == len(res) and target < res:
                res = target
    return res

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值