664. 奇怪的打印机
不能直接从前往后遍历。枚举
for k in range(i,j): dp[i][j] = min(min_val,dp[i][k]+dp[k+1][j])
的时候,k+1是大于i的,还没计算呢。
class Solution:
def strangePrinter(self, s: str) -> int:
#规律:s[i]==s[j]的时候,dp[i][j] = dp[i][j-1]
#当s[i]!=s[j]时,没规律,枚举分割点找最小值
dp = [[1 for _ in range(len(s))] for _ in range(len(s))]
for i in range(len(s),-1,-1):
for j in range(i+1,len(s)):
if s[i] == s[j]:
dp[i][j] = dp[i][j-1]
else:
min_val = float("inf")
for k in range(i,j):
dp[i][j] = min(min_val,dp[i][k]+dp[k+1][j])
min_val = dp[i][j]
return dp[0][-1]
730. 统计不同回文子序列
今天这个每日一题,为什么去充的时候要left+1,right-1。因为区间如果是left,right的话,是不一定包含left,right这个字母的。
我们要找的是,包括left,right这个字母的。
class Solution:
def countPalindromicSubsequences(self, s: str) -> int:
dp = [[0 for _ in range(len(s)+1)] for _ in range(len(s)+1)]
for i in range(1,len(s)+1):
dp[i][i] = 1
for i in range(1,len(s)+1):
for j in range(i-1,0,-1):
# for j in range(i):
if s[i-1] == s[j-1]:
# if j-1 + 1 == i-1:
# dp[j][i] = 2
# continue
if s[i-1] not in s[j:i-1]:
dp[j][i] = 2*dp[j+1][i-1] + 2
elif s[i-1] in s[j:i-1]:
# #出现过一次;出现多2次及以上.这么写超时
# left = j
# right = j
# if_first = True
# count = 0
# for h in range(len(s[j:i-1])):
# if s[j+h] == s[i-1] and if_first:
# count += 1
# #要找的是dp里的下标,是s的下标+1
# left = j+h + 1
# if_first = False
# elif s[j+h] == s[i-1] and not if_first:
# count += 1
# right = j+h + 1
#出现过一次;出现多2次及以上
left = j
while s[left] != s[i-1]:
left += 1
right = i-2
while s[right] != s[i-1]:
right -= 1
if left == right:
dp[j][i] = 2*dp[j+1][i-1] + 1
else:
left += 1
right += 1
dp[j][i] = 2*dp[j+1][i-1] - dp[left+1][right-1]
else:
dp[j][i] = dp[j+1][i]+dp[j][i-1] - dp[j+1][i-1]
# dp[j][i] = dp[j][i] % (10**9+7)
return dp[1][-1] % (10**9+7)
312. 戳气球
class Solution:
def maxCoins(self, nums: List[int]) -> int:
#nums首尾添加1,方便处理边界情况
nums.insert(0,1)
nums.insert(len(nums),1)
store = [[0]*(len(nums)) for i in range(len(nums))]
def range_best(i,j):
m = 0
#k是(i,j)区间内最后一个被戳的气球
for k in range(i+1,j): #k取值在(i,j)开区间中
#以下都是开区间(i,k), (k,j)
left = store[i][k]
right = store[k][j]
a = left + nums[i]*nums[k]*nums[j] + right
if a > m:
m = a
store[i][j] = m
#对每一个区间长度进行循环
for n in range(2,len(nums)): #区间长度 #长度从3开始,n从2开始
#开区间长度会从3一直到len(nums)
#因为这里取的是range,所以最后一个数字是len(nums)-1
#对于每一个区间长度,循环区间开头的i
for i in range(0,len(nums)-n): #i+n = len(nums)-1
#计算这个区间的最多金币
range_best(i,i+n)
return store[0][len(nums)-1]
作者:xiao-yan-gou
链接:https://leetcode.cn/problems/burst-balloons/solution/zhe-ge-cai-pu-zi-ji-zai-jia-ye-neng-zuo-guan-jian-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
1000. 合并石头的最低成本
class Solution:
def mergeStones(self, stones: List[int], k: int) -> int:
if (len(stones) - k) % (k - 1) != 0:
return -1
n = len(stones)
preSum = [0]
for i in range(n):
preSum.append(preSum[-1] + stones[i])
@lru_cache(None)
def dfs(l, r) -> int: # (左右闭区间)把[l,r]合并成最少堆需要至少多少cost
if r - l + 1 < k: # base case::无法再合并
return 0
return min(
dfs(l, i) + dfs(i + 1, r) + ((preSum[r + 1] - preSum[l]) if (r - l) % (k - 1) == 0 else 0) for i in
range(l, r, k - 1))
return dfs(0, n - 1)
作者:imnanch7
链接:https://leetcode.cn/problems/minimum-cost-to-merge-stones/solution/python3-qu-jian-xing-ji-yi-hua-dfs-mei-j-qn02/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。