2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
num_l1=num_l2=0
# l1_p,l2_p=l1,l2,题解中定义了新变量代替l1、l2,实际如果不需要保留输入量的话,可以直接使用输入量
mult=1 #定义十进制数位变量
'''
将链表中的data提出,累加为十进制数
'''
while l1:
num_l1+=l1.val*mult
mult*=10
l1=l1.next
mult=1
while l2:
num_l2+=l2.val*mult
mult*=10
l2=l2.next
num=num_l1+num_l2 #两数相加
head=ListNode() #哨兵节点,头节点为链表第一个节点,
probe=head
if num==0: #返回head,head中的data为空
return head
while num>0: #通过probe将head后面节点的所有data换为num中的数字
probe.next=ListNode(num%10)
probe=probe.next
num //=10
return head.next #哨兵节点的下一个节点为头节点

学习了链表的定义和用法,代码思路基本是照抄题解

3. 无重复字符的最长子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

中等难度题,第一种方法是刚学习时的简单想法,时间复杂度到了n3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
c=''
n=0
i=0
while i<len(s):
if s[i] not in c: #没有重复的话,将字符加到字串c中
c+=s[i]
else: #出现重复,定位到重复字符的下一位,重新开始便利
n=max(n,len(c))
i+=c.find(s[i])-len(c)+1
c=s[i]
i+=1
n=max(n,len(c))
return n

学习数据结构后使用的两种新方法,实际上动态规划和第一种相同

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
#动态规划
if not s: return 0
dp, res = '', 0
for item in s:
if item not in dp: dp += item
else:
if dp[-1] == item: dp = item
else: dp = dp[dp.find(item)+1:] + item
res = max(res, len(dp))
return res
1
2
3
4
5
6
7
8
9
10
11
12
13
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
#双指针,滑动窗口
if not s: return 0
res, dic = 1, {}
i, j = -1, 0
while j < len(s):
if s[j] in dic:
i = max(i,dic[s[j]])
dic[s[j]] = j
res = max(j-i, res)
j += 1
return res

8. 字符串转换整数 (atoi)

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1
  6. 返回整数作为最终结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution:
def myAtoi(self, str: str) -> int:
str = str.lstrip()
if not str: return 0 #字符串为空返回0
#定义两个判断函数
flag1, flag2 = False, False
if str[0] == '+': flag1, flag2 = True, False
if str[0] == '-': flag1, flag2 = True, True
#字符串首位不为+-和数字时,或者字符串只有一位+-时,返回0
if flag1:
if len(str) == 1 or not str[1].isdigit():
return 0
else:
if not str[0].isdigit():
return 0
i = 1
while i < len(str):
if not str[i].isdigit():
break
i += 1
num = int(str[0:i]) if not flag1 else int(str[1:i])
if flag2: num = -num
if num < -2 ** 31:
num = -2 ** 31
elif num >= 2 ** 31:
num = 2 ** 31 - 1
return num

34. 在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

1
2
3
4
5
6
7
#二分法
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
a = bisect_left(nums,target)
b = bisect_right(nums,target)
if a == b: return [-1,-1]
else: return [a,b-1]

50. Pow(x, n)

实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x^n)。

1
2
3
4
5
6
7
8
9
10
class Solution:
def myPow(self, x: float, n: int) -> float:
if x == 0: return 0
if n < 0: x, n = 1/x, -n #转化为正幂讨论
res = 1
while n:
if n & 1: res *= x #如果n二进制位为1,乘上x
x *= x #x=x^2
n >>= 1 #n右移一位
return res

53. 最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

1
2
3
4
5
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
for i in range(1,len(nums)):
nums[i] += max(nums[i-1], 0)
return max(nums)

79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
def dfs(i,j,k):
#i,j越界或者board[i][j]和目标值不符时,返回False
if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False
if k == len(word) - 1: return True #word在board中,返回True
#当board[i][j]等于word[k]时,将该处值改为空,避免重复遍历
board[i][j] = ''
#以下、上、右、左的顺序递归,查看临近格是否存在word[k+1]
res = dfs(i+1,j,k+1) or dfs(i-1,j,k+1) or dfs(i,j+1,k+1) or dfs(i,j-1,k+1)
#递归回溯后,将值还原
board[i][j] = word[k]
return res

for i in range(len(board)):
for j in range(len(board[0])):
if dfs(i,j,0): return True
return False

105. 从前序与中序遍历序列构造二叉树

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
#将二叉树分为左子树、根、右子树,再去考虑左右子树,即将大问题拆解为小问题,分治思想。
def recur(root,left,right):
if left > right: return
node = TreeNode(preorder[root])
i = dic[preorder[root]]
node.left = recur(root+1, left, i-1)
node.right = recur(root+1+i-left, i+1, right)
return node

dic = {}
for i in range(len(inorder)):
dic[inorder[i]] = i #哈希表映射,将值映射为对应索引
return recur(0, 0, len(inorder)-1)

113. 路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 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 pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
path, res = [], []
def dfs(root,target):
if not root: return #终止递归
path.append(root.val)
target -= root.val
if target == 0 and not root.left and not root.right: #符合累加值且为叶节点时,记录路径
res.append(list(path)) #不能直接把对象path加到res中,否则res结果会随path改变
dfs(root.left,target)
dfs(root.right,target)
path.pop() #回溯时删除该路径
dfs(root,targetSum)
return res

151. 反转字符串中的单词

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

**注意:**输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

1
2
3
class Solution:
def reverseWords(self, s: str) -> str:
return ' '.join(s.split()[::-1])

155. 最小栈

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MinStack:
def __init__(self):
self.lst = []
self.lst2 = []
def push(self, val: int) -> None:
self.lst.append(val)
if not self.lst2 or val <= self.lst2[-1]:
self.lst2.append(val)
def pop(self) -> None:
popval = self.lst.pop()
if self.lst2[-1] == popval:
self.lst2.pop()
def top(self) -> int:
return self.lst[-1]
def getMin(self) -> int:
return self.lst2[-1]

240. 搜索二维矩阵 II

编写一个高效的算法来搜索 *m* x *n* 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。
1
2
3
4
5
6
7
8
9
#贪心算法
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
i, j = len(matrix) - 1, 0 #要确保相邻格子的元素性质不一样,所以选左下或者右上
while 0 <= i < len(matrix) and 0 <= j < len(matrix[0]):
if matrix[i][j] > target: i -= 1
elif matrix[i][j] < target: j += 1
else: return True
return False

264. 丑数 II

给你一个整数 n ,请你找出并返回第 n丑数

丑数 就是质因子只包含 235 的正整数。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def nthUglyNumber(self, n: int) -> int:
#动态规划+三指针
f = [1] * n
a = b = c = 0
for i in range(1,n):
n2, n3, n5 = 2 * f[a], 3 * f[b], 5 * f[c]
f[i] = min(n2, n3, n5)
if f[i] == n2: a += 1
if f[i] == n3: b += 1
if f[i] == n5: c += 1
return f[-1]

343. 整数拆分

给定一个正整数 n ,将其拆分为 k正整数 的和( k >= 2 ),并使这些整数的乘积最大化。

返回 你可以获得的最大乘积

1
2
3
4
5
6
7
8
class Solution:
def integerBreak(self, n: int) -> int:
if n < 4: return n-1
x = n // 3
y = n % 3
if y == 0: return 3**x
elif y == 1: return 3**(x-1)*4
else: return 3**x*2

400. 第 N 位数字

给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] 中找出并返回第 n 位上的数字。

1
2
3
4
5
6
7
8
9
10
class Solution:
def findNthDigit(self, n: int) -> int:
res, k, nine = 0, 0, 0.9
while res < n: #找出n是在k位数中
nine *= 10
k += 1
res += nine * k
x, y = (int(res) - n) // k, (int(res) - n) % k #第k位数最大者中反推n
pur = 10**k - 1 - x
return int(str(pur)[-1-y])

647. 回文子串

给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。

回文字符串 是正着读和倒过来读一样的字符串。

子字符串 是字符串中的由连续字符组成的一个序列。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

1
2
3
4
5
6
7
8
9
10
11
12
#中心拓展法
class Solution:
def countSubstrings(self, s: str) -> int:
res = 0
n = len(s)
for k in range(2*n-1):
l, r = k//2, k//2 + k%2
while l>=0 and r<=n-1 and s[l] == s[r]:
res += 1
l -= 1
r += 1
return res