LeetCode上的剑指offer题
刷题ing
#1.双递归
class Solution:
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
'''
先序遍历树A中的每个节点An,对应函数isSubStructure(A, B)
判断树A中以An为根节点的子树是否包含树B,对应函数helper(A, B)
'''
#有点双递归的意思
#是在说子结构,没说子树,B遍历空之后还可以有A的子节点
if not A or not B:
#空树不是任意一个树的子结构
return False
def helper(A,B):
if not B:
return True
if not A:
return False
if A.val==B.val:
return helper(A.left,B.left) and helper(A.right,B.right)
else:
return False
return helper(A,B) or self.isSubStructure(A.left,B) or self.isSubStructure(A.right,B)#找起始点
#1.递归
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root1 = root.left #存一下左节点之后调用
root.left = self.mirrorTree(root.right)
root.right = self.mirrorTree(root1)
return root
#2.队列
import collections
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
q = collections.deque()
q.append(root)
while q:
node = q.popleft()
if not node:
continue
#子树直接交换
tmp = node.left
node.left=node.right
node.right = tmp
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
return root
#3.栈模拟队列
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
s = []
s.append(root)
while s:
node = s[0]
s.pop(0)
if not node:
continue
#子树直接交换
tmp = node.left
node.left=node.right
node.right = tmp
if node.left:
s.append(node.left)
if node.right:
s.append(node.right)
return root
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
#要看子树想不相同
def helper(left,right):
if not left and not right:
return True
if not left and right or left and not right:
return False
if left.val!=right.val:
#比当前节点的值
return False
return helper(left.left,right.right) and helper(left.right,right.left)
return helper(root,root)
#1.老实人写法,左-右-下-左-上,保持每一行列移动的边界更新
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix:
return []
ans = []
m = len(matrix)
n = len(matrix[0])
l = 0
r = n-1
up = 0
down = m-1
while True:
#左→右
ans+=[matrix[up][i] for i in range(l,r+1)]
up += 1
if up>down:
break
#上↓下
ans+=[matrix[i][r] for i in range(up,down+1)]
r -= 1
if r<l:
break
#右←左
ans+=[matrix[down][i] for i in range(r,l-1,-1)]
down -= 1
if up>down:
break
#下↑上
ans+=[matrix[i][l] for i in range(down,up-1,-1)]
l += 1
if l>r:
break
return ans
#2.Py
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
ans = []
while matrix:
ans += list(matrix.pop(0))#取出第一行
matrix = list(zip(*matrix))[::-1]#逆时针rot90度
# A[::-1]这个操作对于行向量可以左右翻转;对于二维矩阵可以实现上下翻转
return ans
class MinStack:
def __init__(self):
"""
initialize your data structure here.
"""
#这就是那个吧,设置最小栈的那个
self.minstack = [float('inf')]
self.stack = []
def push(self, x: int) -> None:
self.stack.append(x)
self.minstack.append(min(x,self.minstack[-1]))#只加入当前最小值
def pop(self) -> None:
self.stack.pop()
self.minstack.pop()
def top(self) -> int:
return self.stack[-1]
def min(self) -> int:
return self.minstack[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.min()
class Solution:
def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
stack = []
#压栈试试
cnt=0
for i in range(len(pushed)):
stack.append(pushed[i])
while stack and stack[-1]==popped[cnt]:
stack.pop()
cnt+=1
return cnt==len(popped)
#1.队列
import collections
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
#层序遍历
q = collections.deque()
q.append(root)
ans = []
while q:
for i in range(len(q)):
node = q.popleft()
if not node:
continue
ans.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
return ans
#2.递归
from typing import List
from functools import reduce
from operator import iconcat
class Solution:
def levelOrder(self, root: TreeNode) -> List:
#递归,记录深度,并将同层节点放到同一个数组中
trees = []
self.levelOrderWithDepth(root, 0, trees)
return reduce(iconcat, trees, [])#reduce() 函数会对参数序列中元素进行累积。
def levelOrderWithDepth(self, root: TreeNode, depth: int, trees: [[int]]):
if not root or depth < 0:
return
while len(trees) <= depth:
trees.append([])
trees[depth].append(root.val)
self.levelOrderWithDepth(root.left, depth + 1, trees)
self.levelOrderWithDepth(root.right, depth + 1, trees)
#3.普通递归也
from operator import iconcat
class Solution:
def levelOrder(self, root: TreeNode) -> List[int]:
ans = []
def helper(node,depth,ans):
if not node:
return
if len(ans)<=depth:
ans.append([])
ans[depth].append(node.val)
helper(node.left,depth+1,ans)
helper(node.right,depth+1,ans)
helper(root,0,ans)
return reduce(iconcat, ans, [])
#1.dfs
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
ans = []
def helper(node,depth,ans):
if not node:
return
if len(ans)<=depth:
ans.append([])
ans[depth].append(node.val)
helper(node.left,depth+1,ans)
helper(node.right,depth+1,ans)
helper(root,0,ans)
return ans
#2.bfs
import collections
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
ans = []
if not root:
return ans
q = collections.deque()
q.append(root)
while q:
tmp = []
for i in range(len(q)):
node = q.popleft()
if not node:
continue
tmp.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
ans.append(tmp)
return ans
#1.dfs_换汤不换药
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
ans = []
def helper(node,depth,ans):
if not node:
return
if len(ans)<=depth:
ans.append([])
ans[depth].append(node.val)
helper(node.left,depth+1,ans)
helper(node.right,depth+1,ans)
helper(root,0,ans)
for depth in range(len(ans)):
if depth%2==1:
#奇数行反过来输出就okk
ans[depth] = ans[depth][::-1]
return ans
#2.bfs_同理
import collections
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
ans = []
if not root:
return ans
q = collections.deque()
q.append(root)
now_depth=0
while q:
tmp = []
for i in range(len(q)):
node = q.popleft()
if not node:
continue
tmp.append(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
if now_depth%2==1:
ans.append(tmp[::-1])
else:
ans.append(tmp)
now_depth+=1
return ans
#1.递归
class Solution:
def verifyPostorder(self, postorder: List[int]) -> bool:
#后序的话,最后一个是root,没法建立唯一的树,不知道左右子树的长度
#往回找,比root大就在右子树,比root小就在左子树,前边开始遍历即可
def helper(pos):
if len(pos)<=1:
#到了子节点了
return True
root = pos[-1]
for i in range(len(pos)):
if pos[i]>root:
break
for j in range(i,len(pos)-1):
if pos[j]<root:
return False
return helper(pos[:i]) and helper(pos[i:-1])
if not postorder:
return True
return helper(postorder)
#2.单调栈辅助迭代
#越往右越大,这样,就可以构造一个单调递增的栈,来记录遍历的元素。
#往右子树遍历的过程,value是越来越大的,一旦出现了value小于栈顶元素value的时候,
#就表示要开始进入左子树了(如果不是,就应该继续进入右子树,否则不满足二叉搜索树的定义
class Solution:
def verifyPostorder(self, postorder: [int]) -> bool:
stack, root = [], float("+inf")
for i in range(len(postorder) - 1, -1, -1):
if postorder[i] > root: return False
while(stack and postorder[i] < stack[-1]):
#找到左子树了,右子树的节点和root都丢出来
root = stack.pop()#查看左子树,当前为root
stack.append(postorder[i])
return True
#1.标准dfs
'''
用dfs的时候注意记录path的数组变化,应该在判断前添加val,到底时判断,到底且不属于的话记得pop不然下一个if的时候
数组值会变,path添加到ans里的时候记得copy,只是变量名的话是贴标签,之后会变化的!!!
'''
class Solution:
def pathSum(self, root: TreeNode, target: int) -> List[List[int]]:
#不是BST,dfs
if not root:
return []
ans = []
def helper(root,nums):
nums.append(root.val)
if not root.left and not root.right:
#到底
summ=sum(nums)
#print(nums)
if summ==target:
ans.append(nums[:])#nums要拷贝,不能是贴着变量名标签不然会随整体变化最后清空
if root.left:
helper(root.left,nums)
if root.right:
helper(root.right,nums)
nums.pop()#走到底且不满足的话要清理nums防止进入下一个if时nums变化了
helper(root,[])
return ans
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
#1.Hash
#On,On
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
#hash
if not head:
return head
memo = {None:None}#不能用dict()这样初始化,不然需要判断q.random!=None,毕竟dict的key一般不能为None
cur = head
#hashmap里存储(原节点,copy节点)的映射
while cur:
memo[cur] = Node(cur.val)
cur = cur.next
cur = head
#映射的值与值连接,节点组成新的链表
while cur:
memo[cur].next = memo[cur.next]
memo[cur].random = memo[cur.random]
cur = cur.next
return memo[head]
#2.原地修改(间隔节点法)
#On,O1
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
#原地修改
if not head:
return head
cur = head
copy = None
#将拷贝节点放到原节点后面,例如1->2->3这样的链表就变成了这样1->1'->2->2'->3->3'
while cur:
copy = Node(cur.val)
copy.next = cur.next
cur.next = copy
cur = cur.next.next
cur = head
#把拷贝节点的random指针安排上
#复制的random就是上一个节点的random的next
while cur:
if cur.random:
cur.next.random = cur.random.next#此时cur.next就都是copy节点了
cur = cur.next.next
newhead = head.next#copy第一个节点位置
#分离拷贝节点和原节点,变成1->2->3和1'->2'->3'两个链表,后者就是答案
#想拉拉链一样,咔咔咔咔咔咔
cur = head
tmp = None
while cur and cur.next:
tmp = cur.next
cur.next = tmp.next
cur = tmp
return newhead
#3.dfs
#本质与hashmap很类似
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
def dfs(head):
if not head: return None
if head in visited:
return visited[head]#return copy的节点
# 创建新结点
copy = Node(head.val, None, None)
visited[head] = copy
copy.next = dfs(head.next)#连到dfs的copy节点上
copy.random = dfs(head.random)
return copy
visited = {}
return dfs(head)
#1.递归中序+头结点设定+最后建立循环
class Solution:
def treeToDoublyList(self, root: 'Node') -> 'Node':
def dfs(cur):
if not cur: return
dfs(cur.left) # 递归左子树
if self.pre: # 修改节点引用
self.pre.right, cur.left = cur, self.pre
else: # 记录头节点
self.head = cur
self.pre = cur # 保存 cur
dfs(cur.right) # 递归右子树
if not root: return
self.pre = None
dfs(root)
self.head.left, self.pre.right = self.pre, self.head#首尾连接
return self.head
#2.迭代中序+建立哑结点标记头部,首尾连接跳过dummy
class Solution:
def treeToDoublyList(self, root: 'Node') -> 'Node':
#双向链表也和tree一样,是left和right标向
#升序的话就是前=中序遍历
if not root:
return None
dummy = Node(0)
last = dummy
stack = [(0,root)]
while stack:
opt,node = stack.pop()
if not node:
continue
if opt==1:
#print(last.right,dummy.right)#神奇的是第一次last赋值后dummy被挂在了头结点左边,标签行为转移到本体上
#浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存
#按道理来讲用none来init加个判断连到head上会比较好
last.right = node
node.left = last
last = node
else:#更早的关系会被提前压入栈
stack.append((0,node.right))
stack.append((1,node))
stack.append((0,node.left))
dummy.right.left = last
last.right= dummy.right
return dummy.right
#1.井号层序遍历隔开+恢复时注意边界,队列的元素对应一左一右俩
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
q = collections.deque()
ans = []
q.append(root)
while q:
for i in range(len(q)):
node = q.popleft()
if not node:
ans.append('null')
continue
ans.append(str(node.val))
q.append(node.left)
q.append(node.right)
return "#".join(ans)
def deserialize(self, data):
data = data.split("#")
#print(data)
if data[0]=='null':
return None
q = collections.deque()
root = TreeNode(int(data[0]))
q.append(root)
i = 1
while q:
node = q.popleft()
if not node:
continue
node.left = TreeNode(int(data[i])) if data[i]!='null' else None
node.right = TreeNode(int(data[i+1])) if data[i+1]!='null' else None
i += 2
q.append(node.left)
q.append(node.right)
return root
#1.dfs+字符串先排序,重复字符不在同一位置进行dfs
class Solution:
def permutation(self, s: str) -> List[str]:
ans = []
def dfs(comb,s):
if len(s) == 0:
#一个单词满了
ans.append("".join(comb))
return
else:
#一个单词没填满
for i in range(len(s)):
if i==0:
dfs(comb+[s[i]],s[:i]+s[i+1:])
if i>0 and s[i]!=s[i-1]:
dfs(comb+[s[i]],s[:i]+s[i+1:])
s = "".join(sorted(s))
dfs([],s)
return ans
#2.dfs用dict、set一类剪枝
class Solution:
def permutation(self, s: str) -> List[str]:
c, res = list(s), []
def dfs(x):
if x == len(c) - 1:
res.append(''.join(c)) # 添加排列方案
return
dic = set()
for i in range(x, len(c)):
if c[i] in dic: continue # 重复,因此剪枝
dic.add(c[i])
c[i], c[x] = c[x], c[i] # 交换,将 c[i] 固定在第 x 位
dfs(x + 1) # 开启固定第 x + 1 位字符
c[i], c[x] = c[x], c[i] # 恢复交换
dfs(0)
return res
#1.hashmap
class Solution:
def majorityElement(self, nums: List[int]) -> int:
n = len(nums)//2
memo = {}
for i in range(len(nums)):
memo[nums[i]] = memo.get(nums[i],0)+1
if memo[nums[i]]>n:
return nums[i]
#2.排序后一定在中间
class Solution:
def majorityElement(self, nums: List[int]) -> int:
nums.sort()
return nums[len(nums)//2]
#3.摩尔投票法
class Solution:
def majorityElement(self, nums: List[int]) -> int:
#摩尔投票法:正负抵消,剩余即为众数
votes = 0
for num in nums:
if votes == 0: x = num
votes += 1 if num == x else -1
return x
#1.Pysort
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
arr.sort()
return arr[:k]
#2.写个快排
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
#使用 partition 过程找到下标为 k - 1 的那个数即可
def quicksort(nums,l,r,target):
if l<r:
i = l
j = r
key = nums[l]
while i<j:
while i<j and nums[j]>=key:
j-=1
if i<j:
nums[i]=nums[j]
i+=1
while i<j and nums[i]<=key:
i+=1
if i<j:
nums[j]=nums[i]
j-=1
nums[i]=key
if i<target:
quicksort(nums,i+1,r,target)
else:
quicksort(nums,l,i-1,target)
quicksort(arr,0,len(arr)-1,k-1)
return arr[:k]
#3.写个堆
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
if k == 0:
return list()
hp = [-x for x in arr[:k]]#因为py是最小堆所以取反数,除掉k以上大的值,之后的堆取反数输出,堆大小为k
heapq.heapify(hp)
for i in range(k, len(arr)):
if -hp[0] > arr[i]:
heapq.heappop(hp)
heapq.heappush(hp, -arr[i])
ans = [-x for x in hp]
return ans
#1.Pysort
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
def addNum(self, num: int) -> None:
self.stack.append(num)
self.stack.sort()
def findMedian(self) -> float:
if len(self.stack)%2==0:
mid = len(self.stack)//2
return (self.stack[mid-1]+self.stack[mid])/2
else:
mid = len(self.stack)//2
return self.stack[mid]
# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
#1.dpdp
'''
如果和是负数,那就从里边选个小点的负数:重新计数的环节
如果和是正数,那就先记录下来在扩大范围看看有没有更大的正数
'''
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
#dpdp
mm = nums[0]
dp = [0]*(len(nums))
dp[0]=nums[0]
for i in range(1,len(nums)):
dp[i] = max(nums[i],dp[i-1]+nums[i])#dp[i-1]有可能小于0
#dp[i-1]<0的场合:这里dp存的并不是当前最大和,而是看是否从i重新开始计数
#dp[i-1]>0的场合:先记下带nums[i]的,无论nums[i]为正负,mm负责记录max值
if dp[i]>mm:
mm = dp[i]
return mm
#2.dpdp_Py空间优化
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1, len(nums)):
nums[i] += max(nums[i - 1], 0)#在nums数组上改,O1,到i时,使用的i还没变化,i-1记录dp的
return max(nums)
#2.大根堆+小根堆
import heapq
class MedianFinder:
'''
把数据分为两部分,让左半部分永远元素个数永远大于等于右半部分,
这样左端大顶堆的堆顶就是左半部分最大值,右端小顶堆的堆顶就是右半部分最小值。
'''
def __init__(self):
self.right = [] # 小顶堆,保存较大的一半
self.left = [] # 大顶堆,保存较小的一半,负的小顶堆
def addNum(self, num: int) -> None:
'''
Push item on the heap, then pop and return the smallest item from the heap.
The combined action runs more efficiently than heappush() followed by a separate call to heappop().
当 m = n(即N为偶数):需向A添加一个元素。实现方法:将新元素num插入至B,再将B堆顶元素插入至A ;
当 N为奇数:需向B添加一个元素。实现方法:将新元素num插入至A,再将 A堆顶元素插入至B ;
if len(self.A) != len(self.B):
heappush(self.A, num)
heappush(self.B, -heappop(self.A))
else:
heappush(self.B, -num)
heappush(self.A, -heappop(self.B))
'''
if len(self.left) != len(self.right):
#奇数?
heappush(self.left, -heappushpop(self.right, num))
else:
#偶数?
heappush(self.right, -heappushpop(self.left, -num))
def findMedian(self) -> float:
#永远是right多存一点,left是负数注意
return self.right[0] if len(self.right) != len(self.left) else (self.right[0] - self.left[0]) / 2.0
#1.找规律,位数从低到高
'''
当 cur = 0时: 此位 1 的出现次数只由高位 high和位数决定:high*i
当 cur = 1时: 此位 1 的出现次数由高位 high ,位数和低位 low 决定,计算公式为:high×digit+low+1相当于整数0以下的部分以外多了一个1以及对应低位带来的部分
当 cur=2,3,⋯,9 时: 此位 1 的出现次数只由高位 high 决定,计算公式为:(high+1)×digit,0以上1的位数个肯定是有了
'''
class Solution:
def countDigitOne(self, n: int) -> int:
cnt = 0
i = 1
while n//i !=0:
high = n//(10*i)#位数,高位
cur = (n//i)%10#余数,当前位i
low = n-(n//i)*i#除法取整残差,低位
if cur==0:
cnt+=high*i
elif cur==1:
cnt+=high*i+low+1
else:
cnt+=(high+1)*i
i = i*10
return cnt
#2.递归,位数从高到低
class Solution:
def countDigitOne(self, n: int) -> int:
return self.dfs(n)
def dfs(self,n):
if n<=0: return 0
num_s = str(n)
high = int(num_s[0])
Pow = 10**(len(num_s)-1)
last = n - high*Pow
if high == 1:
return self.dfs(Pow-1)+self.dfs(last)+last+1
else:
return Pow+high*self.dfs(Pow-1)+self.dfs(last)
class Solution:
def findNthDigit(self, n: int) -> int:
i=0
last = 0
while n>0:
last = n
n-=(10**(i))*9*(i+1)
i+=1
#i就是当前所求数的位数,恢复n到循环的位置
n = last
start = 10**(i-1)
end = str(start+(n-1)//i)
num = end[(n-1)%i]#n-1的话就是从新的数开始计位了,从start开始个数和计位都是
return int(num)
#本来想用全排列选一下最小值的,但是测试用例比intmaxsize还大,这也就是说需要字符串比较大小
#1.字符串比较大小
#sorted key 不仅可以传lamda , 普通函数 , 还可以传有实现比较的类
class smallnumkey(str):
def __lt__(x,y):
return x+y<y+x
class Solution:
def minNumber(self, nums: List[int]) -> str:
ans = "".join(sorted(map(str,nums),key=smallnumkey))
return ans
#2.还是比较大小
#没用class,用了快排
class Solution:
def minNumber(self, nums: List[int]) -> str:
def fast_sort(l , r):
if l >= r: return
i, j = l, r
while i < j:
while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
strs[i], strs[j] = strs[j], strs[i]
strs[i], strs[l] = strs[l], strs[i]
fast_sort(l, i - 1)
fast_sort(i + 1, r)
strs = [str(num) for num in nums]
fast_sort(0, len(strs) - 1)
return ''.join(strs)
#1.dpdp
#边界条件注目
#小青蛙爬楼梯类问题
#还可以进一步空间优化就是了,-2:prepre,-1:pre,0:now这样三个值存储节省空间
class Solution:
def translateNum(self, num: int) -> int:
#分组,检查是否valid,+1
ans = 1#单数字字母 #双数字字母 #感觉很dpdp
num = str(num)
dp = [1]*(len(num))
if len(num)>=2 and int(num[0]+num[1])<=25:
dp[1]=2
for i in range(2,len(num)):
tmp = int(num[i-1]+num[i])
if tmp<=25 and tmp>=10:
dp[i] = dp[i-1]+dp[i-2]#1:和前一个数组成两位的字符,2:单独作为新的一个字符
else:
dp[i] = dp[i-1]#没法和前一个数组成两位的字符,拼法没有增多
return dp[-1]
#2.递归
class Solution:
def translateNum(self, num: int) -> int:
self.ans = 0
def helper(nums):
if len(nums)==0:
self.ans+=1
return
helper(nums[1:])#1的场合
if len(nums)>=2:
if nums[0]=='0' or nums[:2]>'25':
return
helper(nums[2:])#2的场合
helper(str(num))
return self.ans
#1.dfs超时了,避免重复搜索de记忆存储法基本上就是dp,那还不如dp
class Solution:
def maxValue(self, grid: List[List[int]]) -> int:
#dpdp,或者dfs两方向遍历也行
#直接用dfs结果超时了,看看剪枝
self.ans = 0
def dfs(grid,i,j,tmp):
tmp+=grid[i][j]
if i==len(grid)-1 and j==len(grid[0])-1:
#到角落了
self.ans = max(self.ans,tmp)
return
if i+1<len(grid):
dfs(grid,i+1,j,tmp)
if j+1<len(grid[0]):
dfs(grid,i,j+1,tmp)
dfs(grid,0,0,0)
return self.ans
#2.dpdp
class Solution:
def maxValue(self, grid: List[List[int]]) -> int:
m =len(grid)
n =len(grid[0])
dp = [[0]*n for _ in range(m)]
dp[0][0]=grid[0][0]
for j in range(1,n):
#右
dp[0][j]=dp[0][j-1]+grid[0][j]
for i in range(1,m):
#下
dp[i][0]=dp[i-1][0]+grid[i][0]
for j in range(1,n):
dp[i][j] = max(dp[i-1][j],dp[i][j-1])+grid[i][j]
return dp[-1][-1]
#1.双指针哈希
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
last_idx=-1
ans = 0
memo = dict()
for i in range(len(s)):
if s[i] in memo and memo[s[i]]>last_idx:
#出现重复字符,且字符位置大于当前记录子串的起始idx,得是在现在的子串里重复的字符
#一换一,ans不用更新
last_idx = memo[s[i]]
memo[s[i]]=i
else:
memo[s[i]]=i
ans = max(ans,i-last_idx)#上一个重复字开始的新位置到i长度,abca的话就是b2-a[-1]=3
return ans
#2.空间优化dp哈希
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
dic = {}
res = tmp = 0
for j in range(len(s)):
i = dic.get(s[j], -1) # 获取索引 i,没有就返回-1
dic[s[j]] = j # 更新哈希表
'''
dp记录当前子串的长度
1;dp[j-1]=j-i,子串长度变不动了,遇到相同字符了,当前子串j-i长度
'''
tmp = tmp + 1 if tmp < j - i else j - i # dp[j - 1] -> dp[j]
res = max(res, tmp) # max(dp[j - 1], dp[j])
return res