ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

算法刷题之七链表

2021-06-25 14:34:31  阅读:119  来源: 互联网

标签:head slow ListNode self next 链表 算法 刷题


链表

题目:

  1. 链表删除某一个节点
  2. 删除倒数第N个节点
  3. 链表逆序
  4. 回文链表
  5. 判断链表是否有环路
  6. 找出环路链表的入口
  7. 链表排序
  8. 相交链表
  9. 两个连表生成相加链表

链表的数据格式就是如下:

需要注意的是:链表尾部的next为None。所以判断链表结束时,这是遍历一个链表最常用的结束方式。使用的代码:

while p != None:
    p = p.next

其实是当p已经指向了next区域,这时next为空,所以能够退出

当使用p.next != None时,这时p指向的最有一个节点,而不是节点的next。

while p.next != None:
    p = p.next

链表删除某一个节点:

删除节点两种方式:

  1. 当前节点指向下下个节点

  2. 将下一个节点赋值给当前节点,然后删除下一个节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteNode(self, node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        node.val,node.next.val = node.next.val,node.val
        node.next = node.next.next

删除倒数第N个节点

有两种方式:

  1. 算出倒数N的正数num,然后移动到该节点前一个,删除节点
  2. 设置双指针,指针的间距是倒数N。当快指针到链尾时,慢指针当好到待删除的前一个。
  3. 删除节点需要考虑节点为头结点的情况。这时指针指向头结点,不易删除。解决办法是给头结点增加一个前行节点。将指针指向该前行节点。
# 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:
        
        # 设置头结点
        re = ListNode(-1)

        re.next = head
        
        slow = re
        fast = slow
        while n + 1> 0:
            fast =  fast.next
            n -= 1

        while fast != None:
            fast = fast.next
            slow = slow.next

        slow.next = slow.next.next
        return re.next

链表逆序

使用双指针可以将链表逆序。

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        cur = head
        while cur:
            temp = cur.next   # 先把原来cur.next位置存起来
            cur.next = pre
            pre = cur
            cur = temp
        return pre

需要注意结束条件。当cur == None时,pre刚好在链尾的位置。返回pre就是返回了新的链表

回文链表

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false
示例 2:

输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/xnv1oc/

回文最常用的判断方式是:

  1. 逆序,然后比较逆序之后和逆序之前是否相同。如果相同就是回文,不同就不是回文
  2. 将前一半保存,逆序或者入栈,和后一半比较。如果都相同则是回文。

链表回文有多种方式:

  1. 将链表中所有数据保存到列表中,使用列表的逆序来判断
  2. 利用快慢指针,前一半链表的值入栈,然后出栈和后一半比较判断
  3. 利用快慢指针,逆序前一半链表,和后一半比较
class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        if not head or not head.next:
            return True
 
        slow = head
        fast = head
        mystack = []

        while fast and fast.next:
           mystack.append(slow.val)
           fast = fast.next.next
           slow = slow.next
        
        # 奇数状态,需要跨过中间的元素
        if fast:
            slow = slow.next
        
        while slow and slow.val == mystack.pop():
            slow = slow.next

判断链表是否有环路

判断链表是否有环路有两个解决方法,
第一:快慢指针,如果存在环路,快指针一定会追上慢指针
第二:字典。将遍历过的节点存入到字典中,每次遍历时在字典中查找,如果存在则表明有环路。



class Node():

    def __init__(self, data):
        self.data = data
        self.next = None



node1 = Node(100)
node2 = Node(200)
node3 = Node(300)
node4 = Node(300)
node5 = Node(200)
node6 = Node(100)

node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node6
node6.next = node1


def cycle_link(head):

    fast = head
    slow = head

    while fast and fast.next:
        fast = fast.next.next
        slow = slow.next
        if fast == slow:
            return True  
    return False

res = cycle_link(node1)
print(res)
class Solution:
    def hasCycle(self, head: ListNode) -> bool:

        if not head:
            return False
        
        Hash = {}
        temp = head
        while temp != None:
            if Hash.get(temp):
                return True
            else:
                Hash[temp] = True
            temp = temp.next
        return False

找出环路链表的入口

通过计算可以知道,快指针走的距离是慢指针距离的两倍,同时快指针比慢指针多走了一个圆的距离。所以在快慢指针相遇的地方,两个指针以相同的数据在走下去,相遇的地方就是环的入口

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:

        first = head
        second = head

        while first and first.next:
            first = first.next.next
            second = second.next
            if first == second:
                first = head
                while True:
                    if first == second:
                        return first
                    first = first.next
                    second = second.next
                    
        
        return None

链表排序

使用链表这样数据结构实现排序,归并排序的实现如下:
先分开,后合并

def sortList(self, head: ListNode) -> ListNode:
        if not head or not head.next: 
            return head
        slow = head
        fast = head
        # 用快慢指针分成两部分
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        # 找到左右部分, 把左部分最后置空
        mid = slow.next
        slow.next = None
        # 递归下去
        left = self.sortList(head)
        right = self.sortList(mid)
        # 合并
        return self.merge(left, right)

    def merge(self, left, right):
        dummy = ListNode(0)
        p = dummy
        l = left
        r = right

        while l and r:
            if l.val < r.val:
                p.next = l
                l = l.next
                p = p.next
            else:
                p.next = r
                r = r.next
                p = p.next
        if l:
            p.next = l
        if r:
            p.next = r
        return dummy.next

相交链表

编写一个程序,找到两个单链表相交的起始节点。

在节点 c1 开始相交。
原理:两个链表是否有相交的地方,可以通过如下方法测试出来:
走完A之后,从B起始点开始走,同样,走完B之后,从A开始走,这样如果有相交的位置,那么A和B到相交的位置就刚好一致。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:

        if not(headA and headB):
            return None
        nodea = headA
        nodeb = headB

        while nodea != nodeb:
            
            if nodea is None:
                nodea = headB
            else:
                nodea = nodea.next

            if nodeb is None:
                nodeb = headA
            else:
                nodeb = nodeb.next

        return nodea

两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

输入:head = [1,2,3,4]
输出:[2,1,4,3]

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
       
        pre_head = ListNode(-1)
        pre_head.next = head
       
        pre_h = pre_head
        p = head

        while p and p.next:
            next_p = p.next
            p.next = next_p.next
            pre_h.next = next_p
            next_p.next = p

            pre_h = p
            p = p.next

        return pre_head.next

两个连表生成相加链表

假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。
给定两个这种链表,请生成代表两个整数相加值的结果链表。
例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

class Solution:
    def addInList(self , head1 , head2 ):
        def reverse_fun(head):
            pre = None
            p = head
            while p:
                temp = p.next
                p.next = pre 
                pre = p 
                p = temp 
            return pre 
        re_head1 = reverse_fun(head1)
        re_head2 = reverse_fun(head2)
        d = ListNode(0)
        p = d 
        c = 0
        while re_head1 or re_head2 or c:
            if re_head1:
                c += re_head1.val
                re_head1 = re_head1.next
            if re_head2:
                c += re_head2.val
                re_head2 = re_head2.next
            p.next = ListNode(c % 10)
            p = p.next
            c = c // 10
        return reverse_fun(d.next)

链表解题总结

链表是我喜欢的数据结构,因为链表没有太多复杂操作。通常是遍历链表一直到尾节点,然后一边遍历一边配合指针操作。在链表中有几个小技巧可以好好总结一下:

  1. 使用快慢指针可以找到链表的中间位置。
    一个指针是快指针,每次走两步,一个指针是慢指针,每次走一步。当快指针到末尾时,慢指针刚好在链表的中间位置。使用场景:回文链表,归并排序
while first and first.next:
    first = first.next.next
    second = second.next
  1. 带头结点的指针更好操作。在函数中,创建一个带头结点指针更方便操作。
    node = ListNode(None)
    使用场景:删除节点,翻转节点

  2. 链表取奇偶很简单,next的next就能保证奇偶

标签:head,slow,ListNode,self,next,链表,算法,刷题
来源: https://www.cnblogs.com/goldsunshine/p/14930723.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有