链表常见的面试题

1、从链表的末尾添加节点

2、删除链表节点

给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该节点

如果用头指针开始遍历链表时间复杂度为O(n),要在O(1)的时间删除,需要得到被删除的结点的前一个结点,但是前一个结点很难获得,但是我们可以很方便的得到要删除的结点的下一个结点,如果我们把下一个结点的内容复制到需要删除的结点上覆盖原有的内容,在把下一个结点删除。

代码实现:

class ListNode:
    def __init__(self, x=None):
        self.val = x
        self.next = None
    def __del__(self):
        self.val = None
        self.next = None

class Solution:
    def DeleteNode(self, pListHead, pToBeDeleted):
        if not pListHead or not pToBeDeleted:
            return None

        if pToBeDeleted.next != None:
            pNext = pToBeDeleted.next
            pToBeDeleted.val = pNext.val
            pToBeDeleted.next = pNext.next
            pNext.__del__()


        elif pListHead == pToBeDeleted:
            pToBeDeleted.__del__()
            pListHead.__del__()
        else:
            pNode = pListHead
            while pNode.next != pToBeDeleted:
                pNode = pNode.next
            pNode.next = None
            pToBeDeleted.__del__()

3、链表中倒数第K个节点

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

为了实现只遍历一遍链表就能找到倒数第K个结点,我们可以定义两个指针,第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动;从第K步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个指针到达链表的尾节点时,第二个指针正好是倒数第K个结点。

代码实现:

    def FindKthToTail(self, head, k):
        # write code here
        pAhead = ListNode(0)
        pAhead = head
        pBehind = ListNode(0)
        if head == None:
            return
        if k == 0:
            return
        for i in range(k - 1):
            if pAhead.next != None:
                pAhead = pAhead.next
            else:
                return None
        pBehind = head
        while (pAhead.next != None):
            pAhead = pAhead.next
            pBehind = pBehind.next
        return pBehind

扩展问题
1 求链表的中间节点。
这个问题可以定义两个指针。同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步。
当走的快的指针走到链表的末尾时,走得慢的指针正好在链表的中间

class  Solution1:
    def middlenode(self,node):
        phead = ListNode(0)
        pnext = ListNode(0)
        phead = node
        pnext = phead
        if phead is None and pnext is None:
            return
        while  pnext.next!= None:
            phead = phead.next
            pnext = pnext.next.next
        if pnext.next == None:
            result = phead.val
        return result

4、反转链表

定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。

为了防止链表断开,我们需要维护三个指针,分别指向当前遍历结点、它的前一个结点以及后一个结点。
反转链表的操作为当前结点的下一个结点指向前一个结点所指的结点。

代码实现:

    def ReverseList(self, pHead):
        # write code here
        preNode = None
        pReverseNode = None
        pNode = pHead
        while(pNode != None):
            pNext = ListNode(0)
            pNext = pNode.next
            if pNext == None:
                pReverseNode = pNode
            pNode.next = preNode
            preNode = pNode
            pNode = pNext
        return pReverseNode

5、从尾到头打印链表

从尾到头来打印,相当于“先进后出”,借助栈的数据结构。

class listnode:
    def __init__(self,val):
        self.val = val
        self.next  = None

def printlist(listnode):
    stack = []

    while listnode is not  None:
        stack.append(listnode.val)
        listnode = listnode.next

    for i in range(len(stack)-1,-1,-1):
        print(stack[i])

6、合并两个排序的链表

输入两个递增排序的链表,合并两个链表并使新链表中的结点任然是按照递增排序;

对两个链表中的元素进行对比,用一个新的链表记录两个链表中的较小的值,然后增加到新链表中,直到两个链表遍历完成。

代码实现:

    def merge(self,Phead1,Phead2):
        if Phead1 == None:
            return Phead2
        elif Phead2 == None:
            return Phead1
        pmerge = ListNode(0)
        if Phead1.val < Phead2.val:
            pmerge = Phead1
            pmerge.next = self.merge(Phead1.next,Phead2)
        else:
            pmerge = Phead2
            pmerge.next = self.merge(Phead1,Phead2.next)
        return pmerge

7、两个链表的第一个公共节点
如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,最后一个相同的结点就是我们要找的结点。
于是我们借助栈,分别把两个链表的结点放入两个栈中,这样两个链表的尾节点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,知道找到最后一个相同的结点。

更加简单的方法:
受限遍历两个链表得到它们的长度,就能知道那个链表比较长,以及长的链表比短的链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步,接着再同步在两个链表上遍历,找到的第一个相同的结点就是它们的第一个公共结点。

代码实现:

    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        lenhead1 =0
        lenhead2 =0
        p1 = pHead1
        p2 = pHead2
        while pHead1.next !=None:
            lenhead1 +=1
            pHead1= pHead1.next
        while pHead2.next !=None:
            lenhead2 +=1
            pHead2 = pHead2.next
        if lenhead2 > lenhead1:
            step = lenhead2 -lenhead1
            for i in range(step):
                if p2 != None:
                    p2 = p2.next
            while p2 != None and p2!=None:
                if p1.val == p2.val:
                    return p1.val
                    break
                else:
                    p2 = p2.next
                    p1 = p1.next

        else:
            step = lenhead1 - lenhead2
            for i in range(step):
                if p1 != None:
                    p1 = p1.next
            while p2 != None and p1 != None:
                if p1.val == p2.val:
                    return p1.val
                    break
                else:
                    p2 = p2.next
                    p1 = p1.next

8、判断两个链表是否有环相关问题

定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步。如果走得快的指针追上了走的慢的指针,那么链表就是环形链表;

代码实现:

 def findlink(self,node):
        phead = ListNode(0)
        pnext = ListNode(0)
        phead = node
        pnext = phead
        if phead is None and pnext is None:
            return
        phead = phead.next
        pnext = pnext.next.next
        while phead.val != pnext.val and pnext.next != None:
            phead = phead.next
            pnext = pnext.next.next
            if phead.val == pnext.val:

                return True
                break
            else:
                return False

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

10、复杂链表的复制

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值