简单题不会再开单独的博客了,统一在这里做笔记。
258. 各位相加
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。
示例:
输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。
class Solution:
def addDigits(self, num: int) -> int:
n = num
while n >= 10:
res = 0
while n:
res += n % 10
n = n // 10
n = res
if res < 10:
return res
return n
O(1)的解法
226.翻转二叉树
翻转一棵二叉树。
示例:
输入:
4
/ \
2 7
/ \ / \
1 3 6 9
输出:
4
/ \
7 2
/ \ / \
9 6 3 1
核心思路是交换所有节点的左右节点
- 写法1
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
def walk(p):
if p:
p.left, p.right = p.right, p.left
walk(p.left)
walk(p.right)
walk(root)
return root
- 写法2
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
return root
237. 删除链表的节点
乍一看题目很简单,不过有点小心思在里面,没有给Head。
方法很简单,
290. 单词规律
这题和 205.同构字符串本质上是一样的。
给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。
示例1:
输入: pattern = “abba”, str = “dog cat cat dog”
输出: true
- 解法一,代码写的有点丑,应该写一个函数来处理,不需要重复两次写。
class Solution:
def wordPattern(self, pattern: str, str: str) -> bool:
recoder = {}
flag = False
max_len = len(pattern)
if max_len != len(str.split(' ')):
print(1)
return False
for word, p in zip(str.split(' '), pattern):
if p not in recoder:
recoder[p] = word
else:
if recoder[p] != word:
return flag
flag = True
flag2 = False
recoder = {}
for word, p in zip(str.split(' '), pattern):
if word not in recoder:
recoder[word] = p
else:
if recoder[word] != p:
return flag2
flag2 = True
if flag2 and flag:
return True
else:
return False
- 解法二, 将两个字符串按照相同的映射规则,换到另一个字符串上。说法语的人和中国人,如何交流,让他们都说英语。
235. 二叉搜索树的最近公共祖先
二叉搜索树定义:
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树(又称,二叉排序树,二叉查找树)。插入,删除,搜索操作时间复杂度均为树高,O(logN)。
- 节点 NN 左子树上的所有节点的值都小于等于节点 NN 的值
- 节点 NN 右子树上的所有节点的值都大于等于节点 NN 的值
- 左子树和右子树也都是 BST
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
def walk(root, p, q):
if not root:
return
if p.val > q.val:
p, q = q, p
if p.val < root.val and q.val > root.val:
return root
if p.val == root.val or q.val == root.val:
return root
if p.val > root.val and q.val > root.val:
return walk(root.right, p, q)
if p.val < root.val and q.val < root.val:
return walk(root.left, p, q)
return walk(root, p, q)
更简洁的写法
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root:
return None
# 由于二叉搜索树排好序,则按条件左右循环游走
while root:
if p.val < root.val > q.val:
root = root.left
elif p.val > root.val < q.val:
root = root.right
else:
return root
257. 二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入:
1
/ \
2 3
\
5
输出: [“1->2->5”, “1->3”]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
这道题我还是想了很久的,想错方向了,没做出来。就去看了题解,看了思路一下就知道我的问题在哪了。
首先,我想的是,深度遍历,但是具体又该如何把路径存下来呢。其实这个问题很好解决,但我没想到,就是多设置一个形参,按照由顶到底的顺序保存走过的路径就行了。到叶子节点就把路径添加到全局变量中去。
- 递归写法
from collections import deque
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
self.paths = []
def walk(root, path):
if not root.right and not root.left:
self.paths.append(path+str(root.val))
return
if root.left or root.right:
path += str(root.val)+'->'
if root.left:
walk(root.left, path)
if root.right:
walk(root.right, path)
if not root:
return []
walk(root, '')
return self.paths
关键就是这个path形参记录了根节点到父节点的路径。
- 迭代写法,用队列或者栈都OK,关键是path传递的信息。
from collections import deque
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
if not root:
return []
paths = []
queue = deque([(root, str(root.val))])
while len(queue) != 0:
node, path = queue.popleft()
if node.right == None and node.left == None:
paths.append(path)
if node.left:
pathl = path + '->' + str(node.left.val)
queue.append((node.left, pathl))
if node.right:
pathr = path + '->' + str(node.right.val)
queue.append((node.right, pathr))
return paths
437. 路径总和 |||
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
思路:
- 用数组记录走过路径的前缀和,(又是前缀和,之前有道动态规划的题目用到了前缀和)。如果最后一个数字和前面的数的差就是sum,那就找到一条路径了。
- 回溯遍历,先序遍历。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> int:
path_sum = [0]
cnt = 0
if not root:
return cnt
def walk(p):
nonlocal path_sum, cnt
if not p:
return
pre_sum = path_sum[-1]
path_sum.append(p.val+pre_sum)
# print(path_sum)
for k in range(len(path_sum)-1):
if path_sum[k] + sum == path_sum[-1]:
cnt += 1
if p.left:
walk(p.left)
path_sum.pop()
if p.right:
walk(p.right)
path_sum.pop()
walk(root)
return cnt
459. 重复的子字符串
给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
- 思路: 维护一个repeat字符串,记录目前最大的不满足条件的从第一个字符到当前遍历的字符之间的所有字符串。
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
repeat = s[0]
for i in range(1, len(s)):
k = i
while s[k:k+len(repeat)] == repeat:
if k+len(repeat) == len(s):
return True
k += len(repeat)
if k+len(repeat) > len(s):
print(1)
break
repeat = repeat+s[i]
if len(repeat) > 0.5 * len(s):
return False
return False
162. 寻找峰值
峰值元素是指其值大于左右相邻值的元素。
给定一个输入数组 nums,其中 nums[i] ≠ nums[i+1],找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可
算法要求在logn时间内求解。二分没跑了
开始思考条件:当一个位置大于后一个位置,说明这个位置处在下降区域上
class Solution:
def findPeakElement(self, nums):
n = len(nums)
nn = sorted(nums)
i = 0
j = n-1
mid = 0
if n == 1:
return 0
if n > 1:
if nums[0] > nums[1]:
return 0
elif nums[-1] > nums[-2]:
return n - 1
while i < j:
mid = (i + j) >> 1
if nums[mid-1] < nums[mid] > nums[mid+1]:
break
elif nums[mid] > nums[mid+1]: # 处于下降位置
j = mid
else:
i = mid +1
return mid
注意,这里的条件,最好用mid位置的值是否大于mid+1, 如果用mid-1和mid的比较,也许会陷入死循环。
650. 只有两个键的键盘
本质是素数分解,分解的数子全部都是素数,然后这些数字的和就是答案。原因是当p,q都大于等于2时, q + p是小于p * q的。
class Solution:
def minSteps(self, n: int) -> int:
d = 2 # 质数从小到大开始加
ans = 0
while n > 1:
while n % d ==0: # 用while, 把d的因子全部去掉,比如当d为4的时候,
#4不会是n的因子,因为d为2的时候,已经去除了2的倍数的因子
ans += d
n //= d
d += 1
return ans
11. 盛最多水的容器
题目是给一个list,装了值代表高度。哪两个index位置的高度能组成的面积最大
- 双指针思想。i指向第一个位置,j指向最后一个位置。
- 计算一次面积,同时如果第i的值比第j的位置的值小,则i+1;否则j-1
class Solution:
def maxArea(self, height: List[int]) -> int:
i, j = 0, len(height) - 1
res = 0
while i < j:
temp = (j-i) * min(height[i], height[j])
res = max(temp, res)
if height[i] > height[j]:
j -= 1
else:
i += 1
return res