1.5python找出单链表中的倒数第k个元素

题目描述:

找出单链表中的倒数第k个元素,如给定单链表:1->2->3->4->5->6->7,则单链表的倒数第k=3个元素为5

方法:

1. 顺序遍历两遍法

首先遍历一遍单链表,求出整个单链表的长度n,然后把求倒数第k个元素转换为求顺数第n-k个元素,再去遍历一次单链表就可以得到结果。但是该方法需要对单链表进行两次遍历。

2. 快慢指针法
由于单链表只能从头和尾依次访问链表的各个结点,因此,如果要找链表的倒数第 k 个元素,也只能从头到尾进行遍历查找。在查找的过程中,设置两个指针,让一种一个指针前移k步,然后两个指针同时往前移动。循环直到先行的指针值为 None 时,另一个指针所指的位置就是所要找的位置。

算法性能分析:

此方法只对链表进行一次遍历,所以时间复杂度为O(n);
另外由于只需要常量个指针变量来保存结点的地址信息,所以空间复杂度为O(1)

代码实现:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2020/1/16 19:35
# @Author  : buu
# @Software: PyCharm
# @Blog    :https://blog.csdn.net/weixin_44321080
class LNode:
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next


def ConstructList():
    """
    构造一个单链表
    :return: 链表的头结点
    """
    i = 1
    head = LNode()
    tmp = None
    cur = head
    while i < 8:
        tmp = LNode(i)
        cur.next = tmp
        cur = tmp
        i += 1
    return head


def PrintList(head):
    """
    顺序打印单链表结点的数据
    :param head: 单链表的头结点
    :return:
    """
    cur = head.next
    print('raw list:', end=' ')
    while cur is not None:
        print(cur.data, end=' ')
        cur = cur.next
    print()


def FindLastK(head, k):
    """
    找出链表倒数第k个结点
    :param head: 链表头结点
    :return: 倒数第k个结点
    """
    if head is None or head.next is None:
        return head
    slow = head.next
    fast = head.next
    i = 0
    while i < k and fast is not None:  # 快指针先走k步
        fast = fast.next
        i += 1
    if i < k:  # 未走k步,快指针已到链表尾部
        return None
    while fast is not None:
        fast = fast.next
        slow = slow.next
    return slow


if __name__ == '__main__':
    head = ConstructList()
    result = None
    PrintList(head)
    result = FindLastK(head, 3)
    if result != None:
        print('last3 is:', result.data)

结果:
在这里插入图片描述
引申:

如何将单链表向右旋转k个位置,即:给定单链表1->2->3->4->5->6->7,k=3,则旋转后的单链表变为5->6->7->1->2->3->4

思路:

  1. 首先找到链表倒数第k+1个结点slow和尾结点fast(如下图所示);
  2. 把链表断开为两个子链表,其中,后半部分链表结点的个数为k;
  3. 使原链表的尾结点指向链表的第一个结点(而非头结点);
  4. 使链表的头结点指向原链表倒数第k个结点;

算法性能分析:

这种方法只需要对链表进行一次遍历,所以时间复杂度为O(n);
此外,由于只需要几个指针变量来保存结点的地址信息,因此空间复杂度为O(1)
在这里插入图片描述
代码实现:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2020/1/16 20:23
# @Author  : buu
# @Software: PyCharm
# @Blog    :https://blog.csdn.net/weixin_44321080
class LNode:
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next


def ConstructList():
    """
    构造一个单链表
    :return: 链表的头结点
    """
    i = 1
    head = LNode()
    tmp = None
    cur = head
    while i < 8:
        tmp = LNode(i)
        cur.next = tmp
        cur = tmp
        i += 1
    return head


def PrintList(head):
    """
    顺序打印单链表结点的数据
    :param head: 单链表的头结点
    :return:
    """
    cur = head.next
    while cur is not None:
        print(cur.data, end=' ')
        cur = cur.next
    print()


def RotateK(head, k):
    """
    把链表右旋k个位置
    :param head: 头结点
    :param k: k个位置
    :return:
    """
    if head is None or head.next is None:
        return
    slow = head.next
    fast = head.next
    tmp = LNode()
    i = 0
    while i < k and fast is not None:
        fast = fast.next
        i += 1
    if i < k:
        return None
    while fast.next != None:  # FindLastK.py中是 fast != None
        slow = slow.next  # 循环结束后,slow指向倒数第k+1个元素;
        fast = fast.next  # fast指向最后一个元素
    tmp = slow.next  # tmp 指向包含后k个元素链表的首结点
    slow.next = None
    fast.next = head.next
    head.next = tmp


if __name__ == '__main__':
    head = ConstructList()
    print('before rotation:', end=' ')
    PrintList(head)
    RotateK(head, 3)
    print('after  rotation:', end=' ')
    PrintList(head)

结果:
在这里插入图片描述

end

发布了76 篇原创文章 · 获赞 2 · 访问量 2578

猜你喜欢

转载自blog.csdn.net/weixin_44321080/article/details/104010036