class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 滑动窗口问题
l,r = 0,0 # 定义窗口的左右边界
maxn = 0 # 记录最大值
while l <= len(s)-1: # 左边界可以一直试到最后一个位置
while (r+1 <= len(s)-1) and (s[r+1] not in s[l:r+1]): # r的增加不能超过右边界
r+=1
# 右边界停留在了合适的位置上,计算一下当前的长度吧
if r-l+1 > maxn:
maxn = r-l+1
l+=1 # 左边界滑动一格
return maxn
每个数需要和结果集中倒数第二个判断是否相等,是这题的解题关键,因为题目说允许两个数重复。
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
if len(nums)<=2:
return len(nums)
"""
#只管遍历数组即可,遇到合适的数就往前放(赋值),不合适的就不管这个数了
#那么前边就形成了一个好的结果集。
#往前放的时候不用担心,我们会设置一个变量在结果集尾,严格把控人员的进入
"""
# 设置一个看门的变量,前两个元素一定没问题,所以当前的队尾下标就是1
index = 1
# 查看数组中的每个元素(从第三个元素开始看就行),看能不能放行
for i in range(2, len(nums)):
if nums[i] != nums[index-1]: #当前数和结果集中倒数第二个数比较一下
nums[index+1] = nums[i]
index+=1
return index+1
这个题应该属于偏怪的技巧解题吧~~利用数值本身和索引之间的对应关系
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
"""
由于数组中的数是有固定范围的,可以对应映射到下标索引上。
那我们就可以通过操作下标索引位置的那个数,来折射出我们的需求
"""
# 存放找到的结果
res = []
# 遍历数组中的每个数
for num in nums:
index = abs(num)-1 #这个数的索引
#找到那个数nums[index]看一下
if nums[index] < 0: #说明之前有人访问过它了
res.append(abs(num)) #它不行,它是重复数
else: #第一次访问
nums[index] *= -1 #变成负数
return res
import math
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
# 想象成一个队列比较好理解
# 左边不需要一个一个往右扩,因为已经算过这一段的和了。
# 左边挨个削掉数,只需要减一下就算出来新的和了,不需要再重新累加,不断的削减就行
# 只需要定义几个全局变量就够了
left,right=0,0
curSum=0
minLength = 2*len(nums) # 表示一个很大的数
while right<len(nums): # 右边可以一直扩展
curSum+=nums[right] #往里放就行
right+=1 #右边界准备要放的下一个元素
# 只要变了我就判断一下当前的和
while curSum>=target:
minLength = right-left if right-left<minLength else minLength
curSum-=nums[left] # 左边削减
left+=1
return 0 if minLength==2*len(nums) else minLength
定义变量来控制走的边界,要比自己计算每次要走多少步,省事的多
【学习一下python中从大数到小数递减的for循环遍历,如何用range实现】
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
# 定义四个边界,边界控制我们要的走墙边的长度
# 沿着矩阵每走完一个墙边,边界就会压缩一下
# 这四个边界的值,刚好也能被用来作为访问数组的下标,也就是我们要走的那行/列
top,bottom,left,right = 0,n-1,0,n-1 #定义边界
count = 1 #计数
matrix = [[0 for x in range(n)] for x in range(n)]
while count <= n**2:
#沿着上边界右走
for i in range(left,right+1):
matrix[top][i] = count
count += 1
top += 1 #上边界压缩
#沿着右边界下走
for i in range(top,bottom+1):
matrix[i][right] = count
count += 1
right -= 1 #右边界压缩
#沿着下边界左走
for i in range(right,left-1,-1): # range(起点,终点,步长)
matrix[bottom][i] = count
count += 1
bottom -= 1 #下边界压缩
#沿着左边界上走
for i in range(bottom,top-1,-1):
matrix[i][left] = count
count += 1
left += 1 #左边界压缩
return matrix
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head==None or head.next==None:
return head
else:
newHead = head.next #这是最终要返回的头
pre = head
while pre and pre.next: #保持有两个数
cur = pre.next
temp = cur.next
cur.next = pre #核心语句1
if temp==None or temp.next==None:
pre.next = temp
return newHead
else:
pre.next = temp.next #核心语句2
#往下走两格,进入到下一个循环
pre = temp
return newHead
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
nullHead = ListNode(0,head)
# 设立双指针cur、pre,想象两者之间构成一个程度为n的滑块
# 1、pre先走出n步,cur不动,两者之间的距离是n
# 2、一起走,当pre到末尾,cur指向的是倒数第n个
pre = nullHead
cur = nullHead
while n: #pre走到了正确的位置上
pre = pre.next
n -= 1
while pre.next!=None: #pre到最后一个节点时停止
pre = pre.next
cur = cur.next
cur.next = cur.next.next #核心语句
return nullHead.next #返回第一个实节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
# 设置快慢指针,快指针每次走两步,慢指针每次走一步
fast = head
slow = head
while fast and fast.next: # 如果是直链,一定会退出while循环的
fast = fast.next.next # 快指针大胆往前走两步
slow = slow.next # 慢指针走一步
if fast == slow: # 如果他俩相遇了,说明有环
#开始模拟,目的是找到环的入口
index1 = fast #相遇点
index2 = head #链表起点
while index1!=index2: #模拟俩人一起走的过程,最终一定会在环入口处相遇
index1 = index1.next
index2 = index2.next
return index1
return None
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 根(对根有个初步的判定)、左、右、根(这里重点结合左右子树信息进行操作)
if root==None:
return None
if root==p or root==q: # 这个节点就是p或q,它就是最近公共祖先,直接返回结果
return root
leftSolution = self.lowestCommonAncestor(root.left, p, q) # 左子树返回p、q的存在情况
rightSolution = self.lowestCommonAncestor(root.right, p, q) # 右子树返回p、q的存在情况
if leftSolution and rightSolution: # 分析可知,这个根节点就是最近祖先
return root
elif leftSolution==None: # 左边没有p或q,右边是有的,继续往上返回右子树的返回结果,只能往上回溯了,说明最近祖先还得往上找
return rightSolution
else: # 右边没有p或q,左边是有的,继续往上返回左子树的返回结果,同理只能往上回溯了,说明最近祖先还得往上找
return leftSolution
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
# 先审视一下root值
if root==None:
return None
if root.val<low: # 如果这个值都小于左边界了,那它的左子树肯定更小,剪掉!
return self.trimBST(root.right, low, high) # 只要右子树修剪好的
elif root.val>high: # 如果这个值都大于右边界了,那它的右子树肯定更大,剪掉!
return self.trimBST(root.left, low, high) # 只要左子树修剪好的
else: # root值在正常范围内
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
return root
思路1:【迭代法】
思路2:【递归法】
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
#节点该在这里插入哈,但是递归法并不是直接进行节点的指针变换进行硬性插入操作
#而是执行合理的返回操作,往上返回的时候,上一层的节点(递归栈中保存着)会接住它
if root==None:
newNode = TreeNode(val, None, None)
return newNode #此时它就是一棵小子树,要被上层节点接着,我们进行返回
#接住就是用返回值做赋值,那正好就改变了左/右子树,间接实现了插入的操作
if val<root.val:
ltree_returned = self.insertIntoBST(root.left, val) #返回来的左子树
root.left = ltree_returned #当前节点左指针接住,也就是修改左子树指针
else:
rtree_returned = self.insertIntoBST(root.right, val) #返回来的右子树
root.right = rtree_returned #当前节点右指针接住,也就是修改右子树指针
return root #返回调整好的当前这棵树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if root==None:
return None
if root.val==key: #执行删除操作,并做出适当的返回操作
### 此时点的位置很关键(4种)###
# 1.左右都空
if root.left==None and root.right==None:
return None #把它变成空,也就是往上返回None值,上边会有人接着呢
# 2.左边不空,右边空
elif root.left and root.right==None:
return root.left #给上边的人返回左子树
# 3.右边不空,左边空
elif root.right and root.left==None:
return root.right #给上边的人返回右子树
# 4.左右均不空
else:
cur = root.right
while cur.left:
cur = cur.left
cur.left = root.left
# 右子树弄妥了,返回右子树给上边的人吧
return root.right
if key<root.val: #往左继续遍历
root.left = self.deleteNode(root.left, key)
if key>root.val: #往右继续遍历
root.right = self.deleteNode(root.right, key)
return root
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
# 【key】:以后序的列表为基准点,来写终止边界情况
if len(postorder)==0:
return None
if len(postorder)==1: #只有一个节点时,这棵子树就是它自己,直接完事了
newNode = TreeNode(postorder[-1], None, None)
return newNode
#有多个节点时,就需要先构建出左右子树赋值给它才能往上返回了
rootVal = postorder[-1]
# 构建出当前节点
curRoot = TreeNode(rootVal, None, None)
rootIndex = inorder.index(rootVal)
# 期待着左子树
curRoot.left = self.buildTree(inorder[:rootIndex], postorder[:rootIndex])
# 期待着右子树
curRoot.right = self.buildTree(inorder[rootIndex+1:], postorder[rootIndex:len(postorder)-1])
# 弄好了就返回当前这棵树
return curRoot
动态规划,解题思路看我的这篇博客
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
# 记录最大和
max_sum = nums[0] #边界就是0号元素
# 直接用一个变量记录一下前边算出来的值,因为每个位置上只和前一个元素有关,省去dp数组
dp_cur = nums[0] #0号元素没法往前扩,只有一种选择,就是它自己就是累加和
for i in range(1, len(nums)):
dp_cur = max(dp_cur+nums[i], nums[i]) #”前边算出来的dp值+自身值“和”自身值“比大小
max_sum = max(max_sum, dp_cur)
return max_sum
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
# 1、dp[i]:以i为结尾的最长子序列长度
# 2、递推公式:dp[i] = dp[j]+1 (if nums[i]>nums[j])
# 3、初始化:dp[0]=1
# 4、遍历顺序:从小到大
# 5、确定返回值
dp = [1] * len(nums)
maxLen = 1
for i in range(1, len(nums)): # 以i结尾的情况
# 下边的for循环,为了找到最优的dp[i]
for j in range(0, i): # 查看i前边的每个j长度情况
if nums[i]>nums[j]:
dp[i] = max(dp[i], dp[j]+1)
# 在dp[i]中还要找到最优的那个
maxLen = max(maxLen, dp[i])
return maxLen
类似的题目可以查看【1】简单题合集中的674题目
class Solution:
def findLength(self, nums1: List[int], nums2: List[int]) -> int:
maxLen = 0
# 因为当前dp值要基于上一个dp来算,而边界是0处
# 所以多弄出来一行一列进行了扩充,作为边界即初始值
row, col = len(nums1)+1, len(nums2)+1
dp = [[0]*col for i in range(row)] # 创建二维dp数组,
# dp数组从下标为1的位置开始填值,我们的视角在dp身上
for i in range(1, len(nums1)+1):
for j in range(1, len(nums2)+1):
if nums1[i-1] == nums2[j-1]: #dp视角对应的num数组下标应该是减1的
dp[i][j] = dp[i-1][j-1]+1 #修改当前dp[i][j]的值
maxLen = max(maxLen, dp[i][j])
return maxLen
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
maxLen = 0
row,col = len(text1)+1, len(text2)+1
dp = [[0]*col for i in range(row)]
for i in range(1, row):
for j in range(1, col):
if text1[i-1]==text2[j-1]:
dp[i][j] = dp[i-1][j-1]+1
else: #即使不相等,dp状态也要被更新
# 那A序列就刨掉最后一个数好了,去和当前B序列求最长公共子序列长度
# 那B序列也刨掉最后一个数试试,去和当前A序列求最长公共子序列长度
# 选择他俩舍弃后更优的那个结果
dp[i][j] = max(dp[i][j-1], dp[i-1][j])
maxLen = max(maxLen, dp[i][j])
return maxLen
读懂题目后,和上个题(最长公共子序列)代码完全一样
class Solution:
def maxUncrossedLines(self, nums1: List[int], nums2: List[int]) -> int:
maxLen = 0
row = len(nums1)+1
col = len(nums2)+1
dp = [[0]*col for i in range(row)]
for i in range(1, row):
for j in range(1, col):
if nums1[i-1]==nums2[j-1]:
dp[i][j] = dp[i-1][j-1]+1
else:
dp[i][j] = max(dp[i][j-1], dp[i-1][j])
maxLen = max(maxLen, dp[i][j])
return maxLen
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
row = len(s)+1
col = len(t)+1
dp = [[0]*col for i in range(row)]
for i in range(1, row):
for j in range(1, col):
if s[i-1]==t[j-1]:
dp[i][j] = dp[i-1][j-1]+1
else:
dp[i][j] = dp[i][j-1] # s是不会退步的,没有i-1的那个情况
if dp[-1][-1]==len(s):
return True
else:
return False
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
# 求最长公共子序列的长度,两个字符串的长度分别减去公共长度,就是最小步数和
row = len(word1)+1
col = len(word2)+1
dp = [[0]*col for i in range(row)]
maxLen = 0
minStep = 0
for i in range(1, row):
for j in range(1, col):
if word1[i-1]==word2[j-1]:
dp[i][j] = dp[i-1][j-1]+1
else:
dp[i][j] = max(dp[i][j-1], dp[i-1][j])
maxLen = max(maxLen, dp[i][j])
minStep = len(word1)-maxLen+len(word2)-maxLen
return minStep
持续更新中……