一.leetcode 5254. 卖木头块(动态规划) 给你两个整数 m 和 n ,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices ,其中 prices[i] = [hi, wi, pricei] 表示你可以以 pricei 元的价格卖一块高为 hi 宽为 wi 的矩形木块。 每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块: 沿垂直方向按高度 完全 切割木块,或 沿水平方向按宽度 完全 切割木块 在将一块木块切成若干小木块后,你可以根据 prices 卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。 请你返回切割一块大小为 m x n 的木块后,能得到的 最多 钱数。 注意你可以切割木块任意次。 题目分析:这道题目的一个十分好用的优化解法是动态规划。(注意,动态规划可以理解为多维的递归) 以下是正解:
class Solution:
def sellingWood(self, m: int, n: int, prices: List[List[int]]) -> int:
pr = {(h,w):p for [h,w,p] in prices}
f = [[0]*(n+1) for i in range(m+1)]
for i in range(1,m+1):
for j in range(1,n+1):
f[i][j]=max(pr.get((i,j),0),
max([f[i][k]+f[i][j-k] for k in range(1,j)],default=0),
max([f[k1][j]+f[i-k1][j] for k1 in range(1,i)],default=0))
return f[m][n]
(记得自己写一遍试试呀) 二、2304. 网格中的最小路径代价(递归+@lru_cache(None)) 给你一个下标从 0 开始的整数矩阵 grid ,矩阵大小为 m x n ,由从 0 到 m * n - 1 的不同整数组成。你可以在此矩阵中,从一个单元格移动到 下一行 的任何其他单元格。如果你位于单元格 (x, y) ,且满足 x < m - 1 ,你可以移动到 (x + 1, 0), (x + 1, 1), ..., (x + 1, n - 1) 中的任何一个单元格。注意: 在最后一行中的单元格不能触发移动。 每次可能的移动都需要付出对应的代价,代价用一个下标从 0 开始的二维数组 moveCost 表示,该数组大小为 (m * n) x n ,其中 moveCost[i][j] 是从值为 i 的单元格移动到下一行第 j 列单元格的代价。从 grid 最后一行的单元格移动的代价可以忽略。 grid 一条路径的代价是:所有路径经过的单元格的 值之和 加上 所有移动的 代价之和 。从 第一行 任意单元格出发,返回到达 最后一行 任意单元格的最小路径代价。 题目分析:运用递归可以减少程序复杂度; 运用@lru_cache(None)可以减少存储空间和运行时间。 正解:
class Solution:
def minPathCost(self, grid: List[List[int]], moveCost: List[List[int]]) -> int:
m = len(grid)
n=len(grid[0])
# 很多问题会造成出错,不如先改成递归的形式,简洁的形式有助于提高正确率
@lru_cache(None)
def quasi_dfs(row, col):#递归需要两点,一个是递归链条(每次row+1),一个是终止条件(row==m-1)。
if row==m-1:
return grid[row][col]
else:
l2=[0]*n
for i in range(n):
l2[i]=moveCost[grid[row][col]][i]+quasi_dfs(row+1,i)
return grid[row][col]+min(l2)
l1=[]
for i in range(n):
l1.append(quasi_dfs(0,i))
return min(l1)
(记得自己写一遍试试呀) 20220625双周赛 三、6106. 统计无向图中无法互相到达点对数(O(n)的dfs求连通分支) 给你一个整数 n ,表示一张 无向图 中有 n 个节点,编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。 请你返回 无法互相到达 的不同 点对数目 。 我的一个成功但是超时了的解答。(我的解答完全是自己写的,几乎没有用到任何数据结构或者是成熟的算法)
这道题的关键在于:深度优先搜索。(你自己想的算法的复杂度很有可能比dfs高)
class Solution:
def countPairs(self, n: int, edges: List[List[int]]) -> int:
#这又是一道超出了时间限制的题目,需要注意复杂度。也许这其中有
l1=[]
for i in range(n):
l1.append({str(i)})#O(n)
for edge in edges:
for set1 in l1:
if str(edge[0]) in set1:
s1=set1.copy()
break
for set2 in l1:
if str(edge[1]) in set2:
s2=set2.copy()
break#这两个查找,复杂度O(n)
if s1!=s2:
l1.remove(s1)
l1.remove(s2)
s3=s1|s2
l1.append(s3)
l2=[]
for s in l1:
l2.append(len(s))
sum=0
for l in l2:
sum+=l*(n-l)
return int(sum/2) # 所以最后的复杂度为O(mn),所以你自己发展出来的算法往往比已经成熟的算法好的可能性低。所以学习,去掌握那些已经发展好的算法。
# 别人的正确的答案 分析异同 和之前的题目一起。
# class Solution:
# def countPairs(self, n: int, edges: List[List[int]]) -> int:
# g = [[] for _ in range(n)]
# for x, y in edges:
# g[x].append(y)
# g[y].append(x)# 复杂度为O(m)
#
# vis, ans, tot, size = [False] * n, 0, 0, 0
# def dfs(x: int) -> None:
# nonlocal size
# vis[x] = True
# size += 1
# for y in g[x]:
# if not vis[y]:
# dfs(y)
# 这个dfs运行之后结果如何?dfs积累起来,复杂度为O(n)
# for i in range(n):
# if not vis[i]:
# size = 0
# dfs(i)
# ans += size * tot
# tot += size
# return ans
#
# 作者:endlesscheng
# 链接:https://leetcode.cn/problems/count-unreachable-pairs-of-nodes-in-an-undirected-graph/solution/by-endlesscheng-7l50/
# 来源:力扣(LeetCode)
# 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总之,优先使用成熟的算法可以使得复杂度降低。
(记得自己写一遍试试呀) 20220626单周赛 5229.拼接数组的最大分数(最大字数组和,通过观察,找到O(n)的算法) 给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,长度都是 n 。 你可以选择两个整数 left 和 right ,其中 0 <= left <= right < n ,接着 交换 两个子数组 nums1[left...right] 和 nums2[left...right] 。 例如,设 nums1 = [1,2,3,4,5] 和 nums2 = [11,12,13,14,15] ,整数选择 left = 1 和 right = 2,那么 nums1 会变为 [1,12,13,4,5] 而 nums2 会变为 [11,2,3,14,15] 。 你可以选择执行上述操作 一次 或不执行任何操作。 数组的 分数 取 sum(nums1) 和 sum(nums2) 中的最大值,其中 sum(arr) 是数组 arr 中所有元素之和。 返回 可能的最大分数 。 子数组 是数组中连续的一个元素序列。arr[left...right] 表示子数组包含 nums 中下标 left 和 right 之间的元素(含 下标 left 和 right 对应元素)。 提示: n == nums1.length == nums2.length 1 <= n <= 105 1 <= nums1[i], nums2[i] <= 104 以下再贴一个我的自己解决的但是超时了的,复杂度为O(n^2)的程序: 这个程序算是遍历吧。也算是动态规划?(是的)
class Solution:
def maximumsSplicedArray(self, nums1: List[int], nums2: List[int]) -> int:
#用动态规划,这就又超出时间限制了,先把你能想到的都试一试 好吧,我不会
n=len(nums1)
s1=sum(nums1)
s2=sum(nums2)
a1=max(s1,s2)
for left in range(n):
s3=[0]*(n+1)
s4=[0]*(n+1)
for right in range(left,n):
s3[right]=s3[right-1]+nums1[right]
s4[right]=s4[right-1]+nums2[right]
inter=s3[right]-s4[right]
a2=s1-inter
a3=s2+inter
a1=max(a1,a2,a3)
return a1
别人的解答的成功之处在于复杂度是O(n).关键还是在性质刻画。最大子数组和有复杂度为O(n)的算法。你能不能通过观察,总结出来一个复杂度大大降低的算法? 别人的通过了的解答:
class Solution:
def maximumsSplicedArray(self, nums1: List[int], nums2: List[int]) -> int:
def maxSubArray(nums: List[int]) -> int:
pre = 0
res = nums[0]
for num in nums:
pre = max(pre + num, num)
res = max(res, pre)
return res
diff1, diff2 = [], []
for num1, num2 in zip(nums1, nums2):
diff1.append(num1 - num2)
diff2.append(num2 - num1)
res = max(
sum(nums1) + maxSubArray(diff2),
sum(nums2) + maxSubArray(diff1)
)
return res
(记得自己写一遍试试呀)
20220703单周赛第二题
6111. 螺旋矩阵 IV 给你两个整数:m 和 n ,表示矩阵的维数。 另给你一个整数链表的头节点 head 。 请你生成一个大小为 m x n 的螺旋矩阵,矩阵包含链表中的所有整数。链表中的整数从矩阵 左上角 开始、顺时针 按 螺旋 顺序填充。如果还存在剩余的空格,则用 -1 填充。 返回生成的矩阵。 别人的成功的代码:在这道题目中,我连ListNode的用法都不知道,程序写得一团乱麻。所以就先研究一下别人的算法吧 这一次,就不该抱怨为什么自己没有想出来了,而是缺少练习。
下面是正解:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def spiralMatrix(self, m: int, n: int, head: Optional[ListNode]) -> List[List[int]]:
res = [[-1 for _ in range(n)] for _ in range(m)]
visited = [[False for _ in range(n)] for _ in range(m)]
dirs = ((0, 1), (1, 0), (0, -1), (-1, 0))
row, col = 0, 0
idx = 0
while head:
res[row][col] = head.val
visited[row][col] = True
new_row, new_col = row + dirs[idx][0], col + dirs[idx][1]
if not (0 <= new_row < m and
0 <= new_col < n and
not visited[new_row][new_col]):
idx = (idx + 1) % 4
row += dirs[idx][0]
col += dirs[idx][1]
head = head.next
return res
20220705每日一题中用到的好的point:
bisect非常好用。
还有这个:
from itertools import pairwise
a=pairwise('123')
for i in a:
... print(i)
...
('1', '2')
('2', '3')
夸一夸下面这段代码:它的优势在于:1.首先for a,b in pairwise(sorted(arr))增大了生成成对数据的效率。2.其次 if (cur:=b-a)<m:这一段简化了表达。3.还有m,ans=cur,[[a,b]],这样的赋值语句比一般的赋值语句省时间。
class Solution:
def minimumAbsDifference(self, arr: List[int]) -> List[List[int]]:
m, ans = inf, []
for a, b in pairwise(sorted(arr)):
if (cur := b - a) < m:
m, ans = cur, [[a, b]]
elif cur == m:
ans.append([a, b])
return ans
作者:himymBen
链接:https://leetcode.cn/problems/minimum-absolute-difference/solution/-by-himymben-o6ub/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。