LeetCode算法刷题——5月

2022年 5月

5月4号

118题 杨辉三角
思路:
每一行的开头和结尾都是1。其他值都是上一行上一列和上一行当前列的和。

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        yanghui = list()

        for i in range(numRows):
            row = list()
            for j in range(0,i+1):
                if j == 0 or j == i:
                    row.append(1)
                else:
                    row.append(yanghui[i-1][j-1] + yanghui[i-1][j])
            yanghui.append(row)
        
        return yanghui

36题 有效的数独
思路:
重点在于判断board[i][j]在第i行,和第j列,还有第int(i/3) int(j/3)个小格子里面是否出现过两次以上。

class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        rows = [[0] * 9 for _ in range(9)]
        cols = [[0] * 9 for _ in range(9)]
        subboxs = [[[0] * 9 for _ in range(3)] for _ in range(3)]
        for i in range(9):
            for j in range(9):
                c = board[i][j]
                if c != '.':
                    c = int(c) - 1
                    rows[i][c] += 1
                    cols[j][c] += 1
                    subboxs[int(i/3)][int(j/3)][c] += 1
                    if rows[i][c] > 1 or cols[j][c] > 1 or subboxs[int(i/3)][int(j/3)][c] > 1:
                        return False
        return True

5月5号
73 矩阵置零
思路:
将矩阵中值为0的行和列的坐标分别进行标记,存储到两个列表中,然后遍历,进行赋值为0的操作。自己的笨办法

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        row = len(matrix)
        col = len(matrix[0])
        hang = []
        lie = []
        for i in range(row):
            for j in range(col):
                if matrix[i][j] == 0:
                    hang.append(i)
                    lie.append(j)
        for i in hang:
            for j in range(col):
                matrix[i][j] = 0
        for j in lie:
            for i in range(row):
                matrix[i][j] = 0
        return matrix

144 二叉树前序遍历
自己的写办法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        ans = []
        if root == None:
            return ans 
        
        def bianli(ans,root):
            if root == None:
                return ans
            ans.append(root.val)
            bianli(ans,root.left)
            bianli(ans, root.right)
        bianli(ans, root)
        return ans

94 二叉树的中序遍历
自己的写办法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        ans = []
        if root == None:
            return ans 
        
        def bianli(ans,root):
            if root == None:
                return ans
            bianli(ans,root.left)
            ans.append(root.val)
            bianli(ans, root.right)
        bianli(ans, root)
        return ans

145 二叉树的后续遍历
自己的写办法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        ans = []
        if root == None:
            return ans 
        def bianli(ans,root):
            if root == None:
                return ans
            bianli(ans,root.left)
            bianli(ans, root.right)
            ans.append(root.val)
        bianli(ans, root)
        return ans

5月6日
387 字符串中的第一个唯一字符
思路:
用字典存储每个字符出现的次数,遍历字符串,找出第一个出现一次的字符。

class Solution(object):
    def firstUniqChar(self, s):
        """
        :type s: str
        :rtype: int
        """
        frequency = collections.Counter(s)
        for i, ch in enumerate(s):
            if frequency[ch] == 1:
                return i
        return -1

102 二叉树的层序遍历
思路:
使用广度优先搜素(BFS)只能得到一维的输出数组,没办法区分每一层的元素。因此需要把每一层的节点遍历完之后再进入下一层开始遍历数据。引入一个队列专门存放节点,每一次迭代都将队列的长度存入一个变量,即为该层的节点数。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        ret = []
        if root == None:
            return ret
        queue = []
        queue.append(root)
        while len(queue) != 0:
            level = []
            size = len(queue)
            for i in range(1, size +1):
                node = queue.pop(0)
                level.append(node.val)
                if node.left != None:
                    queue.append(node.left)
                if node.right != None:
                    queue.append(node.right)
            ret.append(level)
        return ret

5月9日

136 只出现一次的数字
思路:
可以使用哈希表记录每个数字出现的次数。也可以判断第i个数字是否在数组中出现第二次。自己写的方法

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        # fre = collections.Counter(nums)
        for i in range(len(nums)):
            if nums[i] not in nums[i+1:] and nums[i] not in nums[:i]:
                return nums[i]

方法二,字典记录数字出现次数

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        fre = collections.Counter(nums)
        for i in nums:
            if fre[i] == 1:
                return i

70 爬楼梯
思路:爬到第i层的方法数是爬到第i-1层与i-2层方法数的和,因此用递归的方法求解

class Solution:
    def climbStairs(self, n: int) -> int:
        if n < 3:
            return n
        p = 1
        q = 2
        for i in range(3, n+1):
           number = q + p
           p = q
           q = number

        return number

746 使用最小花费爬楼梯
思路:
在第0层、第1层花费为0,当i>2时,爬到第i层的花费是爬到第i-2层的花费加上i-2层的花费或者是爬到i-1层的花费加上i-1层的花费,两者取其最小值即为爬到第i层的最小花费。
注意爬到数组中最后一个层数时并不是到楼顶,而是要再爬上去一层才到楼顶,因此循环中用n+1,创建的数组dp长度也是n+1,也就是说到达数组最后一个数字代表的楼层还没有到楼顶,此时距离楼顶还差一步。

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        dp = [0] * (n+1)
        for i in range(2, n + 1):
            dp[i] = min(dp[i-2] + cost[i-2], dp[i-1] + cost[i- 1])
        return dp[n]

198 打家劫舍
思路
不能连续偷两间靠近的房子,就是第i个房间的最大收益是在第i-2个房间+第i个房间的钱和第i-1个房间的总收益之间取最大值。

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0] * n
        if n < 3:
            return max(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, n):
            dp[i] = max(dp[i-2] + nums[i], dp[i-1])
        return dp[n-1]

5月11号
152 乘积最大子数组
思路:
因为数组中有负数存在,有可能出现负负得正使得乘积最大,所以在考虑正数的同时也要考虑负数。

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
       n = len(nums)
       maxF = [1] * n
       minF = [1] * n
       maxF[0] = minF[0] = nums[0]
       for i in range(1, n):
           maxF[i] = max(maxF[i - 1] * nums[i], max(nums[i], minF[i - 1] * nums[i]))
           minF[i] = min(minF[i - 1] * nums[i], min(nums[i], maxF[i- 1] * nums[i]))
       ans = maxF[0]
       for i in range(1, n):
            ans = max(ans, maxF[i])
        
       return ans

5月12号
213 打家劫舍Ⅱ
思路:
房屋首尾相连,因此偷了第一间房,最后一间房就不能偷,则此时只考虑前n-1间房屋的最大收益。当偷了最后一间房时,只考虑2~n房子的最大收益,因此两种情况用相同的方法求最大收益后再比较大小得到n间房屋的最大偷窃数。

class Solution:
    def rob(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0] * n
        dp[0] = nums[0]
        if n<3:
            return max(nums)
        dp[1] = max(nums[0], nums[1])
        for i in range(2, n-1):
            dp[i] = max(dp[i-2] + nums[i], dp[i - 1])
        
        fp = [0] * n
        fp[1] = nums[1]
        fp[2] = max(nums[1], nums[2])
        for i in range(3, n):
            fp[i] = max(fp[i-2] + nums[i], fp[i - 1])
        return max(dp[n-2], fp[n-1])


1014 最佳观光组合
思路:
values[ i ] + i +values[ j ] - j 可以拆分成两部分,对于第j个景点,要想找到最佳组合,就是找出
values[ i ] + i的最大值,即 values[ j ] − j在j点是固定的。所以依次遍历j-1个景点来找到j景点以前的最佳组合。

class Solution(object):
    def maxScoreSightseeingPair(self, values):
        """
        :type values: List[int]
        :rtype: int
        """
        ans = 0
        mx = values[0] + 0
        for i in range(1, len(values)):
            ans = max(ans, mx + values[i] - i)
            mx = max(mx, values[i] + i)
        return ans

121 买卖股票的最佳时机
思路:
第i天的收益是在第j天以最低价买入在第j+t天以最高价卖出,其中j < i,
j + t<=i。自己写的方法。

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        profit = 0
        s = 10000
        for i in range(len(prices)):
            s = min(s, prices[i])
            profit = max(profit, prices[i] - s)

        return profit

122 买卖股票的最佳时机Ⅱ
思路:
没理解

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        ans = 0
        n = len(prices)
        for i in range(1, n):
            ans += max(0, prices[i]- prices[i-1])
        return ans

309 最佳股票买卖时机含冷冻期
思路:
将第i天的状态进行分类讨论,运用动态规划实现每天的最大收益。

class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        if not prices:
           return 0
        
        n = len(prices)
        f = [[-prices[0], 0, 0]] + [[0] * 3 for _ in range(n - 1)]
        # f[i][0]: 手上持有股票的最大收益
        # f[i][1]: 手上不持有股票,并且处于冷冻期的累计最大收益
        # f[i][2]:手上不持有股票, 并且不在冷冻期的累计最大收益
        for i in range(1, n):
            f[i][0] = max(f[i - 1][0], f[i - 1][2] - prices[i])
            f[i][1] = f[i - 1][0] + prices[i]
            f[i][2] = max(f[i - 1][1], f[i - 1][2])

        return max(f[n-1][1], f[n - 1][2])

714 买卖股票的最佳时机含手续费
思路:
找出第i天的两种状态,不持有股票的最大收益和持有股票的最大收益。持有股票的最大收益,可能是前一天就持有股票,也可能是今天才买入股票,二者取其大。不持有股票的最大收益可能是昨天就不持有股票,可能是今天卖出股票,二者取其大。

class Solution(object):
    def maxProfit(self, prices, fee):
        """
        :type prices: List[int]
        :type fee: int
        :rtype: int
        """
        n = len(prices)
        sell = 0
        buy = -prices[0]
        for i in range(1, n):
            sell, buy = max(sell, buy + prices[i] - fee), max(buy, sell - prices[i])
        return sell


        

5月18号

15 三数之和
思路:
先排序,然后使用多层遍历。当第一个数固定时,第二个数增大,第三个数就要减小(第三个数从数组末尾开始向前遍历)。使用三指针

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        n = len(nums)
        nums.sort()
        ans = []
        for first in range(n):
            if first > 0 and nums[first] == nums[first - 1]:
                continue
            third = n - 1
            target = -nums[first]
            for second in range(first + 1, n):
                if second > first + 1 and nums[second] == nums[second - 1]:
                    continue
                while second < third and nums[second] + nums[third] > target:
                    third -= 1
                if second == third:
                    break
                if nums[second] + nums[third] == target:
                    ans.append([nums[first], nums[second], nums[third]])
        return ans

75 颜色分类
思路:
使用冒泡排序

class Solution(object):
    def sortColors(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        for i in range(n):
            for j in range(i+1, n):
                if nums[i] > nums[j]:
                    nums[i], nums[j] = nums[j], nums[i]
        return nums

187 重复的DNA序列
思路:
用哈希表存储每一个长度为10 的字符串,并统计出现次数,只返回出现两次的子字符串。

class Solution(object):
    def findRepeatedDnaSequences(self, s):
        """
        :type s: str
        :rtype: List[str]
        """
        n = len(s)
        ans = defaultdict(int)
        out = list()
        for i in range(n-9):
            sub = s[i:i+10]
            ans[sub] += 1
            if ans[sub] == 2:
                out.append(sub)
        return out

763 划分字母区间
思路:
贪心算法,将每个字母在字符串中出现的最后位置的下标存储起来,然后依次遍历字符串,当前字符的下标和其最后依次出现的下标取其大,当它们相等时,则就是最小划分区间,然后再继续遍历之后的字符串。

class Solution(object):
    def partitionLabels(self, s):
        """
        :type s: str
        :rtype: List[int]
        """
        last = [0] * 26
        for i, ch in enumerate(s):
            last[ord(ch) - ord("a")] = i
        
        partition = list()
        start = end = 0
        for i, ch in enumerate(s):
            end = max(end, last[ord(ch) - ord("a")])
            if i == end:
                partition.append(end - start + 1)
                start = end + 1
        
        return partition

5月24日
2 两数相加
思路:
同时遍历两个数组,特别要注意进位,最后如果有进位就放在循环外面添加一个节点。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        head = None
        he = None
        out = 0
        while l1 or l2:
            a = 0
            b = 0
            if l1:
                a = l1.val
                l1 = l1.next
            if l2:
                b = l2.val
                l2 = l2.next
            ans = a + b + out
            if head == None:
                head = he = ListNode(ans % 10)
            else:
                he.next = ListNode(ans % 10)
                he = he.next
            out = (a+b+out) // 10 
        if out > 0:
            he.next = ListNode(out)
        return head

5月25日
56 合并区间
思路:
先对列表里面的区间进行排序,然后依次遍历排序后的每一个区间,若区间的结尾值比后面区间的开头值大,则合并成新的区间,新的区间的结尾值在两个区间的结尾值中取大的。若区间的结尾值小于后面区间的开头值,则不合并,将当前区间添加到新的存储列表中。

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[List[int]]
        :rtype: List[List[int]]
        """
        intervals.sort(key = lambda x : x[0])
        ans = list()

        for i in intervals:
            #如果列表为空,或者当前区间与上一区间不重合,直接添加
            if not ans or ans[-1][1] < i[0]:
                ans.append(i)
            else:
                # 否则的话,与上一区间进行合并
                ans[-1][1] =max(ans[-1][1], i[1])
        return ans


5月26日
740 删除并获得点数
思路:
首先对数组中的相同元素进行求和,选择数据中最大的元素再加一,作为新的数组ans的长度,初始化新数组中元素为0.然后依次遍历原数组中的元素并作为新数组的下标,记录该元素的和。然后就可以利用标准的动态规划来求解最大值,方式和打家劫舍题目一样。

class Solution(object):
    def deleteAndEarn(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = max(nums)
        ans = [0] * (n+1)
        for i in nums:
            ans[i] += i 
        r = ans[0]
        p = max(ans[0], ans[1])
        for i in range(2,len(ans)):
            s = max(p, r+ans[i])
            r = p
            p = s
        return p



5月27日
48 旋转图像
思路:
不会写

class Solution(object):
    def rotate(self, matrix):
        """
        :type matrix: List[List[int]]
        :rtype: None Do not return anything, modify matrix in-place instead.
        """
        n = len(matrix)
        for i in range(n // 2):
            for j in range((n + 1) // 2):
                matrix[i][j], matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1] = matrix[n - j - 1][i],matrix[n - i - 1][n - j -1], matrix[j][n - i -1], matrix[i][j]

5月30日
53 最大子数组和
思路:
自己写的代码。

class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        pre = 0
        ans = nums[0]
        for i in nums:
            pre = max(pre + i, i)
            ans = max(ans, pre)
        return ans

217 存在重复元素
思路:
利用集合不包含重复元素的特性和列表进行长度对比。

class Solution(object):
    def containsDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        return not (len(set(nums)) == len(nums))

5月31号
55 跳跃游戏
思路:
设定一个可以达到的最远距离z,逐个遍历数组的元素时,同时更新z,若出现最远到达距离大于等于数组长度则返回True,退出循环后就返回False。

class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        z = 0
        for i in range(len(nums)):
            if i <= z:
                z = max(z, i + nums[i])
                if z >= len(nums)-1:
                    return True
        return False 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值