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)

猜你喜欢

转载自blog.csdn.net/weixin_44604541/article/details/106853934
今日推荐