剑指Offer(六)——链表

1、(JZ16)合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

非递归做法:

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        tmp = ListNode(0)
        pHead = tmp
        while pHead1 and pHead2:
            if pHead1.val < pHead2.val:
                tmp.next = pHead1
                pHead1 = pHead1.next
            else:
                tmp.next = pHead2
                pHead2 = pHead2.next
            tmp = tmp.next
        if not pHead1:
            tmp.next = pHead2
        if not pHead2:
            tmp.next = pHead1
        return pHead.next

递归做法:

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if not pHead1: return pHead2
        if not pHead2: return pHead1
        if pHead1.val<pHead2.val:
            pHead1.next = self.Merge(pHead1.next, pHead2)
            return pHead1
        else:
            pHead2.next = self.Merge(pHead1,pHead2.next)
            return pHead2

2、(JZ14)链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个结点。

憨憨做法

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param pHead ListNode类 
# @param k int整型 
# @return ListNode类
#
class Solution:
    def FindKthToTail(self , pHead , k ):
        # write code here
        if not pHead:
            return pHead
        tmp = pHead
        count = 0
        while(tmp):
            count += 1
            tmp = tmp.next
        num = count - k + 1
        count = 1
        tmp = pHead
        if num <= 0:
            return None
        while(count != num):
            count += 1
            tmp = tmp.next
        return tmp

放入list中,根据list 

class Solution:
    def FindKthToTail(self , pHead , k ):
        # write code here
        result = []
        if pHead is None:
            return None
        while pHead:
            result.append(pHead)
            pHead = pHead.next
        if k<1 or k>len(result):
            return None
        else:
            return result[-k]
        

3、(JZ15)反转链表

输入一个链表,反转链表后,输出新链表的表头。

方法一:储存所有node,再构造链表

方法二:调整指针

pre 指向已调整好链表的最后一个节点

cur 指向待反转链表的第一个节点

tmp 用于保存待反转链表,所以指向待反转链表的第二个节点

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if not pHead or not pHead.next:
            return pHead
        pre = None
        cur = pHead
        while(cur):
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre

5、(JZ36)两个链表的第一个公共节点

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

写起来简单,但是时间复杂度较高。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        p1,p2 = pHead1,pHead2
        while(p1!=p2):
            p1 = (pHead2 if p1==None else p1.next)
            p2 = (pHead1 if p2==None else p2.next)
        return p1

 下面这个做法仅比较value,我认为存在问题,但是在解释器中可以通过

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        p1 = pHead1
        a = []
        while p1:
            a.append(p1.val)
            p1 = p1.next
        p2 = pHead2
        while p2:
            if p2.val in a:
                return p2
            p2 = p2.next

6、(JZ55)链表中环的入口节点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

借助list完成。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if not pHead or not pHead.next:
            return None
        ans = []
        p = pHead
        while p:
            if p not in ans:
                ans.append(p)
            else:
                return p
            p = p.next
        return None

双指针(快慢)

若不用辅助结构set,该怎么做呢?这里画了一张图

  1. 初始化:快指针fast指向头结点, 慢指针slow指向头结点
  2. 让fast一次走两步, slow一次走一步,第一次相遇在C处,停止
  3. 然后让fast指向头结点,slow原地不动,让后fast,slow每次走一步,当再次相遇,就是入口结点。
    如上解释:


    如果慢指针slow第一次走到了B点处,距离C点处还有距离Y,那么fast指针应该停留在D点处,且BD距离为Y(图中所示是假设快指针走了一圈就相遇,为了便于分析),
    也就是DB+BC=2Y,(因为fast一次走2步,慢指针一次走1步,并且相遇在C处)
    在C点处,此时慢指针slow走的点为ABC,距离为X+Y,而快指针fast走的点为ABCDBC,距离为2X+2Y,
    又因为:AB=X,BC=Y,快指针走了2次BC,所以CDB距离为X,而AB距离也为X。关键在于AB=CDB
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if not pHead:
            return None
        slow = pHead
        fast = pHead
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
            if slow==fast:
                p_new = pHead
                while p_new != slow:
                    p_new = p_new.next
                    slow = slow.next
                return p_new
        return None 
                

7、(JZ3)从尾到头打印链表

递归做法

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        if listNode is None:
            return []
        return self.printListFromTailToHead(listNode.next)+[listNode.val]

 读取链表的值,然后反转

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        ans = []
        if not listNode:
            return []
        p = listNode
        while p!=None:
            ans.append(p.val)
            p = p.next
        return list(reversed(ans))

反转链表

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        pre, cur = None, listNode
        while cur !=None:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp 
        ans = []
        while pre:
            ans.append(pre.val)
            pre = pre.next
        return ans

8、(JZ25)复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

递归作法:

# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        if not pHead:
            return None
        newnode = RandomListNode(pHead.label)
        newnode.random = pHead.random
        newnode.next = self.Clone(pHead.next)
        return newnode

9、(JZ56)删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

# -*- 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 not pHead or not pHead.next:
            return pHead
        if pHead.val == pHead.next.val:
            while pHead.next and pHead.val == pHead.next.val:
                pHead = pHead.next
            return self.deleteDuplication(pHead.next)
        else:
            pHead.next = self.deleteDuplication(pHead.next)
        return pHead

猜你喜欢

转载自blog.csdn.net/caicai0001000/article/details/114455670