前言
继续leetcode刷题生涯
这里记录的都是笔者觉得有点意思的做法
参考了好几位大佬的题解,尤其是powcai大佬和labuladong大佬,感谢各位大佬
401. 二进制手表
# 数下1
class Solution:
def readBinaryWatch(self, num: int) -> List[str]:
res = []
for h in range(12):
for m in range(60):
if bin(h).count("1") + bin(m).count("1") == num:
res.append("{}:{:02d}".format(h, m))
return res
402. 移掉K位数字
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
l = len(num)
if l == k: return "0"
# 维护一个单调增的队列
stack = []
cnt = k
for n in num:
while stack and stack[-1] > n and k:
stack.pop()
k -= 1
stack.append(n)
return str(int("".join(stack[:l - cnt])))
403. 青蛙过河
# 动态规划
class Solution:
def canCross(self, stones: List[int]) -> bool:
n = len(stones)
dp = [[False] * n for _ in range(n)]
dp[0][1] = True
for i in range(1, n):
for j in range(i):
distance = stones[i] - stones[j]
if distance < 0 or distance >= n or not dp[j][distance]:
continue
dp[i][distance] = True
if distance - 1 >= 0: dp[i][distance - 1] = True
if distance + 1 < n: dp[i][distance + 1] = True
return any(dp[-1])
# 记忆+回溯
class Solution:
def canCross(self, stones: List[int]) -> bool:
from functools import lru_cache
end = stones[-1]
s = set(stones)
@lru_cache(None)
def helper(start, jump):
# 结束标志
if start == end:
return True
# 对应3种跳法
for j in [jump - 1, jump, jump + 1]:
if j <= 0: continue
if start + j in s and helper(start + j, j):
return True
return False
return helper(0, 0)
404. 左叶子之和
class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
self.res = 0
def helper(root):
if not root: return 0
if root.left and not root.left.left and not root.left.right:
self.res += root.left.val
helper(root.left)
helper(root.right)
tmp = root
helper(tmp)
return self.res
405. 数字转换为十六进制数
# 位运算
class Solution:
def toHex(self, num: int) -> str:
num &= 0xFFFFFFFF
s = "0123456789abcdef"
res = ""
mask = 0b1111
while num > 0:
res += s[num & mask]
num >>= 4
return res[::-1] if res else "0"
# 分类
class Solution:
def toHex(self, num: int) -> str:
if num == 0: return '0'
res = ''
if num < 0:
num = (abs(num) ^ ((2 ** 32) - 1)) + 1
while (num >> 4) > 0 or num > 0:
a = str(num % 16)
if a == '10':
a = 'a'
elif a == '11':
a = 'b'
elif a == '12':
a = 'c'
elif a == '13':
a = 'd'
elif a == '14':
a = 'e'
elif a == '15':
a = 'f'
res += a
num = num >> 4
return ''.join(reversed(res))
406. 根据身高重建队列
# 先排序再插队
class Solution:
def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
people.sort(key=lambda x: (-x[0], x[1]))
res = []
for p in people:
res.insert(p[1], p)
return res
407. 接雨水 II
# 从最外围开始
class Solution:
def trapRainWater(self, heightMap: List[List[int]]) -> int:
import heapq
row, col = len(heightMap), len(heightMap[0])
hp = []
visited = [[False for _ in range(col)] for _ in range(row)]
# 最外围围栏入堆
for i in range(row):
for j in range(col):
if i == 0 or j == 0 or i == row - 1 or j == col - 1:
# 最小堆,保证最矮的围栏出堆
heapq.heappush(hp, (heightMap[i][j], i, j))
visited[i][j] = True
res = 0
while hp:
h, r, c = heapq.heappop(hp)
for nr, nc in ((r + 1, c), (r - 1, c), (r, c + 1), (r, c - 1)):
if 0 <= nr < row and 0 <= nc < col and not visited[nr][nc]:
# 围栏比内部高,可以灌水
if h > heightMap[nr][nc]:
res += h - heightMap[nr][nc]
# 忽略当前围栏,在(nr, nc)处新建围栏
visited[nr][nc] = True
# 新的围栏入堆
heapq.heappush(hp, (max(h, heightMap[nr][nc]), nr, nc))
return res
409. 最长回文串
class Solution:
def longestPalindrome(self, s: str) -> int:
import string
flag = 0
res = 0
for a in string.ascii_letters:
num = s.count(a)
if num % 2 == 0:
res += num
else:
flag = 1
res += num - 1
return res + flag
410. 分割数组的最大值
# 二分
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
left = max(nums)
right = sum(nums)
while left < right:
mid = (left + right) // 2
sums, cnt = 0, 1
for i in nums:
if sums + i > mid:
cnt += 1
sums = i
else:
sums += i
if cnt <= m:
right = mid
else:
left = mid + 1
return left