2022年 5月
5月4号
118题 杨辉三角
思路:
每一行的开头和结尾都是1。其他值都是上一行上一列和上一行当前列的和。
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
yanghui = list()
for i in range(numRows):
row = list()
for j in range(0,i+1):
if j == 0 or j == i:
row.append(1)
else:
row.append(yanghui[i-1][j-1] + yanghui[i-1][j])
yanghui.append(row)
return yanghui
36题 有效的数独
思路:
重点在于判断board[i][j]在第i行,和第j列,还有第int(i/3) int(j/3)个小格子里面是否出现过两次以上。
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
rows = [[0] * 9 for _ in range(9)]
cols = [[0] * 9 for _ in range(9)]
subboxs = [[[0] * 9 for _ in range(3)] for _ in range(3)]
for i in range(9):
for j in range(9):
c = board[i][j]
if c != '.':
c = int(c) - 1
rows[i][c] += 1
cols[j][c] += 1
subboxs[int(i/3)][int(j/3)][c] += 1
if rows[i][c] > 1 or cols[j][c] > 1 or subboxs[int(i/3)][int(j/3)][c] > 1:
return False
return True
5月5号
73 矩阵置零
思路:
将矩阵中值为0的行和列的坐标分别进行标记,存储到两个列表中,然后遍历,进行赋值为0的操作。自己的笨办法
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
row = len(matrix)
col = len(matrix[0])
hang = []
lie = []
for i in range(row):
for j in range(col):
if matrix[i][j] == 0:
hang.append(i)
lie.append(j)
for i in hang:
for j in range(col):
matrix[i][j] = 0
for j in lie:
for i in range(row):
matrix[i][j] = 0
return matrix
144 二叉树前序遍历
自己的写办法
# 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 preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
if root == None:
return ans
def bianli(ans,root):
if root == None:
return ans
ans.append(root.val)
bianli(ans,root.left)
bianli(ans, root.right)
bianli(ans, root)
return ans
94 二叉树的中序遍历
自己的写办法
# 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 inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
if root == None:
return ans
def bianli(ans,root):
if root == None:
return ans
bianli(ans,root.left)
ans.append(root.val)
bianli(ans, root.right)
bianli(ans, root)
return ans
145 二叉树的后续遍历
自己的写办法
# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
ans = []
if root == None:
return ans
def bianli(ans,root):
if root == None:
return ans
bianli(ans,root.left)
bianli(ans, root.right)
ans.append(root.val)
bianli(ans, root)
return ans
5月6日
387 字符串中的第一个唯一字符
思路:
用字典存储每个字符出现的次数,遍历字符串,找出第一个出现一次的字符。
class Solution(object):
def firstUniqChar(self, s):
"""
:type s: str
:rtype: int
"""
frequency = collections.Counter(s)
for i, ch in enumerate(s):
if frequency[ch] == 1:
return i
return -1
102 二叉树的层序遍历
思路:
使用广度优先搜素(BFS)只能得到一维的输出数组,没办法区分每一层的元素。因此需要把每一层的节点遍历完之后再进入下一层开始遍历数据。引入一个队列专门存放节点,每一次迭代都将队列的长度存入一个变量,即为该层的节点数。
# 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 levelOrder(self, root: TreeNode) -> List[List[int]]:
ret = []
if root == None:
return ret
queue = []
queue.append(root)
while len(queue) != 0:
level = []
size = len(queue)
for i in range(1, size +1):
node = queue.pop(0)
level.append(node.val)
if node.left != None:
queue.append(node.left)
if node.right != None:
queue.append(node.right)
ret.append(level)
return ret
5月9日
136 只出现一次的数字
思路:
可以使用哈希表记录每个数字出现的次数。也可以判断第i个数字是否在数组中出现第二次。自己写的方法
class Solution:
def singleNumber(self, nums: List[int]) -> int:
# fre = collections.Counter(nums)
for i in range(len(nums)):
if nums[i] not in nums[i+1:] and nums[i] not in nums[:i]:
return nums[i]
方法二,字典记录数字出现次数
class Solution:
def singleNumber(self, nums: List[int]) -> int:
fre = collections.Counter(nums)
for i in nums:
if fre[i] == 1:
return i
70 爬楼梯
思路:爬到第i层的方法数是爬到第i-1层与i-2层方法数的和,因此用递归的方法求解
class Solution:
def climbStairs(self, n: int) -> int:
if n < 3:
return n
p = 1
q = 2
for i in range(3, n+1):
number = q + p
p = q
q = number
return number
746 使用最小花费爬楼梯
思路:
在第0层、第1层花费为0,当i>2时,爬到第i层的花费是爬到第i-2层的花费加上i-2层的花费或者是爬到i-1层的花费加上i-1层的花费,两者取其最小值即为爬到第i层的最小花费。
注意爬到数组中最后一个层数时并不是到楼顶,而是要再爬上去一层才到楼顶,因此循环中用n+1,创建的数组dp长度也是n+1,也就是说到达数组最后一个数字代表的楼层还没有到楼顶,此时距离楼顶还差一步。
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
n = len(cost)
dp = [0] * (n+1)
for i in range(2, n + 1):
dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i- 1])
return dp[n]
198 打家劫舍
思路
不能连续偷两间靠近的房子,就是第i个房间的最大收益是在第i-2个房间+第i个房间的钱和第i-1个房间的总收益之间取最大值。
class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)
dp = [0] * n
if n < 3:
return max(nums)
dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
for i in range(2, n):
dp[i] = max(dp[i-2] + nums[i], dp[i-1])
return dp[n-1]
5月11号
152 乘积最大子数组
思路:
因为数组中有负数存在,有可能出现负负得正使得乘积最大,所以在考虑正数的同时也要考虑负数。
class Solution:
def maxProduct(self, nums: List[int]) -> int:
n = len(nums)
maxF = [1] * n
minF = [1] * n
maxF[0] = minF[0] = nums[0]
for i in range(1, n):
maxF[i] = max(maxF[i - 1] * nums[i], max(nums[i], minF[i - 1] * nums[i]))
minF[i] = min(minF[i - 1] * nums[i], min(nums[i], maxF[i- 1] * nums[i]))
ans = maxF[0]
for i in range(1, n):
ans = max(ans, maxF[i])
return ans
5月12号
213 打家劫舍Ⅱ
思路:
房屋首尾相连,因此偷了第一间房,最后一间房就不能偷,则此时只考虑前n-1间房屋的最大收益。当偷了最后一间房时,只考虑2~n房子的最大收益,因此两种情况用相同的方法求最大收益后再比较大小得到n间房屋的最大偷窃数。
class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)
dp = [0] * n
dp[0] = nums[0]
if n<3:
return max(nums)
dp[1] = max(nums[0], nums[1])
for i in range(2, n-1):
dp[i] = max(dp[i-2] + nums[i], dp[i - 1])
fp = [0] * n
fp[1] = nums[1]
fp[2] = max(nums[1], nums[2])
for i in range(3, n):
fp[i] = max(fp[i-2] + nums[i], fp[i - 1])
return max(dp[n-2], fp[n-1])
1014 最佳观光组合
思路:
values[ i ] + i +values[ j ] - j 可以拆分成两部分,对于第j个景点,要想找到最佳组合,就是找出
values[ i ] + i的最大值,即 values[ j ] − j在j点是固定的。所以依次遍历j-1个景点来找到j景点以前的最佳组合。
class Solution(object):
def maxScoreSightseeingPair(self, values):
"""
:type values: List[int]
:rtype: int
"""
ans = 0
mx = values[0] + 0
for i in range(1, len(values)):
ans = max(ans, mx + values[i] - i)
mx = max(mx, values[i] + i)
return ans
121 买卖股票的最佳时机
思路:
第i天的收益是在第j天以最低价买入在第j+t天以最高价卖出,其中j < i,
j + t<=i。自己写的方法。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
profit = 0
s = 10000
for i in range(len(prices)):
s = min(s, prices[i])
profit = max(profit, prices[i] - s)
return profit
122 买卖股票的最佳时机Ⅱ
思路:
没理解
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
ans = 0
n = len(prices)
for i in range(1, n):
ans += max(0, prices[i]- prices[i-1])
return ans
309 最佳股票买卖时机含冷冻期
思路:
将第i天的状态进行分类讨论,运用动态规划实现每天的最大收益。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
if not prices:
return 0
n = len(prices)
f = [[-prices[0], 0, 0]] + [[0] * 3 for _ in range(n - 1)]
# f[i][0]: 手上持有股票的最大收益
# f[i][1]: 手上不持有股票,并且处于冷冻期的累计最大收益
# f[i][2]:手上不持有股票, 并且不在冷冻期的累计最大收益
for i in range(1, n):
f[i][0] = max(f[i - 1][0], f[i - 1][2] - prices[i])
f[i][1] = f[i - 1][0] + prices[i]
f[i][2] = max(f[i - 1][1], f[i - 1][2])
return max(f[n-1][1], f[n - 1][2])
714 买卖股票的最佳时机含手续费
思路:
找出第i天的两种状态,不持有股票的最大收益和持有股票的最大收益。持有股票的最大收益,可能是前一天就持有股票,也可能是今天才买入股票,二者取其大。不持有股票的最大收益可能是昨天就不持有股票,可能是今天卖出股票,二者取其大。
class Solution(object):
def maxProfit(self, prices, fee):
"""
:type prices: List[int]
:type fee: int
:rtype: int
"""
n = len(prices)
sell = 0
buy = -prices[0]
for i in range(1, n):
sell, buy = max(sell, buy + prices[i] - fee), max(buy, sell - prices[i])
return sell
5月18号
15 三数之和
思路:
先排序,然后使用多层遍历。当第一个数固定时,第二个数增大,第三个数就要减小(第三个数从数组末尾开始向前遍历)。使用三指针
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
n = len(nums)
nums.sort()
ans = []
for first in range(n):
if first > 0 and nums[first] == nums[first - 1]:
continue
third = n - 1
target = -nums[first]
for second in range(first + 1, n):
if second > first + 1 and nums[second] == nums[second - 1]:
continue
while second < third and nums[second] + nums[third] > target:
third -= 1
if second == third:
break
if nums[second] + nums[third] == target:
ans.append([nums[first], nums[second], nums[third]])
return ans
75 颜色分类
思路:
使用冒泡排序
class Solution(object):
def sortColors(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
n = len(nums)
for i in range(n):
for j in range(i+1, n):
if nums[i] > nums[j]:
nums[i], nums[j] = nums[j], nums[i]
return nums
187 重复的DNA序列
思路:
用哈希表存储每一个长度为10 的字符串,并统计出现次数,只返回出现两次的子字符串。
class Solution(object):
def findRepeatedDnaSequences(self, s):
"""
:type s: str
:rtype: List[str]
"""
n = len(s)
ans = defaultdict(int)
out = list()
for i in range(n-9):
sub = s[i:i+10]
ans[sub] += 1
if ans[sub] == 2:
out.append(sub)
return out
763 划分字母区间
思路:
贪心算法,将每个字母在字符串中出现的最后位置的下标存储起来,然后依次遍历字符串,当前字符的下标和其最后依次出现的下标取其大,当它们相等时,则就是最小划分区间,然后再继续遍历之后的字符串。
class Solution(object):
def partitionLabels(self, s):
"""
:type s: str
:rtype: List[int]
"""
last = [0] * 26
for i, ch in enumerate(s):
last[ord(ch) - ord("a")] = i
partition = list()
start = end = 0
for i, ch in enumerate(s):
end = max(end, last[ord(ch) - ord("a")])
if i == end:
partition.append(end - start + 1)
start = end + 1
return partition
5月24日
2 两数相加
思路:
同时遍历两个数组,特别要注意进位,最后如果有进位就放在循环外面添加一个节点。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
head = None
he = None
out = 0
while l1 or l2:
a = 0
b = 0
if l1:
a = l1.val
l1 = l1.next
if l2:
b = l2.val
l2 = l2.next
ans = a + b + out
if head == None:
head = he = ListNode(ans % 10)
else:
he.next = ListNode(ans % 10)
he = he.next
out = (a+b+out) // 10
if out > 0:
he.next = ListNode(out)
return head
5月25日
56 合并区间
思路:
先对列表里面的区间进行排序,然后依次遍历排序后的每一个区间,若区间的结尾值比后面区间的开头值大,则合并成新的区间,新的区间的结尾值在两个区间的结尾值中取大的。若区间的结尾值小于后面区间的开头值,则不合并,将当前区间添加到新的存储列表中。
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
intervals.sort(key = lambda x : x[0])
ans = list()
for i in intervals:
#如果列表为空,或者当前区间与上一区间不重合,直接添加
if not ans or ans[-1][1] < i[0]:
ans.append(i)
else:
# 否则的话,与上一区间进行合并
ans[-1][1] =max(ans[-1][1], i[1])
return ans
5月26日
740 删除并获得点数
思路:
首先对数组中的相同元素进行求和,选择数据中最大的元素再加一,作为新的数组ans的长度,初始化新数组中元素为0.然后依次遍历原数组中的元素并作为新数组的下标,记录该元素的和。然后就可以利用标准的动态规划来求解最大值,方式和打家劫舍题目一样。
class Solution(object):
def deleteAndEarn(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = max(nums)
ans = [0] * (n+1)
for i in nums:
ans[i] += i
r = ans[0]
p = max(ans[0], ans[1])
for i in range(2,len(ans)):
s = max(p, r+ans[i])
r = p
p = s
return p
5月27日
48 旋转图像
思路:
不会写
class Solution(object):
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
n = len(matrix)
for i in range(n // 2):
for j in range((n + 1) // 2):
matrix[i][j], matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1] = matrix[n - j - 1][i],matrix[n - i - 1][n - j -1], matrix[j][n - i -1], matrix[i][j]
5月30日
53 最大子数组和
思路:
自己写的代码。
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
pre = 0
ans = nums[0]
for i in nums:
pre = max(pre + i, i)
ans = max(ans, pre)
return ans
217 存在重复元素
思路:
利用集合不包含重复元素的特性和列表进行长度对比。
class Solution(object):
def containsDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
return not (len(set(nums)) == len(nums))
5月31号
55 跳跃游戏
思路:
设定一个可以达到的最远距离z,逐个遍历数组的元素时,同时更新z,若出现最远到达距离大于等于数组长度则返回True,退出循环后就返回False。
class Solution(object):
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
z = 0
for i in range(len(nums)):
if i <= z:
z = max(z, i + nums[i])
if z >= len(nums)-1:
return True
return False