题目链接 本题为树递归问题, 分析树结构可以发现, 叶子节点是同值子树, 非叶子节点如果左右子树均为同值子树, 那么该节点也是同值子树, 设计一个bool类型返回值, 参数为节点和父节点值的函数进行DFS求解. 算法时间复杂度为 O ( n ) \mathcal{O}(n) O(n),空间复杂度为 O ( 1 ) \mathcal{O}(1) O(1).
class Solution: def countUnivalSubtrees(self, root: TreeNode) -> int: ans=0 def dfs(node, pv): if node: lans, rans=dfs(node.left, node.val), dfs(node.right, node.val) nonlocal ans if lans and rans: ans+=1 return node.val==pv else: return False else: return True dfs(root, float('-inf')) return ans题目链接 按照节点的顺序, 每次翻转 k k k个节点, 对剩余节点不足 k k k个时进行special judge, 属于链表细节操作题. 建立虚拟头结点dummy,每次翻转k个节点,并将当前指针向前移动k位,在翻转函数revNode(node, k)中,先探测k位, 如果遇到空节点,说明待翻转节点不足k个,直接return. 记录待翻转的最末节点NK和其后节点NKP,进行顺序翻转,返回节点N1. 算法时间复杂度为 O ( n ) \mathcal{O}(n) O(n),空间复杂度为 O ( 1 ) \mathcal{O}(1) O(1).
class Solution: def reverseKGroup(self, head: ListNode, k: int) -> ListNode: if not head or k<=1: return head dummy=ListNode(-1) dummy.next=head prev=dummy def revNode(prev, k): cur, N1=prev, prev.next for i in range(k): # 向前探测k个节点 cur=cur.next if not cur: return cur NK, NKP, p=cur, cur.next, prev cur=p.next while cur != NKP: # 依次翻转k个节点 pnext=cur.next cur.next=p p=cur cur=pnext prev.next=p N1.next=NKP return N1 while prev: prev = revNode(prev, k) return dummy.next题目链接 对目标方程展开得到 y i + y j + ∣ x i − x j ∣ = y i + y j + x j − x i = ( x j + y j ) + ( y i − x i ) y_i+y_j+|x_i-x_j|=y_i+y_j+x_j-x_i=(x_j+y_j)+(y_i-x_i) yi+yj+∣xi−xj∣=yi+yj+xj−xi=(xj+yj)+(yi−xi) 其中满足 i < j i<j i<j, 因此可以考虑使用单调队列/优先队列/堆求解,对于固定的点 ( x j , y j ) (x_j, y_j) (xj,yj),需要找到满足 x j − x i ≤ k x_j-x_i \leq k xj−xi≤k的最大 y i − x i y_i-x_i yi−xi的点,对点的 y i − x i y_i-x_i yi−xi属性维持最大值. 算法时间复杂度 O ( n ) \mathcal{O}(n) O(n), 空间复杂度 O ( n ) \mathcal{O}(n) O(n)(需要维护一个双端队列)
class Solution: def findMaxValueOfEquation(self, points: List[List[int]], k: int) -> int: q, ans=[], float('-inf') if not k: return 0 q.append((points[0][0], points[0][1]-points[0][0])) for i in range(1, len(points)): pt=points[i] while q and pt[0]-q[0][0]>k: q.pop(0) if q: ans=max(ans, pt[0]+pt[1]+q[0][1]) while q and pt[1]-pt[0]>=q[-1][1]: q.pop(-1) # 出现的早, 值还小, 离开单调队列 q.append((pt[0], pt[1]-pt[0])) return ans题目链接 动态规划问题,关键是找到状态转移方程. 定义 f [ i ] [ j ] f[i][j] f[i][j]表示text1的前 i i i个字符和text2的前 j j j个字符匹配,可以推导出转移方程如下 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + 1 t e x t 1 [ i − 1 ] = = t e x t 2 [ j − 1 ] f [ i ] [ j ] = max ( f [ i ] [ j − 1 ] , f [ i − 1 ] [ j ] , f [ i − 1 ] [ j − 1 ] ) O . W . \begin{aligned} &f[i][j]=f[i-1][j-1]+1 \quad text1[i-1]==text2[j-1] \\ &f[i][j]=\max(f[i][j-1], f[i-1][j], f[i-1][j-1]) \quad O.W. \end{aligned} f[i][j]=f[i−1][j−1]+1text1[i−1]==text2[j−1]f[i][j]=max(f[i][j−1],f[i−1][j],f[i−1][j−1])O.W.
class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: n, m= len(text1), len(text2) f = [[0 for _ in range(m+1)] for _ in range(1+n)] for j in range(1, m+1): for i in range(1, n+1): if text1[i-1]==text2[j-1]: f[i][j]=f[i-1][j-1]+1 else: f[i][j]=max(f[i-1][j], f[i][j-1], f[i-1][j-1]) return f[n][m]题目链接 本题主要使用辅助栈, 对字符路径进行拆分后按照相应的规则进行求解 算法时间复杂度 O ( n ) \mathcal{O}(n) O(n), 空间复杂度 O ( n ) \mathcal{O}(n) O(n)(需要维护一个栈)
class Solution: def simplifyPath(self, path: str) -> str: st = [] for e in path.split('/'): if e and e!='.' and e!='..': st.append(e) elif st and e=='..': st.pop(-1) return '/'+'/'.join(st)题目链接 本题是DP问题中的经典题型,主要考虑初始状态的定义和状态转移方程. 定义 f [ i ] [ j ] f[i][j] f[i][j]表示word1的前 i i i个字符和word2的前 j j j个字符的编辑距离,考虑到添加,删除,替换三种状态对应到状态转移方程中 f [ i ] [ j ] = min ( f [ i − 1 ] [ j ] , f [ i ] [ j − 1 ] , f [ i − 1 ] [ j − 1 ] ) + 1 \begin{aligned} f[i][j]=\min(f[i-1][j], f[i][j-1], f[i-1][j-1])+1 \end{aligned} f[i][j]=min(f[i−1][j],f[i][j−1],f[i−1][j−1])+1 如果出现word1[i]==word2[j],则更新 f [ i ] [ j ] f[i][j] f[i][j] f [ i ] [ j ] = min ( f [ i − 1 ] [ j − 1 ] , f [ i ] [ j ] ) \begin{aligned} f[i][j]=\min(f[i-1][j-1], f[i][j]) \end{aligned} f[i][j]=min(f[i−1][j−1],f[i][j]) 在初始化时,前0个字符和前 i i i个字符的编辑距离为 i i i,因此有 f [ 0 ] [ i ] = i , i = 1 , 2 , … , n f [ j ] [ 0 ] = j , j = 1 , 2 , … , m \begin{aligned} &f[0][i]=i, i=1,2,\dots,n \\ &f[j][0]=j, j=1,2,\dots,m \end{aligned} f[0][i]=i,i=1,2,…,nf[j][0]=j,j=1,2,…,m
class Solution: def minDistance(self, word1: str, word2: str) -> int: n, m= len(word1), len(word2) f=[[0 for _ in range(m+1)] for _ in range(n+1)] for i in range(1, n+1): f[i][0]=i for i in range(1, m+1): f[0][i]=i for i in range(1, n+1): for j in range(1, m+1): f[i][j]=min(f[i-1][j], f[i][j-1], f[i-1][j-1])+1 if word1[i-1]==word2[j-1]: f[i][j]=min(f[i][j], f[i-1][j-1]) return f[n][m]