LeetCode每日一题8月记录
- 8.1 最小区间
- 8.2 二叉树展开为链表
- 8.3字符串相加
- 8.4 课程表
- 8.5 打家劫舍Ⅲ
- 8.6 回文对
- 8.7 相同的树
- 8.8 恢复二叉搜索树
- 8.9 复原ip地址
- 8.10 计数二进制字串
- 8.11 被围绕的区域
- 8.12克隆图
- 8.13字符串相乘
- 8.14 有效的括号
- 8.15 移除盒子
- 8.16 图像渲染
- 8.17平衡二叉树
- 8.18有序链表转换二叉搜索树
- 8.19回文子串
- 8.20 扫雷游戏
- 8.21 二叉树的最小深度
- 8.22 24点游戏
- 8.23 数字范围按位与
- 8.24 重复的子字符串
- 8.25 递增子序列
- 8.26电话号码的字母组合
- 8.27 重新安排行程
- 8.28 机器人能否返回原点
- 8.29 最短回文串
- 8.30 反转字符串中的单词
- 8.31 钥匙和房间
8.1 最小区间
原题地址.
变相的用滑动窗口法求解,统计每个数字出现在输入的哪几个数组里面,然后利用双指针滑动窗口寻找最小的左右边界,使得全部数组都有这些元素。
class Solution:
def smallestRange(self, nums: List[List[int]]) -> List[int]:
n = len(nums)
indices = collections.defaultdict(list)
xMin, xMax = 10**9, -10**9
for i, vec in enumerate(nums):
for x in vec:
indices[x].append(i)
xMin = min(xMin, *vec)
xMax = max(xMax, *vec)
freq = [0] * n
inside = 0
left, right = xMin, xMin - 1
bestLeft, bestRight = xMin, xMax
while right < xMax:
right += 1
if right in indices:
#新加入统计右边界元素出现的list
for x in indices[right]:
freq[x] += 1
#首次出现计数
if freq[x] == 1:
inside += 1
while inside == n:
if right - left < bestRight - bestLeft:
bestLeft, bestRight = left, right
if left in indices:
for x in indices[left]:
freq[x] -= 1
#减到0推出窗口
if freq[x] == 0:
inside -= 1
left += 1
return [bestLeft, bestRight]
8.2 二叉树展开为链表
原题地址.
递归处理,每次把左子树交换到右子树,把原来的右子树摘出来挂到左子树的最右儿子上,再处理下一层树。
class Solution:
def flatten(self, root: TreeNode) -> None:
if not root:
return
temp = root.right
root.right = root.left
root.left = None
curr = root
while curr.right:
curr = curr.right
curr.right = temp
if root.right:
self.flatten(root.right)
return
8.3字符串相加
原题地址.
模拟实际加法,从右到左相加进位。
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
res = ""
i, j, carry = len(num1) - 1, len(num2) - 1, 0
while i >= 0 or j >= 0 or carry:
n1 = int(num1[i]) if i >= 0 else 0
n2 = int(num2[j]) if j >= 0 else 0
tmp = n1 + n2 + carry
carry = tmp // 10
res = str(tmp % 10) + res
i, j = i - 1, j - 1
return res
8.4 课程表
原题地址.
先统计好每个课程的依赖关系,再依次消去没有以来的课程,看最后剩余与否。
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
indegrees = [0 for _ in range(numCourses)]
adjacency = [[] for _ in range(numCourses)]
queue = []
# 统计每个课程的出入度信息
for cur, pre in prerequisites:
indegrees[cur] += 1
adjacency[pre].append(cur)
#队列初始
for i in range(len(indegrees)):
if not indegrees[i]: queue.append(i)
while queue:
pre = queue.pop()
numCourses -= 1
#消去课程时,处理对应的依赖
for cur in adjacency[pre]:
indegrees[cur] -= 1
if not indegrees[cur]: queue.append(cur)
return not numCourses
8.5 打家劫舍Ⅲ
原题地址.
采用递归求解
class Solution:
def dp(self , cur : TreeNode) -> List[int] :
#返回数组[不打劫当前根节点的最大收益,打劫根节点的最大收益]
if not cur :
return [0,0]
l = self.dp(cur.left)
r = self.dp(cur.right)
#注意返回值的第一项,不打劫cur的话,l和r的选择就是自由的,可以选择俩者最大值
return [max(l)+max(r),cur.val+l[0]+r[0]]
def rob(self, root: TreeNode) -> int:
return max(self.dp(root))
8.6 回文对
原题地址.
利用hash表减少枚举操作,使得快速查找有无对应字符串。
class Solution:
def palindromePairs(self, words: List[str]) -> List[List[int]]:
def findWord(s: str, left: int, right: int) -> int:
return indices.get(s[left:right+1], -1)
def isPalindrome(s: str, left: int, right: int) -> bool:
return (sub := s[left:right+1]) == sub[::-1]
n = len(words)
#字符串倒序和index构成的hash表
indices = {
word[::-1]: i for i, word in enumerate(words)}
ret = list()
for i, word in enumerate(words):
m = len(word)
for j in range(m + 1):
#后面是回文,寻找前半段是否存在
if isPalindrome(word, j, m - 1):
leftId = findWord(word, 0, j - 1)
if leftId != -1 and leftId != i:
ret.append([i, leftId])
#前半段回文,搜索后半段是否存在
if j and isPalindrome(word, 0, j - 1):
rightId = findWord(word, j, m - 1