@Author:Runsen
@Date:2020/9/13
链表是我这辈子的痛啊,每次学到链表,就往往不会,就没有继续学下去。现在大四不能继续让这个链表阻碍我了。现在基本是重刷数据结构和算法,毕竟笔试真的太重要了。 我又重温了争大佬专栏的栈,又巩固了下。
争哥专栏有一个非常的经典:就是关于指针的理解:将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指针,或者反过来说,指针中存储了这个变量的内存地址,指向了这个变量,通过指针就能找到这个变量。
涉及到链表的操作,重新看了专栏,一定要在纸上把过程先画出来,再写程序。对于链表其实基本就是单链表,很少是双链表,或者循环链表的题目
由于一个节点只通过next指针保存了它的下一个节点,失去了它的前驱节点信息,而且单链表数据结构通常长度未知,因此几乎所有单链表题目都是在前驱节点和长度上做文章。
常见链表面试算法,可以使用双指针迭代的方式以及递归的方式。
下面就是我2020/9/13 在leetcode 刷的链表题目,很多注释都写清楚了。关于题目的描述,这里不直接抄Leetcode 了。
这个反转单链表,写了N次,但又写的时候,又写不出来。服了,自己。看似,简单,博客最起码写了3次 反转一个单链表
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
prev = None
cur = head
while cur:
# prev 指cur.next cur指prev cur.next指cur
cur.next,prev,cur = prev,cur,cur.next
return prev
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
# 将l1链表的数取出,组成一个数,l2同理,最终求和,将求和结果循环得出每个节点的值,然后链表连接即可!!!
# 将链表转化列表
val1, val2 = [l1.val], [l2.val]
print(val1) #[2]
print(val2) #[5]
while l1.next:
val1.append(l1.next.val)
l1 = l1.next
while l2.next:
val2.append(l2.next.val)
l2 = l2.next
print(val1) #[2, 4, 3]
print(val2) #[5, 6, 4]
# 反转列表 用join方法拼接数字 切片[::-1]
num_1 = ''.join([str(i) for i in val1[::-1]])
num_2 = ''.join([str(i) for i in val2[::-1]])
sums = str(int(num_1) + int(num_2))[::-1] # 708
# 将sum转化成链表res
# 头节点
res = head = ListNode(int(sums[0]))
for i in range(1, len(sums)):
# 拼接
head.next = ListNode(int(sums[i]))
head = head.next
return res
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
# 如果头结点为空,直接返回
if not head:
return head
# 如果头结点值等于val,直接返回head.next(题设中有注明链表中元素不重复)
if head.val == val:
return head.next
# 定义一个指针
cur = head
while cur.next:
# 关键步骤,如果next的值等于val,跳过该节点
if cur.next.val == val:
cur.next = cur.next.next
break
cur = cur.next
return head
# 将要删除节点的 val 赋值为下一结点的 val
node.val = node.next.val
# 然后将要删除节点的下一结点指向要删除节点的下一结点的下一结点
node.next = node.next.next
class Solution:
def removeDuplicateNodes(self, head: ListNode) -> ListNode:
# 如果没有head,那么直接return
if not head: return
# 用集合来储存起来
visited = {
head.val}
cur = head
# 处理当前节点的下一个节点
while cur and cur.next:
# 如果当前的val在字典中,那么直接不要
if cur.next.val in visited:
cur.next = cur.next.next
else:
# 集合的add 直接加入 集合或者元组都可以
visited.add(cur.next.val)
# 往下遍历
cur = cur.next
return head
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
# 链表转化为列表,判断是不是 回文
res = []
cur = head
while cur:
res.append(cur.val)
cur = cur.next
# print(res)
if res[::-1] == res:
return True
else:
return False
class Solution:
'''
@Author :Runsen
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
就是每次取两边,先左到右
1 -> 2 -> 3 -> 4 -> 5 -> 6
第一步,将链表平均分成两半
1 -> 2 -> 3
4 -> 5 -> 6
第二步,将第二个链表逆序
1 -> 2 -> 3
6 -> 5 -> 4
第三步,依次连接两个链表
1 -> 6 -> 2 -> 5 -> 3 -> 4
1 -> 2 -> 3 -> 4 -> 5 -> 6
'''
# 思路 找到中间节点,然后将右面的翻转,先定义一个翻转函数,Leetcode 206题
def reverseList(self, head):
pre = None
cur = head
while cur:
cur.next, pre, cur = pre, cur, cur.next
return pre
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if not head:
return head
slow, fast = head, head
while fast and fast.next:
slow, fast = slow.next, fast.next.next
# 寻找中间节点 快慢指针中的慢指针就是中间节点
p = slow.next
slow.next = None
p = self.reverseList(p)
# 这个时候的p就是链表右面的翻转
m = head
while p:
# 怎么拼接?
# m ,m.next, p, p.next => p, m.next, m.next, p.next 返回的是m这个链表
m.next, p.next, m, p = p, m.next, m.next, p.next
最常规的方法就是将链表变成数组,直接一个索引取值就可以了。
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
res = []
while head:
res.append(head)
head = head.next
return res[-k]
有的大佬给出快慢指针的方法,就是快指针先走 K 步,然后再快慢指针一起走,当快指针跑出来时,慢指针的就是倒数第k个节点。
class Solution:
def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
former, latter = head, head
for _ in range(k):
former = former.next
while former:
former, latter = former.next, latter.next
return latter
参考:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/solution/mian-shi-ti-22-lian-biao-zhong-dao-shu-di-kge-j-11/
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
这题和上面那题是一样的,都是快慢指针,只不过这里需要返回链表的头结点。那定义一个Node = ListNode(None)
就可以了。
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 快慢指针
Node = ListNode(None)
Node.next = head
first,slow = Node,Node
for i in range(n):
first = first.next
while first.next != None:
first = first.next
slow = slow.next
slow.next = slow.next.next
return Node.next
不知不觉现在到了下午三点,从早上九点半到现在,刷了九题的链表算法题目,真心累!!!!