python | 算法-链表结构、反转、公共部分、回文结构、按值划分

针对b站视频左神算法与数据结构,自己练习对应的python代码

相关链接:

1️⃣b站视频地址

2️⃣视频笔记(其实主要是题目截图)

链表

一、链表结构

参考链接在这里

节点结构:

# 链表的基本结构--节点

class Node:
    def __init__(self, cargo=None, next=None):
        self.cargo = cargo
        self.next = next
        
    def __str__(self):
        #测试基本功能输出字符串
        return str(self.cargo)

print(Node(5))
# 输出5

链表结构和基本运算:

class Node():
    """
    链表的基本结构--节点
    """
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next

    def __str__(self):
        return str(self.data)

class LinkedList():
    """
    链表结构及基本操作
    """
    def __init__(self, head=None):
        self.head = head

    def __len__(self):
        #功能:给定头节点返回链表的长度
        cur = self.head
        res = 0
        while cur is not None:
            res += 1
            cur = cur.next
        return res

    def insertFront(self, data):
        #功能:从前插入数据
        if data is None:
            return None
        node = Node(data, self.head)
        self.head = node
        return node

    def append(self, data):
        #功能:从链表后面追加数据
        if data is None:
            return None

        node = Node(data)
        if self.head is None:
            self.head = node
            return node

        cur = self.head
        while cur.next is not None:
            cur = cur.next
        cur.next = node
        return node

    def find(self, data):
        #功能:查找数值等于data的节点
        if data is None:
            return None

        cur = self.head
        while cur is not None:
            if cur.data == data:
                return cur

        return None

    def delete(self, data):
        #功能:删除链表中数值等于data的节点
        if data is None: return
        if self.head is None: return
        if self.head.data == data:
            self.head = self.head.next
            return

        pre_node = self.head
        cur_node = self.head.next
        while cur_node is not None:
            if cur_node.data == data:
                pre_node.next = cur_node.next
            else:
                pre_node = cur_node
                cur_node = cur_node.next
                
    def deleteAlt(self, data):
        #功能:删除节点方法2
        if data is None: return
        if self.head is None: return
        if self.head.data == data:
            self.head = self.head.next
            return
        pre_node = self.head
        while pre_node.next is not None:
            if pre_node.next.data == data:
                pre_node.next = pre_node.next.next
            pre_node = pre_node.next

二、反转单向和双向链表

Q1:分别实现反转单向链表和反转双向链表的函数

req:如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度为O(1)

#反转单向链表

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

class LinkedList():
    def __init__(self, head=None):
        self.head = head

    def reverseList(self):
        if self.head.next is None: return

        cur_node = self.head.next
        self.head.next = None
        cur_next = cur_node.next
        cur_node.next = self.head
        self.head = cur_node

        while cur_next is not None:
            cur_node = cur_next
            cur_next = cur_node.next
            cur_node.next = self.head
            self.head = cur_node
#双向链表的反转

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

class duLinkedList():
    def __init__(self, head=None):
        self.head = head

    def reverse(self):
        pre_node = self.head.last
        while self.head.next is not None:
            next_node = self.head.next
            self.head.next = pre_node
            self.head.last = next_node
            pre_node = self.head
            self.head = next_node
        self.head.next = pre_node
        self.head.last = None

三、打印两个有序链表的公共部分

image

#打印两个 有序 链表 的公共部分

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

def Len(head):
    res = 0
    while head:
        res += 1
        head = head.next
    return res

def iseq(node1, node2):
    return node1.data == node2.data and node1.next == node2.next and id(node1) == id(node2)

def ComPart(head1, head2):
    len1, len2 = Len(head1), Len(head2)
    p1 = head1 if len1 > len2 else head2
    for i in range(abs(len1-len2)):
        p1 = p1.next
    p2 = head2 if len1 > len2 else head1
    while p1:
        if iseq(p1, p2):
            print(p1.data)
        p1 = p1.next
        p2 = p2.next


if __name__ == '__main__':
    head1 = Node(1)
    n2 = Node(2)
    n3 = Node(2)
    n4 = Node(3)
    n5 = Node(3)
    n6 = Node(4)
    head2 = Node(2)
    n7 = Node(3)

    head1.next = n2
    n2.next = n3
    n3.next = n4
    n4.next = n5
    n5.next = n6
    head2.next = n7
    n7.next = n4

    ComPart(head1, head2)
# 输出 3, 3, 4

四、判断一个链表是否为回文结构

image

补充知识:Python用列表实现堆栈

#判断一个链表是否为回文结构

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

def isPalindrome1(head):
    """
    function 1 -> space=O(N)
    :param head: Node
    :return: bool
    """
    if head is None or head.next is None:
        return True
    # step1 all nodes put in the stack
    stack = []
    p = head
    while p is not None:
        stack.append(p.data)
        p = p.next
    # step2 out stack and compare
    while len(stack):
        if stack.pop() != head.data:
            return False
        head = head.next
    return True

def isPalindrome2(head):
    """
    function2 -> space=O(1)
    :param head: Node
    :return: bool
    """
    if head is None or head.next is None:
        return True
    # step1 find mid node
    n1, n2 = head, head
    while n2.next is not None and n2.next.next is not None:
        n1 = n1.next # n1 -> mid
        n2 = n2.next.next # n2 -> end
    n2 = n1.next # n2 -> right first node
    n1.next = None # mid.next -> None
    # step2 reverse right part
    while n2 is not None:
        tmp = n2.next # tmp -> save next node
        n2.next = n1 # n2.next connect mid
        n1 = n2 # n1 -> save pre node
        n2 = tmp # n2 move

    # now n1 is last node
    tmp = n1 # tmp -> save last node
    n2 = head
    # step3 check palindrome
    res = True
    while n1 is not None and n2 is not None:
        if n1.data != n2.data:
            res = False
            break
        n1 = n1.next
        n2 = n2.next
    # step4 recover list
    n1 = tmp.next # tmp -> last node
    tmp.next = None
    while n1 is not None:
        n2 = n1.next # n2 -> save next node
        n1.next = tmp # reverse
        tmp = n1 # tmp -> save pre node
        n1 = n2 # n1 move

    return res

五、单链表按值划分

image

# 单链表划分

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

def ListPartition(head, pivot):
    """
    Partition a linkedlist into left less-than, mid equal and right more-than pivot
    :param head:Node
    :param pivot:int
    :return:Node
    """
    if head is None or head.next is None:
        return head
    cur, p1, p2, p3 = head, None, None, None
    # partiton into three parts: less, equal, more
    while cur is not None:
        lat = cur.next
        if cur.data < pivot:
            if p1 is None:
                p1_tail = cur # tail of less-than part
            cur.next = p1
            p1 = cur # p1 -> head node of less-than part
        elif cur.data == pivot:
            if p2 is None:
                p2_tail = cur # tail of equal part
            cur.next = p2
            p2 = cur # p2 -> head of equal part
        else:
            cur.next = p3
            p3 = cur # p3 -> head of more-than part
        cur = lat # cur move
    # connect three parts
    if p1 is None:
        if p2 is None:
            return p3
        else:
            p2_tail.next = p3
            return p2
    elif p2 is None:
        p1_tail.next = p3
        return p1
    elif p3 is None:
        p1_tail.next = p2
        return p1
    else:
        p1_tail.next = p2
        p2_tail.next = p3
        return p1

    p1_tail.next = p2
    p2_tail.next = p3
    return p1

🤔上面代码没有完成进阶要求:保持各部分原本的相对顺序

(上面代码用的每个部分都用的头插法,所以最后每部分顺序刚好与原来顺序相反,改成尾插法就可以保持相对顺序了)

并且后面整合三个部分的代码不够优雅简洁

优雅的代码还得左神,看了视频里左神的代码,我又优化了一遍

# 单链表划分
# Time:O(N)
# Space:O(1)
class Node():
    def __init__(self, data=None, next=None):
        self.data = data
        self.next = next

def ListPartition(head, pivot):
    sh = None # small head
    st = None # small tail
    eh = None # equal head
    et = None # equal tail
    mh = None # big head
    mt = None # big tail
    # step1 partition according to small, equal and big
    while head is not None:
        next = head.next # next -> save next node
        head.next = None # head -> current node
        if head.data < pivot:
            if sh is None: # firt small node
                sh = head
                st = head
            else:
                st.next = head # connect to tail node
                st = head # tail node move
        elif head.data == pivot:
            if eh is None: # first equal node
                eh = head
                et = head
            else:
                et.next = head
                et = head
        else:
            if mh is None: # first big node
                mh = head
                mt = head
            else:
                mt.next = head
                mt = head
        head = next # current node move

    # step2 connect all parts
    if sh is not None:
        st.next = eh
        et = et if eh is not None else st # et -> connect to mh
    if et is not None: # have small or equal
        et.next = mh
    return sh if sh is not None else (eh if eh is not None else mh)

下一条更新,放在这里了

posted @ 2022-08-17 17:57  万国码aaa  阅读(82)  评论(0编辑  收藏  举报