LeetCode卡片探索-中级算法


LeetCode上知识卡片之 中级算法的刷题记录

数组和字符串

三数之和

把数组排序后,遍历数组,每次固定当前元素,然后用双指针再后续数组里面搜索与它相加为0的元素组合。

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        n=len(nums)
        res=[]
        nums.sort()
        for i in range(n):
            if nums[i] > 0:
            #因为排序了,遍历到大于0的数不可能有结果
                return res
            #重复元素只要第一个
            if(i>0 and nums[i]==nums[i-1]):
                continue
            l = i + 1
            r = n - 1
            while l<r:
                if nums[i] + nums[l] +nums[r] == 0:
                    res.append( [nums[i] , nums[l] , nums[r]])
                    #两个while过滤掉重复元素
                    while(l<r and nums[l]==nums[l+1]):
                        l += 1
                    while(l<r and nums[r]==nums[r-1]):
                        r -= 1
                    l -= 1
                    r -= 1
                elif(nums[i]+nums[l]+nums[r]>0):
                    r-=1
                else:
                    l+=1
        return res

矩阵置零

要求原地变换,所以用行列的第一个元素作为标记,来表示该行该列是否要变为0

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        #记录第一列
        is_col = False
        R = len(matrix)
        C = len(matrix[0])
        
        for i in range(R):
            #只要第一列出现0,标记为True
            if matrix[i][0] == 0:
                is_col = True
            for j in range(1, C):
                if matrix[i][j]  == 0:
                    matrix[0][j] = 0
                    matrix[i][0] = 0
        
        
        #根据行列开头标志改变元素
        for i in range(1, R):
            for j in range(1, C):
                if not matrix[i][0] or not matrix[0][j]:
                    matrix[i][j] = 0
        
        #单独处理第一列和第一行
        if matrix[0][0] == 0:
            for j in range(C):
                matrix[0][j] = 0
    
        if is_col:
            for i in range(R):
                matrix[i][0] = 0

字母异位词分组

本质上是要我们维护一个字典,字母异位词要对应着同一个key,我们可以把字符串排序后当做key,可以把字母计数结果当作key。

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        ans = collections.defaultdict(list)
        #默认字典,索引不在key中,就新建一个空list对应
        for s in strs:
            count = [0] * 26
            for c in s:
                count[ord(c) - ord('a')] += 1
            ans[tuple(count)].append(s)
        return list(ans.values())

无重复字符的最长子串

很明显要使用滑动窗口的思想,一边滑动一边判断就可。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s:
            return 0
        l = r = out = 0
        #窗口内字符
        pattern = set()
        while r < len(s):
            if s[r] not in pattern:
                pattern.add(s[r])
                out = max(out,r-l+1)
                r += 1
            else:
                pattern.remove(s[l])
                l += 1
        return out

最长回文子串

回文子串可以分解为对应的子问题,所以采用动态规划思想。要注意的是两个循环的写法,要保证子问题的求解顺序,不能先出现依赖还没求解子问题的高阶问题。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        dp = [[False] * n for _ in range(n)]
        ans = ""
        # 枚举子串的长度 l+1
        for l in range(n):
        #子串起始位置
            for i in range(n):
                j = i + l
                if j >= len(s):
                    break
                if l == 0:
                    dp[i][j] = True
                elif l == 1:
                    dp[i][j] = (s[i] == s[j])
                else:
                    dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
                if dp[i][j] and l + 1 > len(ans):
                    ans = s[i:j+1]
        return ans

递增的三元子序列

问题只要求判断存在与否就可,我们可以用两个变量存储当前的最小值和次小值,如果新遍历到的值大于次小值,那么已经构成了一个三元组,可以返回True;如果不大于,则根据具体值更新最小次小值即可。

class Solution:
    def increasingTriplet(self, nums: List[int]) -> bool:
        n1 = float('inf')
        n2 = float('inf')
        for num in nums:
            if num <= n1:
                n1 = num
            elif num <= n2:
                n2 = num
            else:
                return True
        return False

链表

两数相加

模拟字符串数字加法即可

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        res  = p = ListNode()
        carry = 0
        while l1 or l2 or carry:
        #优化边界判断
            x = l1.val if l1 else 0
            y = l2.val if l2 else 0
            p.next = ListNode((x+y+carry)%10)
            p = p.next
            carry = (x+y+carry)//10
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next
        return res.next

奇偶链表

用两个指针分别记录奇链表尾和偶链表头,再用一个指针遍历原链表(顺便充当偶链表尾)即可

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head :
            return head
        p1 = head
        p2 = p = head.next
        #P1,P2分别为奇偶链表尾
        while p2 and p2.next:
            p1.next = p2.next
            p1 = p1.next
            p2.next = p2.next.next
            p2 = p2.next
        p1.next = p
        return head

相交链表

把两个链表分别前后顺序拼接起来,如果是相交的,遍历的时候一定会到相同的节点(走过相同的路)。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        p1 = headA
        p2 = headB
        while p1 != p2:
            p1 = p1.next if p1 else headB
            p2 = p2.next if p2 else headA
        #如果两个链表不相交的话,p1和p2都是空值
        return p1

树和图

中序遍历二叉树

递归的解法很容易写出

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        def help(root,res):
            if not root:
                return
            help(root.left,res)
            res.append(root.val)
            help(root.right,res)
        help(root,res)
        return res

迭代需要考虑访问顺序

class Solution:
    def inorderTraversal(self, root: TreeNode) -> List[int]:
        res = []
        s = []
        x = root
        while s or x:
            while x:
                s.append(x)
                x = x.left
                #左子树全部进栈了
            #接下来弹出的就是根节点 
            x = s.pop()
            res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值