题002
题意
给定两个非空链表,分别表示两个非负整数,每位数字按逆序存储,每个节点表示一位数字。将两个链表表示的数相加,并以同样的方式输出。
eg.
输入: l1 = [2,4,3], l2 = [5,6,4]
输出: [7,0,8]
解释: 342 + 465 = 807.
示意图
提示
- 每个链表中的节点数在范围
[1, 100]
内 0 <= Node.val <= 9
- 题目数据保证列表表示的数字不含前导零
解题思路
- 因为链表的第一位是个位,以此类推,所以将两个链表从第一位开始相加,和除以十,判断进位(tmp),余数留下。
- 具体的操作有两种方法:
- 法一:
- 将更长的那个链表(假设是l1)作为返回的链表,将和的值加到l1上
- 创造一个递归函数,根据不同的条件进行操作,具体的判断如下方流程图所示(节点的值相加完成后)
- 法二:
- 创建新的链表,每一位计算后赋值到当前node并建立新的node
- 将l1,l2和进位值三者作为while循环的条件,当l1和l2中的任一个不存在时,赋值为None,计算时加零
- 当不再存在进位或者链表遍历结束时,输出结果。
代码
法一
class Solution:
def addTwoNumbers(self,l1:ListNode,l2:ListNode)->ListNode:
def sum(l1,l2,tmp):
tmp+=l1.val+l2.val
l1.val=tmp%10 #将余数赋值到当前节点
tmp//=10 #tmp整除10后得到进位值
if l1.next and l2.next:
return sum(l1.next,l2.next,tmp)
if l2.next:#如果l2更长,l1,l2互换
l1.next=l2.next
while l1.next and tmp:
l1=l1.next
tmp+=l1.val
l1.val=tmp%10
tmp//=10
if tmp:
l1.next=ListNode(1)
sum(l1,l2,0)
return l1
法二
class Solution:
def addTwoNumbers(self,l1:ListNode,l2:ListNode)->ListNode:
cur=head=ListNode(None)
tmp=0
while l1 or l2 or tmp:
tmp+=(l1.val if l1 else 0)+(l2.val if l2 else 0)
cur.next=ListNode(tmp%10)#创建新节点
tmp//=10
cur=cur.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
return head.next
题004
题意
给定两个大小为m和n的正序数组nums1和nums2,请找出这两个数组合并后的中位数。
要求:时间复杂度控制在O(log(m+n))
eg
输入: nums1 = [1,3], nums2 = [2]
输出: 2.00000
解释: 合并数组 = [1,2,3] ,中位数 2
输入: nums1 = [1,2], nums2 = [3,4]
输出: 2.50000
解释: 合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示
- nums1.length == m
- nums2.length == n
- 0 <= m <= 1000
- 0 <= n <= 1000
- 1 <= m + n <= 2000
- -106 <= nums1[i], nums2[i] <= 106
解题思路
题意要求时间复杂度控制在O(log(m+n)),如果我们用第一反应将两个数组合并后排序,那么时间复杂度将达到O(m+n),所以参考了各种题解后,我觉得寻找第k小的数这种方法比较值得学习,而且这个方法适用性范围比较广。
题目中为两个正序数组,要找中位数,利用题解中讲到的寻找第k个数的方法,就是删除前二分之一的数。
做法是每次循环,删除前一般的数的前面一半,也就是对于前一半的数,每次保留后1/2, 这样最后只剩下了一个数,即中位数。
具体的做法:
- 每次删除完后,两个数组的长度会变化,为了方便操作,每次删除后确保nums1比nums2长
- 删除范围t的大小视具体情况而定,取较短数组的长度和k/2中更小的一个:
t=min(k//2,len(l2))]
- 对于k个数的中位数
- 若k=2m+1,中位数为第m+1个
- 若k=2m,中位数为第m和m+1个的平均值
- 所以求k个数中第(k+1)//2和第k//2+1个数,再取平均数
- 若k=2m+1,取到的是第m+1个和第m+1个
- 若k=2m,取到的是第m个和第m+1个
代码
def findMedianSortedArrays(self, nums1: List\[int\], nums2: List\[int\]) -> float:
def findk(l1,l2,k):
if len(l1)<len(l2):
l1,l2=l2,l1
if len(l2)==0:
return l1[k-1]
if k==1:
return min(l1[0],l2[0])
t=min(k//2,len(l2))#确定删除范围的大小
if l1[t-1]<l2[t-1]:
return findk(l1[t:],l2,k-t)
else:
return findk(l1,l2[t:],k-t)
#取两个数然后求平均值
k1=(len(nums1)+len(nums2)+1)//2
k2=(len(nums1)+len(nums2)+2)//2
return (findk(nums1,nums2,k1)+findk(nums1,nums2,k2))/2
题005
题意
给定一个字符串,找出其中的最长的回文子串。
eg.
输入: s = “babad”
输出: “bab”
解释: “aba” 同样是符合题意的答案。
解题思路
- 还是采取遍历的方式,从头开始,寻找最长的回文子串
- 考虑到回文字符串的格式
- 如果长度为奇数,那么中心为一个字符
- 如果长度为偶数,那中心是两个相同的字符
- 所以遍历时,以当前节点为中心,分两种情况(偶数节点和奇数节点)向外扩张,寻找最长的回文子串
def expand(s,l,i,j):
while i>=0 and j<l and s[i]=s[j]:
i-=1
j+=1
return s[i+1:j],j-1-1
- 每个节点搜寻完成后和当前最长子串的长度进行比较,保留更长的
代码
class Solution:
def longestPalindrome(self, s:str)->str:
#定义一个扩展字符串的函数
def expand(s,l,i,j):
while i>=0 and j<l and s[i]==s[j]:
i-=1
j+=1
return s[i+1:j],j-i-1
l=len(s)
if l<2:
return s
maxl=1
res=s[0]#以防没有回文子串
for i in range(l):
s1,l1=expand(s,l,i,i)
s2,l2=expand(s,l,i,i+1)
cur=s1 if l1>l2 else s2
if len(cur)>maxl:#若发现了更大的回文子串
maxl=len(cur)
res=cur
return res