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