392 判断一个str是不是另一个str的子序列(不用连续)
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
if len(t) < len(s):
return False
l = 0
r = 0
while l < len(s):
if s[l] == t[r]:
l += 1
r += 1
else:
r += 1
if r >= len(t):
return l == len(s)
return True
自己写的双指针, 有点丑陋
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
i, j = 0, 0
while i < len(s) and j < len(t):
if s[i] == t[j]:
i += 1
j += 1
return i == len(s)
学习一下标答
15 三数之和(经经典典)
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
ans = []
n = len(nums)
for i in range(n):
l = i + 1
r = n - 1
if i > 0 and nums[i] == nums[i-1]: # 对i去重
continue
while l < r:
target = 0
x = nums[i]
L = nums[l]
R = nums[r]
if x + L + R > target:
r -= 1
elif x + L + R < target:
l += 1
else:
ans.append([x, L, R])
l += 1
r -= 1
while l < r and nums[l] == nums[l-1]: # 对l去重, 注意这个部分应该在target == 0的时候才去重
l += 1
while l < r and nums[r] == nums[r+1]: # 对r去重, 注意这个部分应该在target == 0的时候才去重
r -= 1
return ans
复杂度分析: O ( n 2 ) O(n^2) O(n2)
206 翻转列表
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = None
prev = dummy
cur = head
while cur:
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
return prev
特别注意这个情况是不能使用dummy head的,
1.是因为翻转过后第一个元素应该是None
2.否则会发生环的情况, 我来具体解释一下:
dummy -> 1 -> 2
dummy <----> 1 -> (经过cur.next = prev)
19 删除列表的倒数第N个节点
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 创建一个虚拟节点,并将其下一个指针设置为链表的头部
dummy_head = ListNode(0, head)
# 创建两个指针,慢指针和快指针,并将它们初始化为虚拟节点
slow = fast = dummy_head
# 快指针比慢指针快 n+1 步
for i in range(n+1):
fast = fast.next
# 移动两个指针,直到快速指针到达链表的末尾
while fast:
slow = slow.next
fast = fast.next
# 通过更新第 (n-1) 个节点的 next 指针删除第 n 个节点
slow.next = slow.next.next
return dummy_head.next
几个问题
- fast和slow都从哪里开始
- 为什么需要dummy
- 最后为什么返回dummy.next而不是一开始head的copy
一个思想解决: 当r
到达none是,l
应该是倒数第n个, 此时l, r
的index分别是len - n, len
. 从这个状态一直往回推, 我们可以得到0, n
160 相交链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
if headA == None or headB == None:
return None
l = headA
r = headB
while l != r:
if l == None:
l = headB
else:
l = l.next
if r == None:
r = headA
else:
r = r.next
return l
情况1: 有环, 则在相交点遇上对方
情况2: 无环, 则在最小公倍数次数之后在None遇见
18 四数之和
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
n = len(nums)
ans = []
for i in range(n):
for j in range(n - 1, i, -1):
if i > 0 and nums[i] == nums[i - 1]:
continue
if j < len(nums) - 1 and nums[j] == nums[j + 1]:
continue
l = i + 1
r = j - 1
while l < r:
cur_sum = nums[i] + nums[j] + nums[l] + nums[r]
if cur_sum < target:
l += 1
elif cur_sum > target:
r -= 1
else:
ans.append([nums[i], nums[j], nums[l], nums[r]])
l += 1
r -= 1
while l < r and nums[l] == nums[l-1]:
l += 1
while l < r and nums[r] == nums[r + 1]:
r -= 1
return ans
情况只能说是一模一样, 只需要在三数之和的基础上再套一层for循环即可
复杂度分析: O ( n 3 ) O(n^3) O(n3)
42 接雨水
一个自然的想法是对于一个木桶, 看左边最高和右边最高就可以了, 但这个情况就需要我们用两个数组来储存, 用双指针的方法可以把空间复杂度降下来.
对于一个桶, 如果前缀最大小, 那么这个桶的容量已经可以计算了
class Solution:
def trap(self, height: List[int]) -> int:
ans = left = pre_max = suf_max = 0
right = len(height) - 1
while left < right:
pre_max = max(pre_max, height[left])
suf_max = max(suf_max, height[right])
if pre_max < suf_max:
ans += pre_max - height[left]
left += 1
else:
ans += suf_max - height[right]
right -= 1
return ans