关于链表的一些操作总结

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/will4906/article/details/82934375

链表反转

这是一个简单的链表操作问题,在leetcode上面有52.7%的通过率,难度是简单。但是还是想在这里基于python做一下总结,顺便总结一下链表的各种操作。

首先先看一下leetcode上面的题目:

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

看完了题目,很直白,就是转过来。我们尝试对这道题进行解决。这道题用python至少会有三种解决方案。
首先是链表的数据结构定义:

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
  1. 将链表遍历进list中,然后利用切片反转list,再将list填充到链表中即可。这是最简单的一种思考逻辑,但是也比较消耗性能。时间和空间复杂度都为O(n)。
def loop(head):
    temp = []
    while head is not None:
        temp.append(head)
        head = head.next
    temp = temp[::-1]
    for i, n in enumerate(temp):
        if i + 1 < len(temp):
            n.next = temp[i + 1]
        else:
            n.next = None
    return temp[0] if temp else None
  1. 另一种迭代算法,是一种纯粹交换的迭代,笔者这里截取了leetcode速度最快的一种。
def reverseList(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head:
        return None
    it = head; jt = head.next
    it.next = None
    while jt:
        tmp = it
        it = jt
        jt = jt.next
        it.next = tmp
    return it

这一波交换操作,我们可以画个示意图就知道他的交换是一种怎么样的交换。

在这里插入图片描述

从图中可以看出,循环的作用就是将反向指针进行保存。同时令将指针转向的功能。

  1. 最后一种方案是采用递归的方式进行链表反转。这种方式也需要一定的理解。我们先展示一下代码。
def reverseList(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if head is None or head.next is None:
        return head
    end = reverseList(head.next)
    head.next.next = head
    head.next = None
    return end

这种解法其实理解起来只有两部分内容,传递反向指针和进行指针反向拼接。我们先来理解一下指针反向拼接这个操作。

1 -> 2 -> 3 -> 4 -> None
依次:
3(head) -> 4(head.next) -> 3(head.next.next)
3 -> None

如此循环即可将链表反转过来。但是还有个关键就是将最后一个指针传递出来。我们可以看到之前的代码中,end传出来后是一直没有做任何操作的。不停的return出最后一个指针。所以就将最后一个指针传递了出来。

以上就是链表反转的3中方法。除此之外还想写一些链表的简单操作。

快慢指针

何为快慢指针,即对链表进行两个不同步频的指针标记遍历。最经典的是慢指针走一步,快指针走两步。
快慢指针有很多的应用,比如说:

  1. 判断一个链表是否存在环
def hasCycle(head):
    """
    :type head: ListNode
    :rtype: bool
    """
    if head is None or head.next is None:
        return False
    fast, slow = head.next.next, head.next
    while fast is not slow:
        if fast is None or fast.next is None:
            return False
        fast = fast.next.next
        slow = slow.next
    return True

两个指针并排走,如果有环的话快指针最终会指向慢指针的位置。没有环的话,快指针会指向None后退出。

当然这道题的解法不止这一样,还可以利用set进行判断。

  1. 输出链表中的倒数第K个节点

这道题利用快慢指针的思路是这样的。定义两个指针,第一个指针向前走k-1步;第2个指针保持不动;到第k步时第2个指针也开始移动。由于两个指针始终保持着k-1的距离,所以当快指针到达末尾时,慢指针刚好指向倒数第k个。

def count_back(head, k):
    if head is None:
        return head
    fast, slow = head, head
    for i in range(k - 1):
        fast = fast.next
        if fast is None:
            return None
    while fast is not None:
        fast = fast.next
        slow = slow.next
    return slow

这是关于链表的两种比较简单的操作,反转和快慢指针。挺常见的面试题,在这里做一些记录分享。

猜你喜欢

转载自blog.csdn.net/will4906/article/details/82934375