剑指offer-----数据结构类题目(链表)

文章目录

      • 剑指offer---- 面试题6: 从尾到头打印链表
      • 题目描述
      • 剑指offer---- 面试题18: 删除链表中重复的结点
      • 题目描述
      • 剑指offer---- 面试题22. 链表中倒数第k个结点
      • 题目描述
      • 剑指offer---- 面试题23. 链表中环的入口结点
      • 题目描述
      • 思路
      • 剑指offer---- 面试题24. 反转链表
      • 题目描述
      • 剑指offer---- 面试题25. 合并两个排序的链表
      • 题目描述
      • 剑指offer---- 面试题35. 复杂链表的复制
      • 题目描述
      • 剑指offer---- 面试题52. 两个链表的第一个公共结点
      • 题目描述
      • 思路
      • de

剑指offer---- 面试题6: 从尾到头打印链表

题目描述

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

# -*- 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
        li=[]
        while listNode:
            li.insert(0,listNode.val)
            listNode=listNode.next
        return li

剑指offer---- 面试题18: 删除链表中重复的结点

题目描述

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

'''
法一思路:
1.新建一个节点n,连接并作为pHead的头节点(防止开始两个节点元素就相等)
2.pre指向n,cur指向pHead
3.循环判断cur.val==cur.next.val:
如果==,创建游标tmp指向cur.next,循环判断直到tmp.val!=cur.val,则pre.next=tmp
如果!=,pre=cur,cur=cur.next
4.返回n.next
'''
# -*- coding:utf-8 -*-
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        n=ListNode(0)
        n.next=pHead
        pre=n
        cur=pHead
        while cur:
            if cur.next and cur.next.val == cur.val:
                tmp=cur.next
                while tmp and tmp.val == cur.val:
                    tmp=tmp.next
                pre.next=tmp
                cur=tmp
            else:
                pre=cur
                cur=cur.next
        return n.next
'''
法二思路:
1.先把链表所有值放到列表里面,去重
2.新建一个头节点
3.将列表每一个元素变为一个节点,连接到新建头节点后面
4.返回头节点后的链表
'''
# -*- coding:utf-8 -*-
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        res=[]
        while pHead:
            res.append(pHead.val)
            pHead=pHead.next
        res=list(filter(lambda c :res.count(c)==1,res))
        tmp=ListNode(0)
        pre =tmp
        for i in res:
            node=ListNode(i)
            pre.next=node
            pre=pre.next
        return tmp.next

'''
## lambda语句
lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值。lambda语句构建的其实是一个函数对象,见证一下:
 foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
 print filter(lambda x: x % 3 == 0, foo)
[18, 9, 24, 12, 27]
 print map(lambda x: x * 2 + 10, foo)
[14, 46, 28, 54, 44, 58, 26, 34, 64]
print reduce(lambda x, y: x + y, foo)
139
'''

剑指offer---- 面试题22. 链表中倒数第k个结点

题目描述

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

'''
思路:
2个游标,p1,p2,p2先走k-1步,然后p1 p2一起走,当p2走到尾时,p1就是链表的倒数第k个节点
注意:
最后要返回p1,而不是p1.val,因为题目要求返回节点而不是返回值。
'''
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        if head==None or k<1:
            return None
        p2=head
        p1=head
        while k>1:
            if p2.next!=None:
                p2=p2.next
                k-=1
            else:
                return None
        while p2.next!=None:
            p1=p1.next
            p2=p2.next
        return p1

剑指offer---- 面试题23. 链表中环的入口结点

题目描述

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

思路

p1,p2同时指向开始,p1每次走一步,p2每次走两步,通过下面的数学计算,当p1p2相遇时(p2环内走过n圈了),m=s,即当相遇时,p1p2每次都走一步,直到相遇即为环口的位置。
剑指offer-----数据结构类题目(链表)_第1张图片
剑指offer-----数据结构类题目(链表)_第2张图片
剑指offer-----数据结构类题目(链表)_第3张图片

# -*- 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 pHead==None or pHead.next==None:
            return None
        p1=pHead
        p2=pHead
        while p2 and p2.next:
            p1=p1.next
            p2=p2.next.next
            if p1==p2:
                p1=pHead
                while p1 !=p2:
                    p1=p1.next
                    p2=p2.next
                return p1
        return None

剑指offer---- 面试题24. 反转链表

题目描述

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

'''
思路:
三个游标,让链表箭头指向反转,即cur.next=pre,始终让cur指向前一个节点,然后后移三个游标。
'''
# -*- 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 pHead==None or pHead.next==None:
            return pHead
        pre = None
        cur = pHead
        while cur != None:
            tmp=cur.next
            cur.next=pre 
            pre=cur 
            cur=tmp
        return pre

剑指offer---- 面试题25. 合并两个排序的链表

题目描述

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

'''
法一思路:
把两个链表的值都放在一个列表里,排序,在编程一个一个的节点连成一个链表。
'''
# -*- 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
        res=[]
        while pHead1:
            res.append(pHead1.val)
            pHead1=pHead1.next
        while pHead2:
            res.append(pHead2.val)
            pHead2=pHead2.next
        res.sort()
        tmp=ListNode(0)
        pre=tmp
        for i in res:
            node=ListNode(i)
            pre.next=node
            pre=pre.next
        return tmp.next
'''
法二思路:(推荐)
递归:
游标指向空,比较两个链表首届点的值,谁小,游标=谁,然后递归循环剩下的,
注意,最后两个链表肯定有一个剩下最后一个节点,直接返回连到链表上即可
'''
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        if pHead1==None:
            return pHead2
        if pHead2==None:
            return pHead1
        pMergeHead=None
        if pHead1.val<pHead2.val:
            pMergeHead=pHead1
            pMergeHead.next=self.Merge(pHead1.next, pHead2)
        else:
            pMergeHead=pHead2
            pMergeHead.next=self.Merge(pHead1, pHead2.next)
        return pMergeHead
'''
法三思路:
循环执行法二思想,游标指向一个构造的节点,
'''
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        res=pMergeHead=ListNode(0)  #这里我之前写的pMergeHead=ListNode(0) ,return pMergeHead.next就不对,因为在循环结束跳出循环后pMergeHead.next=pHead1 or pHead2,return pMergeHead.next就直接返回pHead1 or pHead2了
        while pHead1 and pHead2:
            if pHead1.val<pHead2.val:
                pMergeHead.next=pHead1
                pHead1=pHead1.next
            else:
                pMergeHead.next=pHead2
                pHead2=pHead2.next
            pMergeHead=pMergeHead.next
        pMergeHead.next=pHead1 or pHead2
        return res.next

剑指offer---- 面试题35. 复杂链表的复制

题目描述

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

原复杂链表用笨办法复制的话,randomListNode在复制的时候,都要一个一个找,那么每一个都要找n次,时间复杂度就是O(n²)

原复杂链表:
在这里插入图片描述
在原链表中复制节点,并指定新建节点的random指向,通过A.next.random=a.random.next实现。
最后断开node和新建node的连接
剑指offer-----数据结构类题目(链表)_第4张图片

'''
法一:
1.复制每个节点,并插入原节点后面
2.指定每个新node的random方向,注意有A.next.next出现时,要保证A.next存在,否则报错
3.断开原node何新node之间的连接,返回头部,注意:这里了应该有三个游标,其他两个最后指向了链表末尾,第三个用来返回头部
'''
# -*- 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 pHead==None:
            return None
        #1.复制每个节点,并插入原节点后面
        pTmp=pHead
        while pTmp:
            node =RandomListNode(pTmp.label)
            node.next=pTmp.next
            pTmp.next=node
            pTmp=node.next
        #2.指定每个新node的random方向
        pTmp=pHead
        while pTmp:
            if pTmp.random:
                pTmp.next.random=pTmp.random.next
            pTmp=pTmp.next.next
        #3.断开原node何新node之间的连接
        pTmp=pHead
        NewHead=pHead.next
        pNewHead=pHead.next
        while pTmp:
            pTmp.next=pTmp.next.next
            if pNewHead.next:
                pNewHead.next=pNewHead.next.next
                pNewHead=pNewHead.next
            pTmp=pTmp.next
        return NewHead
'''
法二:
直接用python的深拷贝,一步
竟然可以通过牛客!!!
'''
# -*- coding:utf-8 -*-
# class RandomListNode:
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None
import copy
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        # write code here
        res=copy.deepcopy(pHead)
        return res

剑指offer---- 面试题52. 两个链表的第一个公共结点

题目描述

输入两个链表,找出它们的第一个公共结点。

思路

1.两个链表的游标从头开始一起走,
2.当短的链表next为None时,计数长链表剩下的节点数k,长链表先走k步,然后循环长短链表一起走,循环条件为长短链表节点相等,返回短(长)链表节点。
2是一个封装函数

剑指offer-----数据结构类题目(链表)_第5张图片
剑指offer-----数据结构类题目(链表)_第6张图片

剑指offer-----数据结构类题目(链表)_第7张图片
在这里插入图片描述

de

剑指offer-----数据结构类题目(链表)_第8张图片
剑指offer-----数据结构类题目(链表)_第9张图片

你可能感兴趣的:(剑指offer-----数据结构类题目(链表))