剑指 Offer 最优题解系列python--链表
学习笔记
1. 反转链表(200718)
方法1:双指针
- 定义两个指针: pre和 cur ;pre 在前 cur在后。
- 每次让 prepre 的 next 指向 cur ,实现一次局部反转
- 局部反转完成之后, pre 和 cur 同时往前移动一个位置
- 循环上述过程,直至 pre 到达链表尾部
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
last = None
while head:
head.next, last, head = last, head, head.next
return last
2.链表中倒数第k个结点(200719)
2.链表中倒数第k个结点
解题思路
算法流程:
- 初始化: 前指针 former 、后指针 latter ,双指针都指向头节点 head 。
- 构建双指针距离: 前指针 former 先向前走 k步(结束后,双指针 former 和 latter 间相距 k步)。
- 双指针共同移动: 循环中,双指针 former 和 latter 每轮都向前走一步,直至 former 走过链表 尾节点 时跳出(跳出后, latter 与尾节点距离为 k-1,即 latter 指向倒数第 k 个节点)。
- 返回值: 返回 latter 即可
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getKthFromEnd(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
former,later = head,head
for _ in range(k):
if not former: return
former=former.next
while(former):
former,later = former.next,later.next
return later
复杂度分析:
时间复杂度 O(N) : NN 为链表长度;总体看, former 走了 N 步, latter 走了 (N-k)步。
空间复杂度 O(1) : 双指针 former , latter 使用常数大小的额外空间
3.合并两个排序的链表(200720)
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
cur = dum = ListNode(0)
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
cur.next = l1 if l1 else l2
return dum.next
复杂度分析:
- 时间复杂度 O(M+N) : M, N分别为链表l1,l2的长度,合并操作需遍历两链表。
- 空间复杂度 O(1) : 节点引用 dum , cur使用常数大小的额外空间。
4.复杂链表的复制(200721)
4.复杂链表的复制
题意理解
本题的意思是复制一个链表并返回,这个链表与一般链表不同的是多了一个 random 指针。
在这里,复制的意思是指 深拷贝(Deep Copy),类似我们常用的“复制粘贴”,事实上,与此对应的还有 浅拷贝,它们的区别是:
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
"""
# Definition for a Node.
class Node:
def __init__(self, x, next=None, random=None):
self.val = int(x)
self.next = next
self.random = random
"""
class Solution(object):
def copyRandomList(self, head):
"""
:type head: Node
:rtype: Node
"""
return copy.deepcopy(head)
这段代码太羞耻了。后续更其他方法。
5.两个链表的第一个公共节点(200722)
5.两个链表的第一个公共节点
解题思路:
- node1向终点奔跑,若到终点返回headB,重新向终点奔跑
- node2同理
- 两个人的速度相同,距离相同(若无交点,则两人都在最后A和B的null邂逅。若有交点,则在途中邂逅)
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
node1, node2 = headA, headB
while node1 != node2 :
node1 = node1.next if node1 else headB
node2 = node2.next if node2 else headA
return node1
复杂度分析
- 时间复杂度:O(M+N)。
- 空间复杂度:O(1)。
6.删除链表中结点(200723)
6.删除链表中结点
解题思路:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def deleteNode(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
if head.val == val :
return head.next
pre,cur = head, head.next
while cur and cur.val!= val:
pre,cur=cur,cur.next
if cur:
pre.next = cur.next
return head
复杂度分析:
- 时间复杂度 O(N)O(N) : N为链表长度,删除操作平均需循环 N/2 次,最差 N次。
- 空间复杂度 O(1) : cur, pre 占用常数大小额外空间。
7.删除链表中重复的结点(200723)
删除链表中重复的结点
解题思路:
- 为了防止第一个节点就是重复节点,需要初始化一个新的头节点;
- 其他参照删除链表结点来做
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplication(self, pHead):
# write code here
if pHead == None or pHead.next == None:
return pHead
head = ListNode(0) # 为了防止第一个节点就是重复节点,重新弄个头节点
head.next = pHead
pre = head # 当前节点的前一个节点
cur = pHead # 当前节点
nex = None # 当前节点的后一个节点
while cur != None and cur.next != None:
nex = cur.next
if cur.val == nex.val:
while nex != None and nex.val == cur.val:
nex = nex.next
pre.next = nex
cur = nex
else:
pre = cur
cur = cur.next
return head.next