【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()

返回目录

posted @ 2020-11-08 21:35  Yanqiang  阅读(626)  评论(0编辑  收藏  举报