简单题(2道)
给定一个只包括 '(',')','{','}','[',']' 的字符串 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
给你一个字符串 `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道)
给你两个版本号 version1 和 version2 ,请你比较它们。
版本号由一个或多个修订号组成,各修订号由一个 '.' 连接。每个修订号由 多位数字 组成,可能包含 前导零 。每个版本号至少包含一个字符。修订号从左到右编号,下标从 0 开始,最左边的修订号下标为 0 ,下一个修订号下标为 1 ,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。
比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较 忽略任何前导零后的整数值 。也就是说,修订号 1 和修订号 001 相等 。如果版本号没有指定某个下标处的修订号,则该修订号视为 0 。例如,版本 1.0 小于版本 1.1 ,因为它们下标为 0 的修订号相同,而下标为 1 的修订号分别为 0 和 1 ,0 < 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
给定一个单链表 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道)
给你链表的头节点 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