链表-02
文章目录
- [2. 两数相加](https://leetcode-cn.com/problems/add-two-numbers/)
- [19. 删除链表的倒数第N个节点](https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/)
- [面试题 02.02. 返回倒数第 k 个节点](https://leetcode-cn.com/problems/kth-node-from-end-of-list-lcci/)
- [面试题18. 删除链表的节点](https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/)
- [21. 合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/)
- [23. 合并K个排序链表](https://leetcode-cn.com/problems/merge-k-sorted-lists/)
- [61. 旋转链表](https://leetcode-cn.com/problems/rotate-list/)
- [82. 删除排序链表中的重复元素 II](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/)
- [83. 删除排序链表中的重复元素](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/)
- [86. 分隔链表](https://leetcode-cn.com/problems/partition-list/)
- [206. 反转链表](https://leetcode-cn.com/problems/reverse-linked-list/)
- [234. 回文链表](https://leetcode-cn.com/problems/palindrome-linked-list/)
- [328. 奇偶链表](https://leetcode-cn.com/problems/odd-even-linked-list/)
思路:
链表的题目主要涉及:链表的增、删、改和查,这4种
注意:
-
当仅仅对链表进行遍历时,链表是不变的,其余的3种操作都会改变链表的值和next节点
-
删除节点时,最好用哑变量(指向头结点的节点),防止删除后的链表为空的情况
-
循环向链表中添加节点时,一定要记得添加完一个节点后,指针要往后移动
-
修改链表时,如果要更改某个节点,并且之后还要用到这个节点,一定要把这个节点保存在变量中,以防丢失
-
在遍历链表时,一定要记得先判断节点是否为空
2. 两数相加
思路:链表的遍历和新链表的创建(添加节点); 当循环向链表中添加元素时,一定要记得指针后移
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
res = ListNode(0) #根节点
node = res # 根节点的指针
carry = 0
while (l1!=None or l2!=None):
v1 = l1.val if l1 else 0
v2 = l2.val if l2 else 0
sum_ = carry+v1+v2
node.next = ListNode(sum_%10) # 添加节点
node = node.next #指针后移
carry = sum_//10
l1 = l1.next if l1 else None #链表的遍历
l2 = l2.next if l2 else None
if carry!=0:
node.next = ListNode(carry)
return res.next
19. 删除链表的倒数第N个节点
思路:链表的遍历 和节点的删除
链表的删除最好使用哑变量,以防删除后是空链表的情况
方法1:一次遍历
根据 k + (n-k) = (n-k) +k 的原理,先让指针往前一定k个节点,然后同时移动p和q,这样当指针p走完全程后,指针q刚好走到倒数第k个节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
if not head:
return head
dummy = ListNode(-1)
dummy.next = head
p = dummy
q = dummy
while n+1:
p = p.next
n-=1
while p:
p = p.next
q = q.next
q.next = q.next.next
return dummy.next
方法2:两次遍历,第一次遍历计算链表的长度len,第二次遍历找到len-n的前一个节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
if not head:
return head
length = 0
node = head
while node:
length += 1
node = node.next
m = length - n -1
if m <0:
return head.next
node = head
while m:
node = node.next
m-=1
node.next = node.next.next
return head
面试题 02.02. 返回倒数第 k 个节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def kthToLast(self, head: ListNode, k: int) -> int:
p = head
q = head
while k:
p = p.next
k-=1
while p:
p = p.next
q = q.next
return q.val
面试题18. 删除链表的节点
思路:删节点时首先要判断,是否删除根节点;如果不想判断可以 用哑变量
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, head: ListNode, val: int) -> ListNode:
if head.val == val:
head = head.next
return head
curr = head
while curr.next and curr.next.val!=val:
curr = curr.next
curr.next = curr.next.next
return head
方法2:使用哑变量
def deleteNode(self, head: ListNode, val: int) -> ListNode:
dummy = ListNode(-1)
dummy.next = head
pre = dummy
while pre.next and pre.next.val!=val:
pre = pre.next
pre.next = pre.next.next
return dummy.next
21. 合并两个有序链表
思路:节点的插入
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
if not l1 and not l2:
return None
arr = []
while l1:
arr.append(l1.val)
l1 = l1.next
while l2:
arr.append(l2.val)
l2 = l2.next
arr.sort()
dummpy = ListNode(0)
node = dummpy
for num in arr:
node.next = ListNode(num)
node = node.next
return dummpy.next
23. 合并K个排序链表
思路:链表的遍历和添加节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
arr = []
for i in range(len(lists)):
while lists[i]:
arr.append(lists[i].val)
lists[i] = lists[i].next
arr_sort = sorted(arr)
dummpy = ListNode(0)
node = dummpy
for num in arr_sort:
node.next = ListNode(num)
node = node.next
return dummpy.next
61. 旋转链表
思路:链表的遍历和节点的插入
将倒数第一个节点插入到链表的头部,并将倒数第二个节点的next设置为None, 因此每次遍历需要找到倒数第二个节点
注意一定要保证最后一个节点的next是None,否则算法会卡壳
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
if not head:
return head
if not head.next:
return head
length = 0
node = head
while node:
length += 1
node = node.next
k = k%length
for i in range(k):
node = head
pre = head
while node.next and node.next.next:
node = node.next
tail = node.next
node.next = None
tail.next = head
head = tail
return head
82. 删除排序链表中的重复元素 II
思路:首先对原链表中的节点值进行去重,然后对去重后的节点值,创建新的链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head:
return None
arr = []
node = head
while node:
arr.append(node.val)
node = node.next
dic = {}
for num in arr:
dic[num] = dic.get(num, 0)+1
uniq_arr = []
for num, cnt in dic.items():
if cnt ==1:
uniq_arr.append(num)
dummy = ListNode(-1)
node = dummy
for num in uniq_arr:
node.next = ListNode(num)
node = node.next
return dummy.next
83. 删除排序链表中的重复元素
思路:元素的删除
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head:
return None
node = head
while node and node.next:
if node.val == node.next.val:
node.next = node.next.next
else:
node = node.next
return head
86. 分隔链表
思路:在链表的遍历时,将小于x的节点加入到before链表中,将大于等于x的节点加入到after中,然后before链表再跟after链表合并起来
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
import numpy
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
before = before_head = ListNode(0)
after = after_head = ListNode(0)
while head:
if head.val >=x:
after.next= head
after = after.next
else:
before.next = head
before = before.next
head = head.next
after.next = None
before.next = after_head.next
return before_head.next
206. 反转链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
if not head:
return None
pre = None
curr = head
while curr:
post = curr.next
curr.next = pre
pre = curr
curr = post
return pre
234. 回文链表
思路:使用快慢指针,找到中间节点;判断前半部分跟后半部分的节点是否对称
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
if not head or not head.next:
return True
s = head
f = head
pre_list = [head.val]
while f and f.next:
f = f.next.next
s = s.next
pre_list.append(s.val)
if not f:
pre_list.pop()
post_node = s
post_list = []
while post_node:
post_list.append(post_node.val)
post_node = post_node.next
return pre_list == post_list[::-1]
328. 奇偶链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
dummy = ListNode(0)
odd = dummy
mid = ListNode(0)
event = mid
curr = head
index = 0
while curr:
index+=1
if index%2==1:
odd.next = curr
odd = odd.next
else:
event.next = curr
event = event.next
curr = curr.next
if event:
event.next = None
odd.next = mid.next
return dummy.next
odd = dummy
mid = ListNode(0)
event = mid
curr = head
index = 0
while curr:
index+=1
if index%2==1:
odd.next = curr
odd = odd.next
else:
event.next = curr
event = event.next
curr = curr.next
if event:
event.next = None
odd.next = mid.next
return dummy.next