class Solution:
def removeElement(self, nums: List[int], val: int) -> int:
n = len(nums)
slow = 0
fast = 0
while fast < n :
if nums[fast]!=val :
nums[slow] = nums[fast]
slow += 1
fast += 1
else :
fast += 1
return slow
注意本题的判断条件,是 slow-1 , 所以需要先判定 slow > 0
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
n = len(nums)
slow = 0
fast = 0
while fast < n :
# 注意这个判断条件,是 slow-1 , 所以需要先判定 slow > 0
if slow > 0 and nums[fast] == nums[slow-1] :
fast += 1
else :
nums[slow] = nums[fast]
fast += 1
slow += 1
return slow
注意本题,要最后进行一步赋值0的操作
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
slow = 0
fast = 0
while fast < n :
if nums[fast] != 0 :
nums[slow] = nums[fast]
slow += 1
fast += 1
else :
fast += 1
while slow < n :
nums[slow] = 0
slow += 1
class Solution:
def backspaceCompare(self, s: str, t: str) -> bool:
slow = 0
fast = 0
s = list(s)
t = list(t)
ns = len(s)
nt = len(t)
# 先做s
while fast < ns :
if s[fast] != '#':
s[slow] = s[fast]
slow += 1
fast += 1
else :
if slow > 0 :
slow -= 1
fast += 1
slen = slow
slow = 0
fast = 0
# 再做t
while fast < nt :
if t[fast] != '#':
t[slow] = t[fast]
slow += 1
fast += 1
else :
if slow > 0 :
slow -= 1
fast += 1
tlen = slow
if slen != tlen :
return False
else :
for i in range(slen):
if s[i]!=t[i]:
return False
return True
class Solution:
def sortedSquares(self, nums: List[int]) -> List[int]:
n = len(nums)
res = [0]*n
start = 0
end = n-1
# 倒序给结果数组赋值,这样才能保证是非递减顺序
index = n-1
while start <= end :
if nums[start]+nums[end] > 0 :
res[index] = nums[end]**2
end -= 1
index -= 1
elif nums[start]+nums[end] < 0 :
res[index] = nums[start]**2
index -= 1
start += 1
else :
res[index] = nums[start]**2
index -= 1
start += 1
return res
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
n = len(s)
slow = 0
fast = n-1
while slow < fast :
s[slow],s[fast] = s[fast],s[slow]
slow += 1
fast -= 1
class Solution:
def reverseStr(self, s: str, k: int) -> str:
n = len(s)
for i in range(0,n,2*k):
temp = s[i:i+k]
s = s[:i] + temp[::-1] + s[i+k:]
return s
class Solution:
def replaceSpace(self, s: str) -> str:
s = list(s)
n = len(s)
count = 0
for i in s :
if i == ' ':
count += 1
extend = [0]*count*2
s = s + extend
newn = n + count*2
slow = n-1
fast = newn-1
while slow > -1 :
if s[slow]!=' ' :
s[fast] = s[slow]
slow -= 1
fast -= 1
else :
s[fast-2:fast+1] = '%20'
fast -= 3
slow -= 1
return ''.join(s)
使用 split() 函数版
class Solution:
def reverseWords(self, s: str) -> str:
# 甚至可以不用这个strip
# 直接split也会把首尾的空格去掉
s = s.strip()
s = s[::-1]
s = s.split()
n = len(s)
for i in range(n) :
temp = s[i]
s[i] = temp[::-1]
return ' '.join(s)
class Solution:
def reverseWords(self, s: str) -> str:
s = list(s)
n = len(s)
slow = 0
fast = 0
while fast < n :
if slow == 0 and s[fast]==' ':
fast += 1
elif slow > 0 and s[fast]==' ' and s[slow-1] != ' ':
s[slow] = s[fast]
slow += 1
fast += 1
elif slow > 0 and s[fast]==' ' and s[slow-1] == ' ':
fast += 1
# 上面对 fast 做了加一操作,下面这里的 if 是和上面独立的
# 所以在进行一切操作之前,一定要加上最外层while循环的判断条件 fast < n
if fast < n and s[fast] != ' ':
s[slow] = s[fast]
slow += 1
fast += 1
# 最后一个字符是否是空格,是的话,就去掉
# 我上面的逻辑就会导致,最后一位可能是空格
if s[slow-1] == ' ':
s = s[:slow-1]
length = slow-1
else :
s = s[:slow]
lenght = slow
s = s[::-1]
left = 0
right = 0
while right < slow :
if s[right] != ' ':
right += 1
else :
temp = s[left:right]
s[left:right] = temp[::-1]
right += 1
left = right
# 这里也要注意,要单独处理 right 走到最后一个位置的情况,由于前面已经去掉了空格
# 所以要单独处理
if right == slow-1 :
temp = s[left:]
s[left:] = temp[::-1]
right += 1
left = right
return ''.join(s)
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
pre = None
cur = head
while cur :
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
边界错误情况:
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
slow = head
fast = head
while n > 0:
fast = fast.next
n -= 1
while fast and fast.next :
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return head
歪打正着+虚拟头节点:
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
virtual = ListNode(0,head)
slow = virtual
fast = virtual
while n > 0 :
fast = fast.next
n -= 1
while fast.next :
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return virtual.next
卡哥的代码
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
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
slow = head
fast = head
while n > 0 :
fast = fast.next
n -= 1
# 单独处理,当链表长度等于N的情况,即:删除头结点
if fast == None :
head = head.next
else :
while fast.next :
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return head
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
curA = headA
curB = headB
countA = 0
countB = 0
while curA :
curA = curA.next
countA += 1
while curB :
curB = curB.next
countB += 1
# 在下面这个判断之后,只需要考虑 countA >= countB 的情况了
if countA < countB :
headA,headB = headB,headA
countA,countB = countB,countA
diff = countA - countB
while diff > 0 :
headA = headA.next
diff -= 1
while headA :
if headA == headB :
return headA
headA = headA.next
headB = headB.next
return None
这里列出一个代码对比:
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# If there is a cycle, the slow and fast pointers will eventually meet
if slow == fast:
# Move one of the pointers back to the start of the list
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
# If there is no cycle, return None
return None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = head
fast = head
while fast and fast.next :
slow = slow.next
fast = fast.next.next
if slow == fast :
fast = head
while fast != slow :
slow = slow.next
fast = fast.next
return slow
return None
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(0,n-2):
if nums[i] > 0 :
break
if i > 0 and nums[i] == nums[i-1] :
continue
left = i+1
right = n-1
while left < right :
if nums[i] + nums[left] + nums[right] > 0 :
right -= 1
elif nums[i] + nums[left] + nums[right] < 0 :
left += 1
else :
path = [nums[i] , nums[left] , nums[right]]
res.append(path)
while left < right and nums[right] == nums[right-1]:
right -= 1
while left < right and nums[left] == nums[left+1]:
left += 1
left += 1
right -= 1
return res
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums = sorted(nums)
n = len(nums)
res = []
for i in range(0,n-3):
if i > 0 and nums[i]==nums[i-1]:
continue
# 剪枝细节,一定注意,要考虑target是负数的情况
if nums[i] > 0 and nums[i] > target:
# 这里因为是最外层循环,所以break还是return 无所谓
break
for j in range(i+1,n-2):
if j > i+1 and nums[j]==nums[j-1]:
continue
# 剪枝细节,一定注意,要考虑target是负数的情况,同时要留意到:
# 多个负数相加是更小的负数,所以(nums[i]+nums[j]) > 0是必须的
# 比如 target=-8,解是[-1,-2,-2,-3],前两个的加和是大于target的!
if (nums[i]+nums[j]) > 0 and (nums[i]+nums[j]) > target:
# 注意这里,不能是return ,而是break
break
left = j+1
right = n-1
temp = target - (nums[i]+nums[j])
while left < right :
if nums[left]+nums[right] > temp :
right -= 1
elif nums[left]+nums[right] < temp :
left += 1
else :
path = [nums[i],nums[j],nums[left],nums[right]]
res.append(path)
while left < right and nums[left]==nums[left+1]:
left += 1
while left < right and nums[right]==nums[right-1]:
right -= 1
left += 1
right -= 1
return res
class MyQueue:
def __init__(self):
self.pushin = []
self.pushout = []
def push(self, x: int) -> None:
self.pushin.append(x)
def pop(self) -> int:
if self.pushout != [] :
return self.pushout.pop()
else :
self.pushout = self.pushin[::-1]
self.pushin = []
return self.pushout.pop()
def peek(self) -> int:
# 我觉得这里是唯一的难点,搞清楚代码复用的逻辑
# pop出来后,在对pushout,append进去就好了
# 这样下次再pop,还是这个值,是正确的!
# 因为pushout已经可以看做是一个队列了
num = self.pop()
self.pushout.append(num)
return num
def empty(self) -> bool:
if self.pushin == [] and self.pushout == []:
return True
else :
return False
两个队列实现:
from collections import deque
class MyStack:
def __init__(self):
self.dq1 = deque()
self.dq2 = deque()
self.number = 0
def push(self, x: int) -> None:
self.dq1.append(x)
self.number += 1
def pop(self) -> int:
if self.empty():
return None
for i in range(0,self.number-1):
self.dq2.append(self.dq1.popleft())
num = self.dq1.popleft()
self.dq1 , self.dq2 = self.dq2 , self.dq1
self.number -= 1
return num
def top(self) -> int:
return self.dq1[-1]
def empty(self) -> bool:
if len(self.dq1) == 0:
return True
else :
return False
一个队列实现:
from collections import deque
class MyStack:
def __init__(self):
self.dq1 = deque()
self.number = 0
def push(self, x: int) -> None:
self.dq1.append(x)
self.number += 1
def pop(self) -> int:
if self.empty():
return None
for i in range(0,self.number-1):
self.dq1.append(self.dq1.popleft())
num = self.dq1.popleft()
self.number -= 1
return num
def top(self) -> int:
return self.dq1[-1]
def empty(self) -> bool:
if len(self.dq1) == 0:
return True
else :
return False
class Solution:
def isValid(self, s: str) -> bool:
stack = []
n = len(s)
i = 0
while i < n :
if s[i]=='(' :
stack.append(')')
elif s[i]=='[' :
stack.append(']')
elif s[i]=='{' :
stack.append('}')
else :
if stack == [] or stack.pop() != s[i]:
return False
i += 1
if len(stack)!=0 :
return False
else :
return True
class Solution:
def removeDuplicates(self, s: str) -> str:
stack = []
n = len(s)
i = 0
while i < n :
if stack == [] :
stack.append(s[i])
else :
if s[i] == stack[-1]:
stack.pop()
else :
stack.append(s[i])
i += 1
return ''.join(stack)
from collections import deque
class DQ:
def __init__(self):
self.dq = deque()
def push(self,val):
if len(self.dq) == 0 :
self.dq.append(val)
else :
while len(self.dq) != 0 and val > self.dq[-1] :
self.dq.pop()
self.dq.append(val)
def top(self):
return self.dq[0]
def popleft(self):
self.dq.popleft()
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
res = []
dq = DQ()
n = len(nums)
for i in range(k):
dq.push(nums[i])
res.append(dq.top())
for i in range(k,n):
if nums[i-k] == dq.top() :
dq.popleft()
dq.push(nums[i])
res.append(dq.top())
return res
from collections import deque
class MyQueue: #单调队列(从大到小
def __init__(self):
self.queue = deque() #这里需要使用deque实现单调队列,直接使用list会超时
#每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
#同时pop之前判断队列当前是否为空。
def pop(self, value):
if self.queue and value == self.queue[0]:
self.queue.popleft()#list.pop()时间复杂度为O(n),这里需要使用collections.deque()
#如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
#这样就保持了队列里的数值是单调从大到小的了。
def push(self, value):
while self.queue and value > self.queue[-1]:
self.queue.pop()
self.queue.append(value)
#查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
def front(self):
return self.queue[0]
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
que = MyQueue()
result = []
for i in range(k): #先将前k的元素放进队列
que.push(nums[i])
result.append(que.front()) #result 记录前k的元素的最大值
for i in range(k, len(nums)):
que.pop(nums[i - k]) #滑动窗口移除最前面元素
que.push(nums[i]) #滑动窗口前加入最后面的元素
result.append(que.front()) #记录对应的最大值
return result
卡哥的代码:
#时间复杂度:O(nlogk)
#空间复杂度:O(n)
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#要统计元素出现频率
map_ = {} #nums[i]:对应出现的次数
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i], 0) + 1
#对频率排序
#定义一个小顶堆,大小为k
pri_que = [] #小顶堆
#用固定大小为k的小顶堆,扫描所有频率的数值
for key, freq in map_.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
heapq.heappop(pri_que)
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
前K个高频元素–大顶堆小顶堆