LeetCode刷题1:第二周
目录
相关系列笔记:
LeetCode刷题:前言
LeetCode刷题1:第一周
LeetCode刷题1:第二周
LeetCode刷题1:第三周
LeetCode刷题1:第四周
LeetCode刷题1:第五周
LeetCode刷题1:第六周
LeetCode刷题1:第七周
前言
本周Topic是【链表】,对应的5道题:
22.返回倒数第k个节点
21.合并两个有序链表
148.排序链表
147.对链表进行插入排序
25.K个一组翻转链表
知识点
1、链表
链表(linked list) 是一组数据项的集合,其中每个数据项都是一个节点的一部分,每个节点还包含指向下一个节点的链接。
链表的节点的结构如下:
data为自定义的数据,next为下一个节点的地址。
根据结构的不同,链表可以分为单向链表、单向循环链表、双向链表、双向循环链表等。其中,单向链表和单向循环链表的结构如下图所示:
2、单向链表的实现
1)Node实现
每个Node分为两部分。一部分含有链表的元素,可以称为数据域;另一部分为一指针,指向下一个Node。
class Node():
__slots__=['_item','_next'] #限定Node实例的属性
def __init__(self,item):
self._item=item
self._next=None #Node的指针部分默认指向None
def getItem(self):
return self._item
def getNext(self):
return self._next
def setItem(self,newitem):
self._item=newitem
def setNext(self,newnext):
self._next=newnext
2) SinglelinkedList的实现
class SingleLinkedList():
def __init__(self):
self._head=None #初始化链表为空表
self._size=0
3) 检测链表是否为空
def isEmpty(self):
return self._head==None
4) add在链表前端添加元素
def add(self,item):
temp=Node(item)
temp.setNext(self._head)
self._head=temp
5) append在链表尾部添加元素
def append(self,item):
temp=Node(item)
if self.isEmpty():
self._head=temp #若为空表,将添加的元素设为第一个元素
else:
current=self._head
while current.getNext()!=None:
current=current.getNext() #遍历链表
current.setNext(temp) #此时current为链表最后的元素
6) search检索元素是否在链表中
def search(self,item):
current=self._head
founditem=False
while current!=None and not founditem:
if current.getItem()==item:
founditem=True
else:
current=current.getNext()
return founditem
7) index索引元素在链表中的位置
def index(self,item):
current=self._head
count=0
found=None
while current!=None and not found:
count+=1
if current.getItem()==item:
found=True
else:
current=current.getNext()
if found:
return count
else:
raise ValueError,'%s is not in linkedlist'%item
8) remove删除链表中的某项元素
def remove(self,item):
current=self._head
pre=None
while current!=None:
if current.getItem()==item:
if not pre:
self._head=current.getNext()
else:
pre.setNext(current.getNext())
break
else:
pre=current
current=current.getNext()
9) insert链表中插入元素
def insert(self,pos,item):
if pos<=1:
self.add(item)
elif pos>self.size():
self.append(item)
else:
temp=Node(item)
count=1
pre=None
current=self._head
while count<pos:
count+=1
pre=current
current=current.getNext()
pre.setNext(temp)
temp.setNext(current)
LeetCode例题
22. 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例:
输入:n = 3
输出:[
“((()))”,
“(()())”,
“(())()”,
“()(())”,
“()()()”
]
实现:
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
#回溯法
result = []
def backtrack(left, right, tmp):
if right > left or left > n: return
if left + right == 2 * n:
result.append(tmp)
return
backtrack(left + 1, right, tmp + '(')
backtrack(left, right + 1, tmp + ')')
backtrack(0, 0, '')
return result
21. 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
# 递归
if l1 and l2:
if l1.val > l2.val:
l1, l2 = l2, l1
l1.next = self.mergeTwoLists(l1.next, l2)
return l1 or l2
148. 排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
• 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
# 使用快慢指针寻找链表中点,分解链表,递归融合2个有序链表
if not (head and head.next):
return head
pre, slow, fast = None, head, head
while fast and fast.next:
pre, slow, fast = slow, slow.next, fast.next.next
pre.next = None
return self.mergeTwoLists(*map(self.sortList, (head, slow)))
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if l1 and l2:
if l1.val > l2.val: l1, l2 = l2, l1
l1.next = self.mergeTwoLists(l1.next, l2)
return l1 or l2
147. 对链表进行插入排序
对链表进行插入排序。
插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
3. 重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
实现:
class Solution:
def insertionSortList(self, head: ListNode) -> ListNode:
# 找个排头
dummy = ListNode(-1)
pre = dummy
# 依次拿head节点
cur = head
while cur:
# 把下一次节点保持下来
tmp = cur.next
# 找到插入的位置
while pre.next and pre.next.val < cur.val:
pre = pre.next
# 进行插入操作
cur.next = pre.next
pre.next = cur
pre= dummy
cur = tmp
return dummy.next
25. K 个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
tmp = head
for _ in range(k): # 判断从当前节点起,够不够k个节点 【递归的终止条件】
if tmp == None: # 不够则后续节点都不用变动
return head
tmp = tmp.next
# 设置两个指针 # 经过上面的终止条件后,下面要做的就是将一段长度为k的链表反转
p, rev = head, None # 起始情况 rev p ➡ 走一步后 rev p
for _ in range(k): # None p0->p1->...pk-1 None <- p0 p1->...pk-1
rev, rev.next, p = p, rev, p.next # 最终指针p指向pk-1.next, 也就是下一段的入口
head.next = self.reverseKGroup(p, k) # 进行递归 【递归入口】
return rev # rev恰好是原来长度为k的链表的末尾,也是当前这一段链表的头