Leetcode刷题(17) 双指针系列

Leetcode刷题(17) 双指针系列

快慢指针系列(泛指)

参考labuladong的如何去除有序数组的重复元素

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

# 双指针(快慢指针)
class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        if n == 0:
            return 0
        slow = 0
        fast = 1
        while(fast < n):
            # 如果当前的nums[fast]和当前的nums[slow]不同
            # 便后移slow, 将nums[fast]赋值给后移之后的nums[fast]
            if nums[fast] != nums[slow]:
                slow += 1
                nums[slow] = nums[fast]
            # 每次都要后移一次fast
            fast += 1
        return slow + 1

83. 删除排序链表中的重复元素

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head:
            return None

        slow = head
        fast = head

        while fast!=None:
            # 当遇到slow.val的值和fast.val的值不相同的时候
            # 就可以直接跳过中间相同val的节点连接到这个fast.val上
            # 然后更新slow为fast指向的节点
            if slow.val != fast.val:
                # 跳过当前的fast
                slow.next = fast
                slow = fast
            # fast一直在向前移动
            fast = fast.next
        # 注意这里要把slow后面多余的节点给截断
        slow.next = None
        return head
    

283. 移动零

双指针之左右指针

参考labuladong的如何高效解决接雨水问题

class Solution(object):
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        if n == 0:
            return []
        
        slow = 0
        for fast in range(n):
            # 如果i的位置不是0的话就把i上的元素填到j的位置上
            if nums[fast] != 0:
                nums[slow] = nums[fast]
                # 如果不是自己换自己的话, 就要将0换到后面保持0的个数
                if slow != fast:
                    nums[fast] = 0
                # 腾出下一个放非0数字的位置
                slow += 1

11. 盛最多水的容器

相向而行的左右指针

class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        # 双指针, 左右指针相向而行
        n = len(height)
        if n == 0:
            return 0
        left = 0
        right = n - 1
        ares = 0
        while left < right:
            if height[left] < height[right]:
                ares = max(ares, (right - left) * height[left])
                left += 1
            else:
                ares = max(ares, (right - left) * height[right])
                right -= 1
        return ares
class Solution(object):
    def maxArea(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        n = len(height)
        left = 0
        right = n - 1 
        max_area = 0
        while(left < right):
            # 得到面积
            max_area = max(min(height[right], height[left]) * (right-left), max_area)
            # 小的height向大的height的方向移动
            if height[left] > height[right]:
                right -= 1
            else:
                left += 1
        return max_area
            

42. 接雨水

class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        n = len(height)
        if n == 0:
            return 0
        l = 0
        l_max = height[l]
        r = n -1
        r_max = height[r]
        ans = 0
        while l <= r:
            l_max = max(l_max, height[l])
            r_max = max(r_max, height[r])
            if l_max < r_max:
                ans += l_max - height[l]
                l += 1
            else:
                ans += r_max - height[r]
                r -= 1
        return ans

15. 三数之和

先排序,再用双指针,毕竟要的只是值不是索引

参考labuladong的一个函数秒杀N桑(Sum)问题

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums = sorted(nums)
        n = len(nums)
        ans = []
        def twoSum(start, target):
            l = start
            r = n-1
            res = []
            while(l < r):
                sum_ = nums[l] + nums[r]
                left = nums[l]
                right = nums[r]
                if sum_ < target:
                    # while(l < r and left==nums[l]):
                    l += 1
                elif sum_ > target:
                    # while(l < r and right==nums[r]):
                    r -= 1
                elif sum_ == target:
                    res.append([left, right])
                    while(l < r and left==nums[l]):
                        l += 1
                    while(l < r and right==nums[r]):
                        r -= 1
            return res

        i = 0
        while i < n:
            cur_i = i
            target = 0 - nums[cur_i]
            res = twoSum(cur_i + 1, target)
            for re in res:
                re.append(nums[cur_i])
                ans.append(re)
            i += 1
            # 跳过相等的元素,避免重复
            while(i < n and nums[cur_i]==nums[i]):
                i += 1
            
        return ans

704. 二分查找

参考labuladong的二分查找详解

左右指针

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums)
        while(left < right):
            # 防止right + left太大导致溢出
            mid = left + (right - left) / 2
            if (nums[mid] == target):
                 return mid
            elif(nums[mid] > target):
                right = mid
            elif(nums[mid] < target):
                left = mid + 1
        return -1

34. 在排序数组中查找元素的第一个和最后一个位置

左右指针

# 寻找边界一般用左闭右开的区间来搜索
class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        def findleft():
            l = 0
            r = len(nums)
            while(l < r):  # 终止条件 l == r
                mid = l + (r - l) / 2
                if nums[mid] == target:
                    r = mid
                elif nums[mid] > target:
                    r = mid
                elif nums[mid] < target:  # l跳过的一定是不大于target的数字, 终止的时候一般是在大于等于target的位置(如果有target的话就会在等于的位置)
                    l = mid + 1
            # 处理越界
            if l == len(nums):
                return -1
            else:
                return l if nums[l] == target else -1

        def findright():
            l = 0
            r = len(nums)
            while(l < r):   # 终止条件 l == r
                mid = l + (r - l) / 2
                # l只有加的操作, 所以在终止的时候l一定是跳过了一个等于(小于)target的,如果有等于的就不会轮到小于的
                # 轮不到等于的l就会一直右移直到越界(len(nums))
                if nums[mid] == target:
                    l = mid + 1
                elif nums[mid] > target:
                    r = mid
                elif nums[mid] < target:
                    l = mid + 1

            # 处理越界
            # l - 1 = -1
            if l == 0: 
                return -1
            else:
                return l-1 if nums[l-1] == target else -1
        l = findleft()
        r = findright()
        return [l, r]

我想下面这两题也能算针对两个不同字符串的双指针吧:

415. 字符串相加

class Solution:
    def addStrings(self, num1, num2):
        res = ""
        # carry 记录上一次计算的进位
        i, j, carry = len(num1) - 1, len(num2) - 1, 0
        # 从低位遍历, 反着遍历
        while i >= 0 or j >= 0:
            n1 = int(num1[i]) if i >= 0 else 0
            n2 = int(num2[j]) if j >= 0 else 0
            tmp = n1 + n2 + carry  # 上一次计算的进位加到这里
            carry = tmp / 10
            res = str(tmp % 10) + res
            i, j = i - 1, j - 1
        return "1" + res if carry else res

43. 字符串相乘

class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """

        n1 = len(num1)
        n2 = len(num2)
        n = n1 + n2
        res = [0] * n
        for i in range(n1 - 1, -1, -1):
            for j in range(n2 - 1, -1, -1):
                p1 = i + j
                p2 = i + j + 1
                # 其实下面这段我想了很久才想通, 我觉得p1和p2反了,
                # 之后才想起来, p1才是高位, 而且在p1上不可能再有进位
                curtotal = int(num1[i]) * int(num2[j]) + res[p2] 
                res[p2] = curtotal % 10
                res[p1] += curtotal / 10 

        count = 0
        while(count < n and res[count] == 0):
            count += 1
        if count >= n:
            return "0"
        else:
            res = res[count:]
            res = list(map(str, res))
            return ''.join(res)

                

剑指 Offer 52. 两个链表的第一个公共节点

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        a = headA
        b = headB
        # 除非两个都是None否则继续遍历
        while a or b:
            # 最后一段路两个人一定是一起走的
            if a == b:
                return a 
            else:
                if a == None:
                    a = headB
                else:
                    a = a.next
                if b == None:
                    b = headA
                else:
                    b = b.next
        return None

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值