1. 程式人生 > 其它 >【leetcode】周賽記錄

【leetcode】周賽記錄

技術標籤:字串列表資料結構演算法java

目錄:

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

返回目錄