目录
1.最后一块石头的重量-easy。堆
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
- 如果 x == y,那么两块石头都会被完全粉碎;
- 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。
提示:
- 1 <= stones.length <= 30
- 1 <= stones[i] <= 1000
用最大堆
# 最大堆
class Solution(object):
def lastStoneWeight(self, stones):
from heapq import heappush, heappop
h = []
for s in stones:
heappush(h, -s)
while len(h):
x = -heappop(h)
if len(h) == 0:
return x
y = -heappop(h)
heappush(h, -abs(x-y))
return 0
2.删除字符串中的所有相邻重复项-easy。栈
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca"
输出:"ca" 解释:例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
# 栈
class Solution(object):
def removeDuplicates(self, S):
st = []
for c in S:
if not st or st[-1] != c:
st.append(c)
else:
st.pop()
return "".join(st)
3.最长字符串链-medium。DFS、DP
给出一个单词列表,其中每个单词都由小写英文字母组成。如果我们可以在 word1 的任何地方添加一个字母使其变成 word2,那么我们认为 word1 是 word2 的前身。例如,"abc" 是 "abac" 的前身。词链是单词 [word_1, word_2, ..., word_k] 组成的序列,k >= 1,其中 word_1 是 word_2 的前身,word_2 是 word_3 的前身,依此类推。从给定单词列表 words 中选择单词组成词链,返回词链的最长可能长度。
示例:
输入:["a","b","ba","bca","bda","bdca"] 输出:4 解释:最长单词链之一为 "a","ba","bda","bdca"。
3种做法
- DFS。先排序,遍历所有词链组合可能性
- DP。由DFS转化而来,套路有点像求最长递增子序列那个题
- 字典,尚未get
# DFS,先排序,遍历所有词链组合可能性
class Solution(object):
def longestStrChain(self, words):
if not words:
return 0
words.sort(key = lambda w: len(w))
res = 1
n = len(words)
for i in range(n):
cur = self.helper(words, i, words[i], n, 1)
if cur > res:
res = cur
return res
def helper(self, words, index, w, n, level):
if index >= n-1:
return level
tmp_max = level
for i in range(index+1, n):
if len(words[i]) == len(w)+1 and self.isPreBody(w, words[i]):
tmp_max = max(tmp_max, self.helper(words, i, words[i], n, level+1))
return tmp_max
def isPreBody(self, w1, w2):
i = j = 0
flag = False
while i < len(w1) and j < len(w2):
if w1[i] == w2[j]:
i += 1
j += 1
else:
if not flag:
flag = True
j += 1
else:
return False
return True
# top_a = 0
# top_b = 0
# while top_a < len(a):
# if top_a + 1 < top_b:
# return False
# if a[top_a] == b[top_b]:
# top_b += 1
# top_a += 1
# else:
# top_b += 1
# return True
# DFS转DP
class Solution(object):
def longestStrChain(self, words):
dp = [1 for _ in range(len(words))]
res = 0
words.sort(key=len)
for i in range(len(words)):
for j in range(i):
if len(words[i]) == len(words[j]) + 1 and self.isPreBody(words[j], words[i]):
dp[i] = max(dp[i], dp[j]+1)
res = max(res, dp[i])
return res
def isPreBody(self, w1, w2):
i = j = 0
flag = False
while i < len(w1) and j < len(w2):
if w1[i] == w2[j]:
i += 1
j += 1
else:
if not flag:
flag = True
j += 1
else:
return False
return True
# top1 神仙做法
class Solution(object):
def longestStrChain(self, words):
words.sort(key=len)
f = collections.defaultdict(int)
ans = 0
for w in words:
l = len(w)
for i in range(l):
f[w] = max(f[w], f[w[:i] + w[i+1:]] + 1)
# print(f)
ans = max(ans, f[w])
return ans
4.最后一块石头的重量 II-medium。DP
有一堆石头,每块石头的重量都是正整数。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
- 如果 x == y,那么两块石头都会被完全粉碎;
- 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。
最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回 0。
示例:
输入:[2,7,4,1,8,1]
输出:1 解释: 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1], 组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1], 组合 2 和 1,得到 1,所以数组转化为 [1,1,1], 组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum=0;
for (const auto& stone: stones) sum+=stone;
vector<bool> f(sum+1, false);
f[0]=true;
for (const auto& stone: stones)
for (int j=sum; j>=stone; j--)
f[j]=f[j] || f[j-stone];
for (int i=sum/2; i>=0; i--) if (f[i]) return sum-i-i;
return -1;
}
};
# 2
class Solution:
def lastStoneWeightII(self, stones) -> int:
s = sum(stones)
memo = {}
def dfs(i,c):
key = (i,c)
if key in memo:
return memo[key]
if i == 0:
return abs(s-c-c)
res = min(dfs(i-1,c),dfs(i-1,c+stones[i-1]))
memo[key] = res
return res
return dfs(len(stones),0)