高频Leetcode题库 - 前进 一格

219 阅读5分钟

简单题(2道)

20.有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
   左括号必须用相同类型的右括号闭合。
   左括号必须以正确的顺序闭合。
 示例 1:
   输入:s = "()"
   输出:true
  • 解题思路

解题思路

  • 代码实现
class Solution:
    def isValid(self, s: str) -> bool:
        n = len(s)
        # 奇数个直接判错
        if n % 2 != 0: return False
        # 模仿栈
        res = []
        # 通过右括号定位左括号
        dic = {")": "(", "}": "{", "]": "["}
        for elem in s:
            if elem in dic.values():
                res.append(elem)
            elif elem in dic.keys():
                if len(res) == 0 or res[-1] != dic[elem]:
                    return False
                res.pop()
            else:
                return False
        # 排除左括号有过多的情况
        return len(res) == 0

1154. 一年中的第几天

给你一个字符串 `date` ,按 `YYYY-MM-DD` 格式表示一个现行公元纪年法日期。返回该日期是当年的第几天。

示例 1:
  输入: date = "2019-01-09"
  输出: 9
  解释: 给定日期是2019年的第九天。
  • 解题思路

解题思路

  • 代码实现
class Solution:
    def dayOfYear(self, date: str) -> int:
        year, month, day = [int(x) for x in date.split("-")]
        mapping = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30]
        # YEAR == 闰年 ?
        if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0):
            mapping[2] = 29
        # 月份
        dayOfCurrentYear += sum(mapping[0: month])
        # + DAY
        dayOfCurrentYear = day
        return dayOfCurrentYear

中等题(2道)

165. 比较版本号

给你两个版本号 version1 和 version2 ,请你比较它们。

版本号由一个或多个修订号组成,各修订号由一个 '.' 连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.330.1 都是有效的版本号。

比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订号 1 和修订号 001 相等 。如果版本号没有指定某个下标处的修订号,则该修订号视为 0 。例如,版本 1.0 小于版本 1.1 ,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 010 < 1 。

返回规则如下:
    如果 version1 > version2 返回 1,
    如果 version1 < version2 返回 -1,
    除此之外返回 0。

示例 1:
    输入:version1 = "1.01", version2 = "1.001"
    输出:0
    解释:忽略前导零,"01""001" 都表示相同的整数 "1"
  • 解题思路

解题思路

1.由于只包含 数字 和 ".",所以按照 . 分隔出每一个元素,按照从左到右进行比较。
2.长度更短的版本值以0进行填充比较
  • 代码实现
def compareVersion(self, version1: str, version2: str) -> int:
    # zip默认按照最短长度生成,zip_loingest按照最长长度生成,以 fillvalue 进行补位
    for v1, v2 in zip_longest(version1.split("."), version2.split("."), fillvalue="0"):
        x, y = int(v1), int(v2)
        if x != y:
            return 1 if x > y else -1
    return 0

143. 重排链表

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例1:
    输入: head = [1,2,3,4]
    输出: [1,4,2,3]
  • ① 解题思路

解题思路

1.将所有的节点Node按顺序添加到数组中

解题思路

2.双指针交替更新节点的next指针

线性表: 将所有的Node按顺序添加到数组中,按照双指针交替进行next赋值
  • ① 代码实现
class Solution: 
    def reorderList(self, head: Optional[ListNode]) -> None: 
        if not head: return
        res = list() 
        node = head 
        # 将node按照顺序添加到数组中
        while node: 
            res.append(node) 
            node = node.next 
        # 双指针
        i, j = 0, len(res) - 1 
        while i < j: 
            # 模拟第1个node情况: 先 index = 1, 后 index = n - 1
            res[i].next = res[j] 
            # 获取 顺序index = 2的元素
            i += 1 
            # 当指向同一个元素时,不需要处理该元素的next指向
            if i == j: break 
            # 模拟index = n -1 的情况, (n-1) -> 2 ->...
            res[j].next = res[i] 
            # 获取 顺序index = n -2 的元素
            j -= 1 
        # 当获取中间元素时
        vec[i].next = None
  • ② 解题思路
(1) -> (n - 1) -> (2) -> (n - 2) -> .. 
就像 中间分开,左边按照顺序 和 右边按照倒序 交替的插入
例:
 A -> B -> C -> D -> E
左边: A -> B -> C
右边: D -> E

① 先拿到中间节点C:通过fast and slow 双指针
② 再将right右边区域进行倒序排列
③ 依次更新next指针
  • ② 代码实现
class Solution:
    def reorderList(self, head: Optional[ListNode]) -> None:
        # 交替更新每个元素的next指向
        def mergeList(left, right):
            while left and right:
                leftTemp = left.next 
                rightTemp = right.next 

                left.next = right
                left = leftTemp

                right.next = left
                right = rightTemp

        # 将右边区域倒序
        def reversedList(head):
            cur = head
            while cur and cur.next:
                node = cur.next 
                cur.next = node.next 
                node.next = head
                head = node
            return head

        
        # 找到中间节点
        def findMiddleNode(head):
            slow, fast = head, head
            while fast.next and fast.next.next:
                slow = slow.next 
                fast = fast.next.next 
            return slow
        
        # 1.中间节点
        middle = findMiddleNode(head)
        # 2.右侧元素倒序
        rightNode = reversedList(middle.next)
        middle.next = None
        # 左侧元素
        leftNode = head
        # 3.合并
        mergeList(leftNode, rightNode)

困难 (1道)

25. K 个一组翻转链表

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例1:
    输入: head = [1,2,3,4,5], k = 2
    输出: [2,1,4,3,5]
  • 解题思路

解题思路

1.将所有的节点Node按顺序添加到数组中

解题思路

2.区域内翻转,记录区域前一个元素pre以及后一个元素next

线性表:数组按顺序记录所有的Node,每K个元素进行交换
需要注意的是:如果该区域内Node数量 < K,那么不需要处理直接保留返回即可

① [0, K) k个元素内部逆序
② 获取逆序后的 newHead 和 newTail,将
     pre.next = newHead 
     newTail.next = oldTailNext
  • 代码实现

① 线性表

class Solution: 
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: 
        if not head: return
        res = []
        # 按序记录所有的节点
        while head: 
            res.append(head) 
            head = head.next 
        i = 0 
        prev = None 
        while i < len(res): 
            # 当不满足 K 个元素时,无需处理
            if (i + k - 1) >= len(res): 
                if prev: prev.next = res[i] 
                break
            right = i + k - 1 
            cur = res[right] 
            for idx in range(right, i, -1): 
                res[idx].next = res[idx - 1] 
            if prev: prev.next = cur # 拿到上次的最后一个元素 
            prev = res[i] 
            prev.next = None 
            # 下一个开始的位置 
            i = i + k
       return res[k - 1]

② 无需记录所有元素,按照获取该区域内新的head、tail 方式进行实现

class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        def reverse(head, tail):
        # 逆转该区域内所有元素
            cur = head
            p = head
            end = tail.next
            while cur.next != end:
                node = cur.next 
                cur.next = node.next 
                node.next = p
                p = node
            return tail, head

        pre = ListNode(val=-1, next=head)
        hair = pre
        tail = pre
        # 下一组开始的node
        while head:
            # 判断是否有k的元素
            for _ in range(k):
                tail = tail.next 
                # 结束
                if not tail:
                    return hair.next
            # 翻转
            next = tail.next
            head, tail = reverse(head, tail)
            pre.next = head
            tail.next = next 
            # 更新开头
            pre = tail
            # 下一组开始的时候
            head = tail.next
        return hair.next