【leetcode】周赛记录
目录:
1. 2020年9月13日 -- 周赛
2. 2020年10月31日 -- 双周赛
3. 2020年11月1日 -- 周赛
4. 2020年11月8日 -- 周赛
5. 2020年11月28日 -- 双周赛
2020年9月13日 -- 周赛
做对了两道题。
1582. 二进制矩阵中的特殊位置 -- 简单
题目链接:https://leetcode-cn.com/problems/special-positions-in-a-binary-matrix/
题目描述
给你一个大小为 rows x cols 的矩阵 mat,其中 mat[i][j] 是 0 或 1,请返回 矩阵 mat 中特殊位置的数目。
特殊位置 定义:如果 mat[i][j] == 1 并且第 i 行和第 j 列中的所有其他元素均为 0(行和列的下标均 从 0 开始 ),则位置 (i, j) 被称为特殊位置。
示例 1:
输入:mat =
[[1,0,0],
[0,0,1],
[1,0,0]]
输出:1
解释:(1,2) 是一个特殊位置,因为 mat[1][2] == 1 且所处的行和列上所有其他元素都是 0
示例 2:
输入:mat =
[[1,0,0],
[0,1,0],
[0,0,1]]
输出:3
解释:(0,0), (1,1) 和 (2,2) 都是特殊位置
示例 3:
输入:mat =
[[0,0,0,1],
[1,0,0,0],
[0,1,1,0],
[0,0,0,0]]
输出:2
示例 4:
输入:mat =
[[0,0,0,0,0],
[1,0,0,0,0],
[0,1,0,0,0],
[0,0,1,0,0],
[0,0,0,1,1]]
输出:3
提示:
rows == mat.length
cols == mat[i].length
1 <= rows, cols <= 100
mat[i][j] 是 0 或 1
解题思路
统计每行每列之和,如果为1,则根据行列定位所求的特殊位置。
代码
class Solution:
def numSpecial(self, mat: List[List[int]]) -> int:
if mat is None or len(mat) == 0 or len(mat[0]) == 0:
return 0
rows = len(mat)
cols = len(mat[0])
rows_sum = [0]*rows
cols_sum = [0]*cols
for i in range(rows):
for j in range(cols):
rows_sum[i] += mat[i][j]
cols_sum[j] += mat[i][j]
rst = 0
for i in range(rows):
for j in range(cols):
if rows_sum[i] == 1 and cols_sum[j] == 1 and mat[i][j] == 1:
rst += 1
return rst
1583. 统计不开心的朋友 -- 中等
题目链接:https://leetcode-cn.com/problems/count-unhappy-friends/
题目描述
给你一份 n 位朋友的亲近程度列表,其中 n 总是 偶数 。
对每位朋友 i,preferences[i] 包含一份 按亲近程度从高到低排列 的朋友列表。换句话说,排在列表前面的朋友与 i 的亲近程度比排在列表后面的朋友更高。每个列表中的朋友均以 0 到 n-1 之间的整数表示。
所有的朋友被分成几对,配对情况以列表 pairs 给出,其中 pairs[i] = [xi, yi] 表示 xi 与 yi 配对,且 yi 与 xi 配对。
但是,这样的配对情况可能会是其中部分朋友感到不开心。在 x 与 y 配对且 u 与 v 配对的情况下,如果同时满足下述两个条件,x 就会不开心:
x 与 u 的亲近程度胜过 x 与 y,且
u 与 x 的亲近程度胜过 u 与 v
返回 不开心的朋友的数目 。
示例 1:
输入:n = 4, preferences = [[1, 2, 3], [3, 2, 0], [3, 1, 0], [1, 2, 0]], pairs = [[0, 1], [2, 3]]
输出:2
解释:
朋友 1 不开心,因为:
- 1 与 0 配对,但 1 与 3 的亲近程度比 1 与 0 高,且
- 3 与 1 的亲近程度比 3 与 2 高。
朋友 3 不开心,因为: - 3 与 2 配对,但 3 与 1 的亲近程度比 3 与 2 高,且
- 1 与 3 的亲近程度比 1 与 0 高。
朋友 0 和 2 都是开心的。
示例 2:
输入:n = 2, preferences = [[1], [0]], pairs = [[1, 0]]
输出:0
解释:朋友 0 和 1 都开心。
示例 3:
输入:n = 4, preferences = [[1, 3, 2], [2, 3, 0], [1, 3, 0], [0, 2, 1]], pairs = [[1, 3], [0, 2]]
输出:4
提示:
2 <= n <= 500
n 是偶数
preferences.length == n
preferences[i].length == n - 1
0 <= preferences[i][j] <= n - 1
preferences[i] 不包含 i
preferences[i] 中的所有值都是独一无二的
pairs.length == n/2
pairs[i].length == 2
xi != yi
0 <= xi, yi <= n - 1
每位朋友都 恰好 被包含在一对中
解题思路
给排序赋值,然后遍历既可,找出不开心的对。
注意下这里的二位数组的初始化,要逐行初始化。不能直接[[0]n]n。
代码
class Solution:
def unhappyFriends(self, n: int, preferences: List[List[int]], pairs: List[List[int]]) -> int:
prefer_weight = [] # 值越小表示关系越近
for i in range(n):
temp = [0]*n
prefer_weight.append(temp)
for i in range(n):
for j in range(n-1):
a = i
b = preferences[i][j]
#print(b)
prefer_weight[a][b] = j+1
#print(prefer_weight)
#print(prefer_weight)
link = [-1]*n
for i in range(len(pairs)):
a, b = pairs[i][0], pairs[i][1]
link[a] = b
link[b] = a
#print(link)
more_prefer = []
for i in range(n):
temp = [0]*n
more_prefer.append(temp)
for i in range(n):
for j in range(n):
now_weight = prefer_weight[i][j]
link_weight = prefer_weight[i][link[i]]
#print(now_weight, link_weight)
if now_weight != 0 and now_weight < link_weight:
more_prefer[i][j] = 1
#print(more_prefer)
unhappy = [0]*n
for i in range(n):
for j in range(n):
if more_prefer[i][j] == 1 and more_prefer[j][i] == 1:
unhappy[i] = 1
unhappy[j] = 1
return sum(unhappy)
2020年10月31日 -- 双周赛
做对了前三道,第四道运行超时了。赛后参考了一下其他人的代码,重新做了提交。
1. 按照频率将数组升序排序 -- 简单
题目链接:https://leetcode-cn.com/problems/sort-array-by-increasing-frequency/
题目描述:
给你一个整数数组 nums ,请你将数组按照每个值的频率 升序 排序。如果有多个值的频率相同,请你按照数值本身将它们 降序 排序。
请你返回排序后的数组。
示例 1:
输入:nums = [1,1,2,2,2,3]
输出:[3,1,1,2,2,2]
解释:'3' 频率为 1,'1' 频率为 2,'2' 频率为 3 。
示例 2:
输入:nums = [2,3,1,3,2]
输出:[1,3,3,2,2]
解释:'2' 和 '3' 频率都为 2 ,所以它们之间按照数值本身降序排序。
示例 3:
输入:nums = [-1,1,-6,4,5,-6,1,4,1]
输出:[5,-1,4,4,-6,-6,1,1,1]
提示:
1 <= nums.length <= 100
-100 <= nums[i] <= 100
思路解析:
用python实现非常简单。即使不用sorted,自己写个排序也不难。
代码:
class Solution:
def frequencySort(self, nums: List[int]) -> List[int]:
dic = {}
for num in nums:
if num not in dic:
dic[num] = 0
dic[num] += 1
temp_lst = sorted(dic.items(), key = lambda d: (d[1], -d[0]), reverse=False)
rst_lst = []
for temp in temp_lst:
for i in range(temp[1]):
rst_lst.append(temp[0])
return rst_lst
2. 两点之间不包含任何点的最宽垂直面积 -- 中等
题目链接:https://leetcode-cn.com/problems/widest-vertical-area-between-two-points-containing-no-points/
题目描述:
给你 n 个二维平面上的点 points ,其中 points[i] = [xi, yi] ,请你返回两点之间内部不包含任何点的 最宽垂直面积 的宽度。
垂直面积 的定义是固定宽度,而 y 轴上无限延伸的一块区域(也就是高度为无穷大)。 最宽垂直面积 为宽度最大的一个垂直面积。
请注意,垂直区域 边上 的点 不在 区域内。
示例 1:
输入:points = [[8,7],[9,9],[7,4],[9,7]]
输出:1
示例 2:
输入:points = [[3,1],[9,0],[1,0],[1,4],[5,3],[8,8]]
输出:3
提示:
n == points.length
2 <= n <= 105
points[i].length == 2
0 <= xi, yi <= 109
思路解析:
算一下横坐标的最大间隔就可以了。
代码:
class Solution:
def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int:
dic = {}
for pairs in points:
if pairs[0] not in dic:
dic[pairs[0]] = 1
lst = sorted([i for i in dic.keys()])
max_len = 0
for i in range(1, len(lst)):
temp = lst[i] - lst[i-1]
if temp > max_len:
max_len = temp
return max_len
3. 统计只差一个字符的子串数目 -- 中等
题目链接:https://leetcode-cn.com/problems/count-substrings-that-differ-by-one-character/
题目描述:
给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换 一个不同字符 以后,是 t 串的子串。换言之,请你找到 s 和 t 串中 恰好 只有一个字符不同的子字符串对的数目。
比方说, "computer" 和 "computation" 加粗部分只有一个字符不同: 'e'/'a' ,所以这一对子字符串会给答案加 1 。
请你返回满足上述条件的不同子字符串对数目。
一个 子字符串 是一个字符串中连续的字符。
示例 1:
输入:s = "aba", t = "baba"
输出:6
解释:以下为只相差 1 个字符的 s 和 t 串的子字符串对:
("aba", "baba")
("aba", "baba")
("aba", "baba")
("aba", "baba")
("aba", "baba")
("aba", "baba")
加粗部分分别表示 s 和 t 串选出来的子字符串。
示例 2:
输入:s = "ab", t = "bb"
输出:3
解释:以下为只相差 1 个字符的 s 和 t 串的子字符串对:
("ab", "bb")
("ab", "bb")
("ab", "bb")
加粗部分分别表示 s 和 t 串选出来的子字符串。
示例 3:
输入:s = "a", t = "a"
输出:0
示例 4:
输入:s = "abe", t = "bbc"
输出:10
提示:
1 <= s.length, t.length <= 100
s 和 t 都只包含小写英文字母。
解题思路:
暴力解法,遍历一下就可以了。
代码:
class Solution:
def countSubstrings(self, s: str, t: str) -> int:
max_len = min(len(s), len(t))
cnt = 0
for s_len in range(1, max_len+1):
for i in range(len(s)-s_len+1):
s_temp = s[i:i+s_len]
for j in range(len(t)-s_len+1):
t_temp = t[j:j+s_len]
if self.only_one_diff(s_temp, t_temp):
#print(s_temp, i, t_temp, j)
cnt += 1
return cnt
def only_one_diff(self, s, t):
if len(s) != len(t):
return False
cnt = 0
for i in range(len(s)):
if s[i] != t[i]:
cnt += 1
if cnt == 1:
return True
return False
4. 通过给定词典构造目标字符串的方案数 -- 困难
题目链接:https://leetcode-cn.com/problems/number-of-ways-to-form-a-target-string-given-a-dictionary/
题目描述:
给你一个字符串列表 words 和一个目标字符串 target 。words 中所有字符串都 长度相同 。
你的目标是使用给定的 words 字符串列表按照下述规则构造 target :
- 从左到右依次构造 target 的每一个字符。
- 为了得到 target 第 i 个字符(下标从 0 开始),当 target[i] = words[j][k] 时,你可以使用 words 列表中第 j 个字符串的第 k 个字符。
- 一旦你使用了 words 中第 j 个字符串的第 k 个字符,你不能再使用 words 字符串列表中任意单词的第 x 个字符(x <= k)。也就是说,所有单词下标小于等于 k 的字符都不能再被使用。
- 请你重复此过程直到得到目标字符串 target 。
请注意, 在构造目标字符串的过程中,你可以按照上述规定使用 words 列表中 同一个字符串 的 多个字符 。
请你返回使用 words 构造 target 的方案数。由于答案可能会很大,请对 109 + 7 取余 后返回。
(译者注:此题目求的是有多少个不同的 k 序列,详情请见示例。)
示例 1:
输入:words = ["acca","bbbb","caca"], target = "aba"
输出:6
解释:总共有 6 种方法构造目标串。
"aba" -> 下标为 0 ("acca"),下标为 1 ("bbbb"),下标为 3 ("caca")
"aba" -> 下标为 0 ("acca"),下标为 2 ("bbbb"),下标为 3 ("caca")
"aba" -> 下标为 0 ("acca"),下标为 1 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 0 ("acca"),下标为 2 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 1 ("caca"),下标为 2 ("bbbb"),下标为 3 ("acca")
"aba" -> 下标为 1 ("caca"),下标为 2 ("bbbb"),下标为 3 ("caca")
示例 2:
输入:words = ["abba","baab"], target = "bab"
输出:4
解释:总共有 4 种不同形成 target 的方法。
"bab" -> 下标为 0 ("baab"),下标为 1 ("baab"),下标为 2 ("abba")
"bab" -> 下标为 0 ("baab"),下标为 1 ("baab"),下标为 3 ("baab")
"bab" -> 下标为 0 ("baab"),下标为 2 ("baab"),下标为 3 ("baab")
"bab" -> 下标为 1 ("abba"),下标为 2 ("baab"),下标为 3 ("baab")
示例 3:
输入:words = ["abcd"], target = "abcd"
输出:1
示例 4:
输入:words = ["abab","baba","abba","baab"], target = "abba"
输出:16
提示:
1 <= words.length <= 1000
1 <= words[i].length <= 1000
words 中所有单词长度相同。
1 <= target.length <= 1000
words[i] 和 target 都仅包含小写英文字母。
解题思路
做位运算,或者递归,容易超时。
这里用表实现迭代,可以满足题目要求。
代码
class Solution:
def numWays(self, words: List[str], target: str) -> int:
word_len = len(words[0])
target_len = len(target)
cnt = [[0] * 26 for _ in range(word_len)] # 存放words的每一个字符的频次
for word in words:
for i, char in enumerate(word):
cnt[i][ord(char)-ord('a')] += 1 # 统计频次
dp = [[0]*(target_len+1) for _ in range(word_len+1)] # dp大小是(word_len+1)*(target_len)*1
for i in range(word_len+1):
dp[i][0] = 1 # 该列全部置为1,是为了保证在后面乘法计算时,从1开始乘
for i in range(word_len):
for j in range(target_len):
# i, j -> i+1, j+1 匹配下一个word字母,及下一个target字母
# cnt[i][ord(target[j])-ord('a')] 为0与否,说明匹配是否成功,匹配成功则乘上所有word里都有该字母的数量
# i, j+1 -> i+1, j+1 直接跳过,匹配下一个word字母
dp[i+1][j+1] = dp[i][j] * cnt[i][ord(target[j])-ord('a')] + dp[i][j+1]
return dp[word_len][target_len] % 1000000007
2020年11月1日 -- 周赛
做对了前两道,第三道超时了。第三道题目测试数据太弱了,居然直接先堆砖再用梯子就可以AC。
1. 能否连接形成数组 -- 简单
题目链接:https://leetcode-cn.com/problems/check-array-formation-through-concatenation/
题目描述:
给你一个整数数组 arr ,数组中的每个整数 互不相同 。另有一个由整数数组构成的数组 pieces,其中的整数也 互不相同 。请你以 任意顺序 连接 pieces 中的数组以形成 arr 。但是,不允许 对每个数组 pieces[i] 中的整数重新排序。
如果可以连接 pieces 中的数组形成 arr ,返回 true ;否则,返回 false 。
示例 1:
输入:arr = [85], pieces = [[85]]
输出:true
示例 2:
输入:arr = [15,88], pieces = [[88],[15]]
输出:true
解释:依次连接 [15] 和 [88]
示例 3:
输入:arr = [49,18,16], pieces = [[16,18,49]]
输出:false
解释:即便数字相符,也不能重新排列 pieces[0]
示例 4:
输入:arr = [91,4,64,78], pieces = [[78],[4,64],[91]]
输出:true
解释:依次连接 [91]、[4,64] 和 [78]
示例 5:
输入:arr = [1,3,5,7], pieces = [[2,4,6,8]]
输出:false
提示:
1 <= pieces.length <= arr.length <= 100
sum(pieces[i].length) == arr.length
1 <= pieces[i].length <= arr.length
1 <= arr[i], pieces[i][j] <= 100
arr 中的整数 互不相同
pieces 中的整数 互不相同(也就是说,如果将 pieces 扁平化成一维数组,数组中的所有整数互不相同)
解题思路:
很简单,遍历一下就可以。
代码:
class Solution:
def canFormArray(self, arr: List[int], pieces: List[List[int]]) -> bool:
len_arr = len(arr)
len_pieces = sum([len(piece) for piece in pieces])
if len_arr != len_pieces:
return False
index = 0
while index < len_arr:
temp_index = index
for i in range(len(pieces)):
piece = pieces[i]
if piece[0] == arr[index]:
for j in range(len(piece)):
if piece[j] == arr[index]:
index += 1
else:
return False
break
if temp_index == index:
return False
return True
2. 统计字典序元音字符串的数目 -- 中等
题目链接:https://leetcode-cn.com/problems/count-sorted-vowel-strings/
题目描述:
给你一个整数 n,请返回长度为 n 、仅由元音 (a, e, i, o, u) 组成且按 字典序排列 的字符串数量。
字符串 s 按 字典序排列 需要满足:对于所有有效的 i,s[i] 在字母表中的位置总是与 s[i+1] 相同或在 s[i+1] 之前。
示例 1:
输入:n = 1
输出:5
解释:仅由元音组成的 5 个字典序字符串为 ["a","e","i","o","u"]
示例 2:
输入:n = 2
输出:15
解释:仅由元音组成的 15 个字典序字符串为
["aa","ae","ai","ao","au","ee","ei","eo","eu","ii","io","iu","oo","ou","uu"]
注意,"ea" 不是符合题意的字符串,因为 'e' 在字母表中的位置比 'a' 靠后
示例 3:
输入:n = 33
输出:66045
提示:
1 <= n <= 50
解题思路:
用数组去存储字符串会超时。正确的做法是直接推算一下,用矩阵存储结果。
代码:
class Solution:
def countVowelStrings(self, n: int) -> int:
matrix = []
for i in range(5):
matrix.append([0]*(n+1))
for i in range(5):
matrix[i][0] = 1
for j in range(1, n+1):
for i in range(5):
for t in range(i+1):
matrix[i][j] += matrix[t][j-1]
return matrix[4][n]
3. 可以到达的最远建筑 -- 中等
题目链接:https://leetcode-cn.com/problems/furthest-building-you-can-reach/
题目描述:
给你一个整数数组 heights ,表示建筑物的高度。另有一些砖块 bricks 和梯子 ladders 。
你从建筑物 0 开始旅程,不断向后面的建筑物移动,期间可能会用到砖块或梯子。
当从建筑物 i 移动到建筑物 i+1(下标 从 0 开始 )时:
如果当前建筑物的高度 大于或等于 下一建筑物的高度,则不需要梯子或砖块
如果当前建筑的高度 小于 下一个建筑的高度,您可以使用 一架梯子 或 (h[i+1] - h[i]) 个砖块
如果以最佳方式使用给定的梯子和砖块,返回你可以到达的最远建筑物的下标(下标 从 0 开始 )。
示例 1:
输入:heights = [4,2,7,6,9,14,12], bricks = 5, ladders = 1
输出:4
解释:从建筑物 0 出发,你可以按此方案完成旅程:
- 不使用砖块或梯子到达建筑物 1 ,因为 4 >= 2
- 使用 5 个砖块到达建筑物 2 。你必须使用砖块或梯子,因为 2 < 7
- 不使用砖块或梯子到达建筑物 3 ,因为 7 >= 6
- 使用唯一的梯子到达建筑物 4 。你必须使用砖块或梯子,因为 6 < 9
无法越过建筑物 4 ,因为没有更多砖块或梯子。
示例 2:
输入:heights = [4,12,2,7,3,18,20,3,19], bricks = 10, ladders = 2
输出:7
示例 3:
输入:heights = [14,3,19,3], bricks = 17, ladders = 0
输出:3
提示:
1 <= heights.length <= 105
1 <= heights[i] <= 106
0 <= bricks <= 109
0 <= ladders <= heights.length
解题思路:
因为梯子没有限制高度,所以应当尽可能把梯子放在楼层差更大的地方。
所以要求楼层差的最大N位数,涉及到排序。
以下代码思路应该对,不过会超时。(待优化)
代码:
class Solution:
def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int:
# 主要是充分利用梯子,在楼层差最大时使用
diff = []
for i in range(1, len(heights)):
if heights[i] <= heights[i-1]:
diff.append(0)
else:
diff.append(heights[i]-heights[i-1])
"""
# 楼层差排序
diff_dic = {}
for i in range(len(diff)):
if diff[i] != 0:
diff_dic[i] = diff[i]
sort_lst = sorted(diff_dic.items(), key = lambda d: (-d[1], d[0]), reverse=False)
"""
#print(diff)
diff_sum = 0
max_path = 0
temp_lst = [0]
for i in range(len(diff)):
diff_sum += diff[i]
for t in range(len(temp_lst)):
if temp_lst[t] <= diff[i]:
temp_lst.insert(t, diff[i])
break
#temp_lst = sorted(diff[:i+1], reverse=True)
replace_sum = sum(temp_lst[:ladders])
#print(temp_lst)
#print(diff_sum, bricks, replace_sum)
if diff_sum <= bricks + replace_sum:
max_path = i+1
else:
break
return max_path
2020年11月8日 -- 周赛
做对了前三道,第四道超时了。
1. 获取生成数组中的最大值
题目链接:https://leetcode-cn.com/problems/get-maximum-in-generated-array/
题目描述:
给你一个整数 n 。按下述规则生成一个长度为 n + 1 的数组 nums :
nums[0] = 0
nums[1] = 1
当 2 <= 2 * i <= n 时,nums[2 * i] = nums[i]
当 2 <= 2 * i + 1 <= n 时,nums[2 * i + 1] = nums[i] + nums[i + 1]
返回生成数组 nums 中的 最大 值。
示例 1:
输入:n = 7
输出:3
解释:根据规则:
nums[0] = 0
nums[1] = 1
nums[(1 * 2) = 2] = nums[1] = 1
nums[(1 * 2) + 1 = 3] = nums[1] + nums[2] = 1 + 1 = 2
nums[(2 * 2) = 4] = nums[2] = 1
nums[(2 * 2) + 1 = 5] = nums[2] + nums[3] = 1 + 2 = 3
nums[(3 * 2) = 6] = nums[3] = 2
nums[(3 * 2) + 1 = 7] = nums[3] + nums[4] = 2 + 1 = 3
因此,nums = [0,1,1,2,1,3,2,3],最大值 3
示例 2:
输入:n = 2
输出:1
解释:根据规则,nums[0]、nums[1] 和 nums[2] 之中的最大值是 1
示例 3:
输入:n = 3
输出:2
解释:根据规则,nums[0]、nums[1]、nums[2] 和 nums[3] 之中的最大值是 2
提示:
0 <= n <= 100
代码:
class Solution:
def getMaximumGenerated(self, n: int) -> int:
nums = [0]*(n+1)
max_num = 0
if n > 0:
nums[1] = 1
max_num = 1
for i in range(2, n+1):
if i % 2 == 0:
nums[i] = nums[i//2]
if nums[i] > max_num:
max_num = nums[i]
else:
nums[i] = nums[i//2] + nums[i//2 + 1]
if nums[i] > max_num:
max_num = nums[i]
return max_num
2. 字符频次唯一的最小删除次数 -- 中等
题目链接:https://leetcode-cn.com/problems/minimum-deletions-to-make-character-frequencies-unique/
题目描述:
如果字符串 s 中 不存在 两个不同字符 频次 相同的情况,就称 s 是 优质字符串 。
给你一个字符串 s,返回使 s 成为 优质字符串 需要删除的 最小 字符数。
字符串中字符的 频次 是该字符在字符串中的出现次数。例如,在字符串 "aab" 中,'a' 的频次是 2,而 'b' 的频次是 1 。
示例 1:
输入:s = "aab"
输出:0
解释:s 已经是优质字符串。
示例 2:
输入:s = "aaabbbcc"
输出:2
解释:可以删除两个 'b' , 得到优质字符串 "aaabcc" 。
另一种方式是删除一个 'b' 和一个 'c' ,得到优质字符串 "aaabbc" 。
示例 3:
输入:s = "ceabaacb"
输出:2
解释:可以删除两个 'c' 得到优质字符串 "eabaab" 。
注意,只需要关注结果字符串中仍然存在的字符。(即,频次为 0 的字符会忽略不计。)
提示:
1 <= s.length <= 105
s 仅含小写英文字母
代码:
class Solution:
def minDeletions(self, s: str) -> int:
dic = {}
for i in range(len(s)):
if s[i] not in dic:
dic[s[i]] = 0
dic[s[i]] += 1
dic_num = {}
for k, v in dic.items():
if v not in dic_num:
dic_num[v] = 0
dic_num[v] += 1
cnt = 0
dic_num_cp = {}
for k, v in dic_num.items():
dic_num_cp[k] = v
for k, v in dic_num.items():
k_cp = k
v_cp = v
while v_cp > 1:
k_cp -= 1
cnt += 1
if k_cp not in dic_num_cp or k_cp == 0:
dic_num_cp[k_cp] = 1
v_cp -= 1
k_cp = k # 重置
else:
continue
return cnt
3. 销售价值减少的颜色球 -- 中等
题目链接:https://leetcode-cn.com/problems/sell-diminishing-valued-colored-balls/
题目描述:
你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。
这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的)
给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。
请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。
示例 1:
输入:inventory = [2,5], orders = 4
输出:14
解释:卖 1 个第一种颜色的球(价值为 2 ),卖 3 个第二种颜色的球(价值为 5 + 4 + 3)。
最大总和为 2 + 5 + 4 + 3 = 14 。
示例 2:
输入:inventory = [3,5], orders = 6
输出:19
解释:卖 2 个第一种颜色的球(价值为 3 + 2),卖 4 个第二种颜色的球(价值为 5 + 4 + 3 + 2)。
最大总和为 3 + 2 + 5 + 4 + 3 + 2 = 19 。
示例 3:
输入:inventory = [2,8,4,10,6], orders = 20
输出:110
示例 4:
输入:inventory = [1000000000], orders = 1000000000
输出:21
解释:卖 1000000000 次第一种颜色的球,总价值为 500000000500000000 。 500000000500000000 对 109 + 7 取余为 21 。
提示:
1 <= inventory.length <= 105
1 <= inventory[i] <= 109
1 <= orders <= min(sum(inventory[i]), 109)
解题思路:
先排序,然后再计算。
代码:
class Solution:
def maxProfit(self, inventory: List[int], orders: int) -> int:
values = 0
lst = sorted(inventory, reverse=True)
lst.append(0)
#print(lst)
diff = [0]*(len(lst)-1)
for i in range(len(lst)-1):
diff[i] = lst[i] - lst[i+1]
#print(diff)
for i in range(len(diff)):
#print(values)
if diff[i] != 0:
#print(orders)
if orders >= diff[i]*(i+1):
values += (i+1)*self.getSum(lst[i], lst[i+1])
#print(lst[i], lst[i+1])
#print(values)
values %= 1000000007
orders -= diff[i]*(i+1)
#print(diff[i]*(i+1))
#print(orders)
else:
#print(orders)
high = orders // (i+1)
#print(high)
#print(lst[i], lst[i]-high)
values += (i+1)*self.getSum(lst[i], lst[i]-high)
values %= 1000000007
orders %= i+1
values += (orders)*(lst[i]-high)
values %= 1000000007
return values
return values
def getSum(self, start, end): # [start, end)
if start < end:
start, end = end, start
end = end + 1 # [start, end]
return (start + end) * (start - end + 1) // 2
4. 通过指令创建有序数组 -- 困难
题目链接:https://leetcode-cn.com/problems/create-sorted-array-through-instructions/
题目描述:
给你一个整数数组 instructions ,你需要根据 instructions 中的元素创建一个有序数组。一开始你有一个空的数组 nums ,你需要 从左到右 遍历 instructions 中的元素,将它们依次插入 nums 数组中。每一次插入操作的 代价 是以下两者的 较小值 :
nums 中 严格小于 instructions[i] 的数字数目。
nums 中 严格大于 instructions[i] 的数字数目。
比方说,如果要将 3 插入到 nums = [1,2,3,5] ,那么插入操作的 代价 为 min(2, 1) (元素 1 和 2 小于 3 ,元素 5 大于 3 ),插入后 nums 变成 [1,2,3,3,5] 。
请你返回将 instructions 中所有元素依次插入 nums 后的 总最小代价 。由于答案会很大,请将它对 109 + 7 取余 后返回。
示例 1:
输入:instructions = [1,5,6,2]
输出:1
解释:一开始 nums = [] 。
插入 1 ,代价为 min(0, 0) = 0 ,现在 nums = [1] 。
插入 5 ,代价为 min(1, 0) = 0 ,现在 nums = [1,5] 。
插入 6 ,代价为 min(2, 0) = 0 ,现在 nums = [1,5,6] 。
插入 2 ,代价为 min(1, 2) = 1 ,现在 nums = [1,2,5,6] 。
总代价为 0 + 0 + 0 + 1 = 1 。
示例 2:
输入:instructions = [1,2,3,6,5,4]
输出:3
解释:一开始 nums = [] 。
插入 1 ,代价为 min(0, 0) = 0 ,现在 nums = [1] 。
插入 2 ,代价为 min(1, 0) = 0 ,现在 nums = [1,2] 。
插入 3 ,代价为 min(2, 0) = 0 ,现在 nums = [1,2,3] 。
插入 6 ,代价为 min(3, 0) = 0 ,现在 nums = [1,2,3,6] 。
插入 5 ,代价为 min(3, 1) = 1 ,现在 nums = [1,2,3,5,6] 。
插入 4 ,代价为 min(3, 2) = 2 ,现在 nums = [1,2,3,4,5,6] 。
总代价为 0 + 0 + 0 + 0 + 1 + 2 = 3 。
示例 3:
输入:instructions = [1,3,3,3,2,4,2,1,2]
输出:4
解释:一开始 nums = [] 。
插入 1 ,代价为 min(0, 0) = 0 ,现在 nums = [1] 。
插入 3 ,代价为 min(1, 0) = 0 ,现在 nums = [1,3] 。
插入 3 ,代价为 min(1, 0) = 0 ,现在 nums = [1,3,3] 。
插入 3 ,代价为 min(1, 0) = 0 ,现在 nums = [1,3,3,3] 。
插入 2 ,代价为 min(1, 3) = 1 ,现在 nums = [1,2,3,3,3] 。
插入 4 ,代价为 min(5, 0) = 0 ,现在 nums = [1,2,3,3,3,4] 。
插入 2 ,代价为 min(1, 4) = 1 ,现在 nums = [1,2,2,3,3,3,4] 。
插入 1 ,代价为 min(0, 6) = 0 ,现在 nums = [1,1,2,2,3,3,3,4] 。
插入 2 ,代价为 min(2, 4) = 2 ,现在 nums = [1,1,2,2,2,3,3,3,4] 。
总代价为 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 2 = 4 。
提示:
1 <= instructions.length <= 105
1 <= instructions[i] <= 105
解题思路:
用dic存储,然后遍历一下,找出其中比当前值小的和大的。
不过这种遍历算法会超时,需要进一步优化。
代码:
class Solution:
def createSortedArray(self, instructions: List[int]) -> int:
dic = {}
cnt = 0
for i in range(len(instructions)):
num = instructions[i]
big = 0
small = 0
for k, v in dic.items():
if k < num:
small += v
if k > num:
big += v
if num not in dic:
dic[num] = 0
dic[num] += 1
cnt += min(big, small)
cnt %= 1000000007
return cnt
2020年11月28日 -- 双周赛
做对了三道,最后一道有点复杂,没时间写了。
1. 最大重复子字符串 -- 简单
题目链接:https://leetcode-cn.com/problems/maximum-repeating-substring/
题目描述
给你一个字符串 sequence ,如果字符串 word 连续重复 k 次形成的字符串是 sequence 的一个子字符串,那么单词 word 的 重复值为 k 。
单词 word 的 最大重复值 是单词 word 在 sequence 中最大的重复值。如果 word 不是 sequence 的子串,那么重复值 k 为 0 。
给你一个字符串 sequence 和 word ,请你返回 最大重复值 k 。
示例 1:
输入:sequence = "ababc", word = "ab"
输出:2
解释:"abab" 是 "ababc" 的子字符串。
示例 2:
输入:sequence = "ababc", word = "ba"
输出:1
解释:"ba" 是 "ababc" 的子字符串,但 "baba" 不是 "ababc" 的子字符串。
示例 3:
输入:sequence = "ababc", word = "ac"
输出:0
解释:"ac" 不是 "ababc" 的子字符串。
提示:
1 <= sequence.length <= 100
1 <= word.length <= 100
sequence 和 word 都只包含小写英文字母。
解题思路
字符串匹配问题,只不过word可以循环多次。
代码
class Solution:
def maxRepeating(self, sequence: str, word: str) -> int:
len_s = len(sequence)
len_w = len(word)
index = 0
max_cnt = 0
for i in range(len_s):
while i+index < len_s and sequence[i+index] == word[index%len_w]:
index += 1
temp_cnt = index // len_w
if temp_cnt > max_cnt:
max_cnt = temp_cnt
index = 0
return max_cnt
2. 合并两个链表 -- 中等
题目链接:https://leetcode-cn.com/problems/merge-in-between-linked-lists/
题目描述
给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。
请你将 list1 中第 a 个节点到第 b 个节点删除,并将list2 接在被删除节点的位置。
请你返回结果链表的头指针。
示例 1:
输入:list1 = [0,1,2,3,4,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]
输出:[0,1,2,1000000,1000001,1000002,5]
解释:我们删除 list1 中第三和第四个节点,并将 list2 接在该位置。上图中蓝色的边和节点为答案链表。
示例 2:
输入:list1 = [0,1,2,3,4,5,6], a = 2, b = 5, list2 = [1000000,1000001,1000002,1000003,1000004]
输出:[0,1,1000000,1000001,1000002,1000003,1000004,6]
解释:上图中蓝色的边和节点为答案链表。
提示:
3 <= list1.length <= 104
1 <= a <= b < list1.length - 1
1 <= list2.length <= 104
解题思路:
链表操作问题,比较简单。
代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeInBetween(self, list1: ListNode, a: int, b: int, list2: ListNode) -> ListNode:
index = 0
leftNode = list1
rightNode = list1
while index <= b:
if index < a-1:
leftNode = leftNode.next
if index <= b:
rightNode = rightNode.next
index += 1
leftNode.next = list2
list2_tail = list2
while list2_tail.next is not None:
list2_tail = list2_tail.next
list2_tail.next = rightNode
return list1
3. 设计前中后队列 -- 中等
题目链接:https://leetcode-cn.com/problems/design-front-middle-back-queue/
题目描述:
请你设计一个队列,支持在前,中,后三个位置的 push 和 pop 操作。
请你完成 FrontMiddleBack 类:
FrontMiddleBack() 初始化队列。
void pushFront(int val) 将 val 添加到队列的 最前面 。
void pushMiddle(int val) 将 val 添加到队列的 正中间 。
void pushBack(int val) 将 val 添加到队里的 最后面 。
int popFront() 将 最前面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
int popMiddle() 将 正中间 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
int popBack() 将 最后面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回 -1 。
请注意当有 两个 中间位置的时候,选择靠前面的位置进行操作。比方说:
将 6 添加到 [1, 2, 3, 4, 5] 的中间位置,结果数组为 [1, 2, 6, 3, 4, 5] 。
从 [1, 2, 3, 4, 5, 6] 的中间位置弹出元素,返回 3 ,数组变为 [1, 2, 4, 5, 6] 。
示例 1:
输入:
["FrontMiddleBackQueue", "pushFront", "pushBack", "pushMiddle", "pushMiddle", "popFront", "popMiddle", "popMiddle", "popBack", "popFront"]
[[], [1], [2], [3], [4], [], [], [], [], []]
输出:
[null, null, null, null, null, 1, 3, 4, 2, -1]
解释:
FrontMiddleBackQueue q = new FrontMiddleBackQueue();
q.pushFront(1); // [1]
q.pushBack(2); // [1, 2]
q.pushMiddle(3); // [1, 3, 2]
q.pushMiddle(4); // [1, 4, 3, 2]
q.popFront(); // 返回 1 -> [4, 3, 2]
q.popMiddle(); // 返回 3 -> [4, 2]
q.popMiddle(); // 返回 4 -> [2]
q.popBack(); // 返回 2 -> []
q.popFront(); // 返回 -1 -> [] (队列为空)
提示:
1 <= val <= 109
最多调用 1000 次 pushFront, pushMiddle, pushBack, popFront, popMiddle 和 popBack 。
解题思路:
Python类操作及数组插入删除题。
代码:
class FrontMiddleBackQueue:
def __init__(self):
self.data = []
def pushFront(self, val: int) -> None:
self.data.append(val)
cnt = len(self.data) - 1
while cnt >= 1:
self.swap(cnt-1, cnt)
cnt -= 1
#print(self.data)
def pushMiddle(self, val: int) -> None:
self.data.append(val)
cnt = len(self.data) - 1
while cnt > (len(self.data)+1)//2 - 1:
self.swap(cnt-1, cnt)
cnt -= 1
#print(self.data)
def pushBack(self, val: int) -> None:
self.data.append(val)
#print(self.data)
def popFront(self) -> int:
if len(self.data) == 0:
return -1
rst = (self.data)[0]
self.data = (self.data)[1:]
#print(self.data)
return rst
def popMiddle(self) -> int:
if len(self.data) == 0:
return -1
cnt = (len(self.data)+1)//2 - 1
while cnt < len(self.data)-1:
self.swap(cnt, cnt+1)
cnt += 1
rst = (self.data)[-1]
self.data = (self.data)[:-1]
#print(self.data)
return rst
def popBack(self) -> int:
if len(self.data) == 0:
return -1
rst = (self.data)[-1]
self.data = (self.data)[:-1]
#print(self.data)
return rst
def swap(self, a, b):
temp = (self.data)[a]
(self.data)[a] = (self.data)[b]
(self.data)[b] = temp
# Your FrontMiddleBackQueue object will be instantiated and called as such:
# obj = FrontMiddleBackQueue()
# obj.pushFront(val)
# obj.pushMiddle(val)
# obj.pushBack(val)
# param_4 = obj.popFront()
# param_5 = obj.popMiddle()
# param_6 = obj.popBack()