1、最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
#
class Solution:
def longestCommonPrefix(self, strs: list[str]) -> str:
constr = strs[0]
if constr == '':
return ''
for i in range(1,len(strs)):
if strs[i] == '':
return ''
if len(constr) > len(strs[i]):
constr = constr[:len(strs[i])]
else:
strs[i] = strs[i][:len(constr)]
j = len(constr)-1
while j>=0:
if strs[i][j] != constr[j]:
constr = constr[:j]
j -= 1
if len(constr) <= 0:
return ''
return constr
if __name__ == '__main__':
strs = ["flower","flow","flight"]
solu = Solution()
print(solu.longestCommonPrefix(strs))
#动态规划类问题,此题从尾部开始
2、删除链表中的节点
请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。
题目数据保证需要删除的节点 不是末尾节点 。
示例 1:
输入:head = [4,5,1,9], node = 5
输出:[4,1,9]
解释:指定链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9
示例 2:
输入:head = [4,5,1,9], node = 1
输出:[4,5,9]
解释:指定链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9
示例 3:
输入:head = [1,2,3,4], node = 3
输出:[1,2,4]
示例 4:
输入:head = [0,1], node = 0
输出:[1]
示例 5:
输入:head = [-3,5,-99], node = -3
输出:[5,-99]
#其实实际上就是利用后面节点覆盖前一节点的思想
class Solution:
def deleteNode(self, node):
node.val = node.next.val
node.next = node.next.next
3、两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
#
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
Res = p = ListNode(0) # Res和p当前都指在表头
temp = 0 # temp用于进位,初始为0,表示无进位,为1,则进一位
while l1 or l2: # 判断l1和l2是否为空,不为空,则继续
# 将l1 和l2表长改成一样长,空的地方用0补充
if not l1: # 此时l1空,l2不空,则将l1增加一位,值为0
l1 = ListNode(0)
if not l2: # 此时l2空,l1不空,则将l2增加一位,值为0
l2 = ListNode(0)
sum = l1.val + l2.val + temp # sum表示当前节点下l1,l2,和进位值相加的结果 <10则不进位,temp置零,p链表下一节点值就是sum;>10则进位,temp置1,p链表下一节点值就是sum%10
# print(sum)
if (sum < 10):
temp = 0
p.next = ListNode(sum)
else:
temp = 1
p.next = ListNode(sum % 10)
# 当前节点运算结束,前往下一节点
p = p.next
l1 = l1.next
l2 = l2.next
if (temp): # 判断最后一次运算有无进位,有进位,则p再加一位节点,置1
p.next = ListNode(temp)
return Res.next
if __name__ == '__main__':
l1 = [2,4,3]
l2 = [5,6,4]
solu = Solution()
print(solu.addTwoNumbers(l1,l2))
4、重复的子字符串
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。
示例 2:
输入: s = "aba"
输出: false
示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)
#方法一:
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
return s in (s+s)[1:-1]
#方法二:KMP
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
next = [-1] * n
for i in range(1,n):
j = next[i-1]
while j >= 0 and s[j+1] != s[i]:
j = next[j]
if s[j+1] == s[i]:
next[i] = j + 1
return next[-1] >= 0 and n % (n - 1 - next[-1]) == 0
#对于一个重复的字符串,譬如a b a b a b a b a b
#他的next数组是(我这个next数组存的是数组的元素的index)-1 -1 0 1 2 3 4 5 6 7
#观察到,除了第一个子字符串,其他子字符串的的next数组是连续的,n为长度减去next[-1] + 1就是一个##子字符串的长度n % 以上 == 0, 即成功验证
5、合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
#
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
temp = 0
if list1 == "" and list2 == "":
return None
elif list1 == "":
return list2
elif list2 == "":
return list1
else:
new_list: list[int] = []
if list1.val <= list2.val:
new_list.append(list1.val)
temp = list1
temp.next = list1.next
return temp
else:
new_list.append(list2.val)
temp = list2
temp.next = list2.next
return temp
6、二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
new_num = max(self.maxDepth(root.left), self.maxDepth(root.right))
return new_num + 1