在力扣中,已经对单链表的节点有了定义。
具有两个参数:该节点的值和指向下一个节点(类)的指针
如下所示:
#Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
目录
删除链表的倒数第 N 个结点
第一道题删除链表的倒数第 N 个结点
由于每个节点链接的是下一个节点,所以链表只能从前向后查询,不能从后向前查询。
所以我们并不能从后向前查询n个节点,
但是要找到这个节点,我们可以从前向后查询(s-n)个节点(假设共有s个节点)
所以这道题的思路是:首先查询所给链表总节点个数
然后从前向后查询(s-n)个节点,使得这个节点前的那个节点直接链接到这 个节点后的那个节点去(形式上删除这个节点)
代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
def getLength(head: ListNode):
lent = 0
while(head):
head = head.next
lent = lent + 1
return lent
dummy = ListNode(0, head)
cur = dummy
lenth = getLength(head)
for i in range(0, lenth-n):
cur = cur.next
cur.next = cur.next.next
return dummy.next
注意:这里我们自己建立一个头节点(这里其实也可以不建)
合并两个有序链表
第二道题合并两个有序链表
一个基本的想法是把两个有序链表合成一个新的链表
这两个链表各有一个指针,
给新链表一个元素,就往后移一个元素
否则就不往后移
对于新链表而言,每获得一个元素,指针就往后移一个元素
这两个指针,用于比较两个有序链表最前端的两个元素的大小,小的则会赋值给新链表
这个循环执行下去,直到其中一个链表被扫描完,此时新链表只需连接另一个链表剩余元素就可以了。
代码如下:
# 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:
dummy = ListNode(0)
cur = dummy
while(l1 and l2):
if(l1.val < l2.val):
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if(l1):
cur.next = l1
if(l2):
cur.next = l2
return dummy.next
注意:这道题需要定义一个头指针(头节点),以使得对新链表的第一个节点创建 和 链表中的其他节点一样。
反转链表
第三道题反转链表
此处采用递推的想法来解决这个问题
我们需要为翻转后的链表构造一个为空的尾节点
从链表的第一个节点开始扫描,记录该节点后的节点,使当前节点与前一个节点相连(如果是第一个节点,它需要和那么构造的第一个节点相连)
更新前一个节点和当前节点
代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
# 构造要连成链表的尾结点
prev = None
# 初始化当前节点(从头结点开始)
curr = head
while(curr != None):
# 记录当前节点后的一个节点
lian = curr.next
# 当前节点和前一个节点相连
curr.next = prev
#递推
prev = curr
curr = lian
return prev
最后需要返回最后原链表最后一个节点(不是None)
两两交换链表中的节点
第四道题两两交换链表中的节点
这道题目我们采用递归的写法,我们首先保存下不为None的head.next.next节点
采用递归的写法,我们将首先翻转链表尾部的两个节点,依次,最后再翻转头部的两个节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
if(not head or not head.next):
return head
subResult = self.swapPairs(head.next.next)
headNext = head.next
headNext.next = head
head.next = subResult
return headNext
现在我们来考虑第四道题 合并K个升序链表
我们已经学会了合并两个有序链表,那么对于 合并k个有序链表
一种想法:
我们可以初始化一个空链表,只有一个为None的head节点,
然后对于我们要合并的k个链表的操作一样:
使得head链表首先与第一个链表合并,记为head链表
使得head链表再与第二个链表合并,记为head链表
... ...
head链表与第k个链表合并,记为head链表
最后返回head
对应代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
head = None
for lNode in lists:
head = self.merge(head, lNode)
return head
def merge(self, head: ListNode, lx: ListNode) -> ListNode:
dummy = ListNode(0)
cur = dummy
while(head and lx):
if(head.val < lx.val):
dummy.next = head
head = head.next
else:
dummy.next = lx
lx = lx.next
dummy = dummy.next
if(head):
dummy.next = head
if(lx):
dummy.next = lx
return cur.next
K 个一组翻转链表
第五道题K 个一组翻转链表
我们已经学会了如何翻转链表,
那么我们只需要从第一个节点开始数k个节点,将第一个节点作为头节点,将第k个节点作为尾节点,对这k个节点翻转链表。
如果我们数数不足k个,说明已经到了链表尾部。不需进行操作,直接返回头节点。
需要注意的是我们需要记录头节点的前一个节点,和尾节点后的一个节点,因为翻转后的链表的头尾节点已不再和之前相同,我们需要将他们进行连接。
每翻转k个节点,我们需要更新一下,需要连接的前一个节点pre,需要连接的后一个节点nex将在查k个节点的时候取得,以及便于循环操作的k个节点链表的head节点
代码如下:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverse(self, head: ListNode, tail: ListNode):
# 构造要连成链表的尾结点
prev = None
# 初始化当前节点(从头结点开始)
tailNext = tail.next
curr = head
while(curr != tailNext):
# 记录当前节点后的一个节点
lian = curr.next
# 当前节点和前一个节点相连
curr.next = prev
#递推
prev = curr
curr = lian
return prev, head
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
hair = ListNode(0)
hair.next = head
# 赋予初值
pre = hair
tail = hair
while(head):
for i in range(k):
tail = tail.next
if(not tail):
return hair.next
# 若tail不为None,记录下翻转链表后的一个节点
nex = tail.next
head, tail = self.reverse(head, tail)
# 每次循环需要记录翻转链表的前一个节点和后一个节点,即pre和nex
# 使得pre和翻转后的链表和nex相连
pre.next = head
tail.next = nex
#为下一次循环更新pre
pre = tail
head = tail.next
return hair.next
最后,我们讲一道题目最长公共前缀
这道题目是给出一系列字符串列表,指出这些字符串的公共前缀是什么
我们可以先初始化一个字符串,记为这些字符串的公共前缀,然后依次找它与第0个,第1个,第2个,...,第n个字符串的公共前缀(这个字符串可以先初始化为第一个字符串)
那么最后这个字符串就是公共前缀
那么现在问题是怎么寻找两个字符串的公共前缀呢?
我们可以从第0个字符开始寻找,如果相同,则在初始为空的两者公共前缀上连接这个字符,
否则,寻找结束
返回这个两个字符串的公共前缀
代码如下:
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
longestStr = strs[0]
count = len(strs)
for i in range(1, count):
longestStr = self.longerStr(longestStr, strs[i])
return longestStr
def longerStr(self, str1, str2) -> str:
commonStr = ''
index = 0
lenth = min(len(str1), len(str2))
for i in range(index, lenth):
if(str1[i] != str2[i]):
break
else:
commonStr = commonStr + str1[i]
return commonStr
欢迎交流、指正!
参考题解: