leetcode刷題記錄411-420 python版

前言

繼續leetcode刷題生涯
這裏記錄的都是筆者覺得有點意思的做法
參考了好幾位大佬的題解,尤其是powcai大佬和labuladong大佬,感謝各位大佬

412. Fizz Buzz

class Solution:
    def fizzBuzz(self, n: int) -> List[str]:
        res = []
        for i in range(1, n+1):
            if i % 3 == 0 and i % 5 == 0:
                res.append("FizzBuzz")
            elif i % 3 == 0:
                res.append("Fizz")
            elif i % 5 == 0:
                res.append("Buzz")
            else:
                res.append(str(i))
        return res

413. 等差數列劃分

# 滑動窗口
class Solution:
    def numberOfArithmeticSlices(self, A: List[int]) -> int:
        if len(A) < 3: return 0
        left = 0
        right = 2
        res = 0
        while right < len(A):
            if A[right] - A[right-1] == A[left+1] - A[left]:
                res += right - left -1
                right += 1
            else:
                left = right -1
                right = left +2
        return res
# dp
class Solution:
    def numberOfArithmeticSlices(self, A: List[int]) -> int:
        # 至少3個才叫數列,纔有等差這種概念
        # f[i]表示到i元素爲止的等差數列個數,差(d)是一樣的
        # A[i] - A[i-1]等於A[i-1] - A[i-2],則f[i] = f[i-1] + 1
        # 從左往右更新
        n = len(A)
        if n < 3: return 0
        f = [0] * n
        # f[0], f[1], f[2]
        for i in range(2, n):
            if A[i] - A[i - 1] == A[i - 1] - A[i - 2]:
                f[i] = f[i - 1] + 1
        return sum(f)

414. 第三大的數

# 暴力
class Solution:
    def thirdMax(self, nums: List[int]) -> int:
        nums = sorted(set(nums))
        if len(nums) < 3: return nums[-1]
        return nums[-3]
# 三個數
class Solution:
    def thirdMax(self, nums: List[int]) -> int:
        first = second = third = float('-inf')
        for num in nums:
            if num > third:  # 通過第3關
                if num < second:
                    third = num
                elif num > second:  # 通過第2關
                    if num < first:
                        third = second
                        second = num
                    elif num > first:  # 通過第1關
                        third = second
                        second = first
                        first = num
        if third == float('-inf'):
            return first
        else:
            return third

415. 字符串相加

class Solution:
    def addStrings(self, num1: str, num2: str) -> str:
        res = ""
        i, j, carry = len(num1) - 1, len(num2) - 1, 0
        while i >= 0 or j >= 0:
            n1 = int(num1[i]) if i >= 0 else 0
            n2 = int(num2[j]) if j >= 0 else 0
            tmp = n1 + n2 + carry
            carry = tmp // 10
            res = str(tmp % 10) + res
            i, j = i - 1, j - 1
        return "1" + res if carry else res

416. 分割等和子集

# 暴力
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        n = len(nums)
        target = sum(nums)
        if target % 2: return False
        target //= 2
        dic = set() #用於儲存當前元素和的可能情況
        dic.add(0)
        for i in range(n):
            dic_tmp = set() #用於存儲經過這一步操作,增加的元素和狀態
            for j in dic:
                tmp = j + nums[i]
                if tmp == target:
                    return True
                if tmp < target:
                    dic_tmp.add(tmp)
            for j in dic_tmp:
                dic.add(j)
        return False
# 揹包問題
class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        avg, mod = divmod(sum(nums), 2)
        # 不能被2整除
        if mod != 0: return False
        n = len(nums)
        dp = [[1] + [0] * avg for _ in range(n + 1)]
        for i in range(1, n + 1):
            for j in range(1, avg + 1):
                if j - nums[i - 1] >= 0:
                    dp[i][j] = dp[i - 1][j - nums[i - 1]] | dp[i - 1][j]
        return dp[-1][-1]

417. 太平洋大西洋水流問題

# 從邊緣開始的dfs
class Solution:
    def pacificAtlantic(self, matrix: List[List[int]]) -> List[List[int]]:
        if not matrix or not matrix[0]: return []
        res1 = set() #流向太平洋的位置
        res2 = set() #流向大西洋的位置
        row = len(matrix)
        col = len(matrix[0])
        # 從邊界開始的dfs
        def dfs(i, j, cur, res):
            res.add((i, j))
            for x, y in [[1, 0], [-1, 0], [0, 1], [0, -1]]:
                tmp_i = i + x
                tmp_j = j + y
                if 0 <= tmp_i < row and 0 <= tmp_j < col and matrix[i][j] <= matrix[tmp_i][tmp_j] and (tmp_i, tmp_j) not in res:
                    dfs(tmp_i, tmp_j, matrix[i][j], res)
        # 太平洋
        for i in range(row):
            dfs(i, 0, 0, res1)
        # 太平洋
        for j in range(col):
            dfs(0, j, 0, res1)
        # 大西洋
        for i in range(row):
            dfs(i, col - 1, 0, res2)
        # 大西洋
        for j in range(col):
            dfs(row - 1, j, 0, res2)
        return res1 & res2

419. 甲板上的戰艦

# 甲板上哪來的戰艦。。。
class Solution:
    def countBattleships(self, board: List[List[str]]) -> int:
        row = len(board)
        col = len(board[0])
        res =  0
        for i in range(row):
            for j in range(col):
                if board[i][j] == ".":
                    continue
                if i > 0 and board[i - 1][j] == "X": 
                    continue
                if j > 0 and board[i][j - 1] == "X": 
                    continue
                res += 1
        return res

420. 強密碼檢驗器

class Solution:
    def strongPasswordChecker(self, s: str) -> int:
        has_lower, has_upper, has_num = 0, 0, 0
        for ch in s:
            if ch.isnumeric(): has_num = 1
            elif ch.isupper(): has_upper = 1
            elif ch.islower(): has_lower = 1
        if len(s) < 6:
            # 總長度不到6時候,肯定至少補一次字符,補自字符同時就可以
            # 把連續的3個字符打斷,最長只可能5個連續字符,插入一次字符
            # 就可以完成分割,所以只需要關注字符種類夠不夠,假設缺少Ncat
            # 種字符,那就需要添加max(len(s) - 6, Ncat)個字符滿足要求
            return max(3 - has_num - has_upper - has_lower, 6 - len(s))
        elif len(s) <= 20:
            '''
            這種情況不需要考慮長度問題,長度已經符合條件了,對於破壞三個連續字符這個操作而言,修改
            字符是開銷最小的,連續n個字符連續,只需要每3個把最後一個字符修改成不一樣的字符即可,總共
            修改n//3次,而且還不會影響字符串長度,對於字符類型不足的問題,也可以通過修改字符來滿足條件
            所以修改字符這個操作可以同時對3字符連續和字符種類不足兩種錯誤進行修正,且不會造成字符串
            長度問題,假設連續字符問題總共需要修改Nseq次滿足要求,字符種類不足問題總共需要修改Ncat次
            才能滿足要求,那最佳修改方案就是max(Nseq, Ncat)次修改滿足題目題目要求
            '''
            i = 0
            Nseq = 0
            while i < len(s):
                j = i
                while j < len(s) and s[j] == s[i]:
                    j += 1

                if j - i >= 3:
                    Nseq += (j - i) // 3
                i = j
            return max(3 - has_num - has_upper - has_lower, Nseq)
        else:
            '''
            對於字符串長度大於20的情況,最少會有len(s) - 20 次刪除的操作,這些刪除操作是節約不掉的
            刪除不可能解決字符類型不足的問題但是可能解決3個連續字符的問題,所以刪除時候儘量讓3個連續
            字符問題多得到解決,這樣在字符串長度減少到20個時候,繼續解決3個連續字符的問題和字符種類
            不足的問題時候,剩下操作次數就最少
            考慮n個連續的字符,n%3 == 0 的情況下, 只要刪掉尾巴上的字符,就可以解決一個3字符連續問題,
            轉變成n%3 == 2的狀態,
            n%3 == 1 的情況,需要刪除2個字符才能減少一個3字符連續問題,轉變成n%3 == 0狀態
            n%3 == 2時候,需要刪除3個字符才能減少一個三字符連續問題,轉變成n%3 == 1狀態
            所以對於連續3字符問題,需要按照這個優先級來進行處理,直到剩餘字符爲20個
            刪除字符時候一定能找到不會讓字符種類數減少的方式進行刪除,所以不需要考慮字符類型不足的問題
            等字符數量減到20個的時候,再通過修改字符的方式來和3字符連續的問題一起解決                             
            '''
            from queue import PriorityQueue
            que = PriorityQueue()
            i = 0
            while i < len(s):
                j = i
                while j < len(s) and s[j] == s[i]:
                    j += 1
                if j - i >= 3:
                    que.put(((j - i) % 3, j - i))
                i = j
            del_cnt = len(s) - 20
            for _ in range(del_cnt):
                if que.empty():
                    break
                mod, val = que.get()
                if val > 3:
                    if mod == 0:
                        que.put((2, val - 1))
                    elif mod == 1:
                        que.put((0, val - 1))
                    else:
                        que.put((1, val - 1))
            # 字符剩餘20個時候,繼續解決3字符連續問題和種類不足問題
            Nseq = 0
            while not que.empty():
                _, val = que.get()
                Nseq += val // 3
            return del_cnt + max(3 - has_upper - has_lower - has_num, Nseq)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章