Python 算法(三、1) 链表

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

给定一个链表的头节点head,请判断该链表是否为回文结构。
例如: 1->2->1,返回true。 1->2->2->1,返回true。
15->6->15,返回true。 1->2->3,返回false。
进阶:如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。

思路1:遍历过程中,将所有结果放入栈,查看逆序和原结构是否一样,空间复杂度o(N)

思路2:将中间后面的结果放入栈,然后一起遍历比较,0(N/2)

思路3:慢指针指向中间位置,并使元素指向空,快指针指向中间多一个,然后将后面元素指向前面。空间复杂度o(1)

from queue import LifoQueue


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

class IsPalindromeList:
    def stack_method(self, head):
        stack_ = LifoQueue()
        cur = head
        while cur is not None:
            stack_.put(cur)
            cur = cur.next
        while head is not None:
            if head.value != stack_.get().value:
                return False
            head = head.next
        return True

    # need n/2 extra space
    def stack_method2(self, head):
        if head == None or head.next is None:
            return True
        right = head.next
        cur = head
        while cur.next is not None and cur.next.next is not None:
            right = right.next
            cur = cur.next.next

        stack_ = LifoQueue()
        while right is not None:
            stack_.put_nowait(right)
            right = right.next
        while not stack_.empty():
            if head.value != stack_.get().value:
                return False
            head = head.next
        return True

    # need O(1) extra space
    def no_stack_method(self, head):
        if head == None or head.next == None:
            return True
        n1 = head
        n2 = head
        while n2.next != None and n2.next.next != None:  # find mid node
            n1 = n1.next  # mid node
            n2 = n2.next.next  # end node

        n2 = n1.next  # right part first node
        n1.next = None  # mid.next-> None
        while n2 != None:  # right part revert
            n3 = n2.next  # save next node
            n2.next = n1  # next of right node convert
            n1 = n2  # n1 move
            n2 = n3  # n2 move
            # n2.next, n1 = n1, n2
        n3 = n1  # save last node
        n2 = head  # left first node
        res =True
        while n1 != None and n2 != None:
            if n1.value != n2.value:
                res = False
                break
            n1 = n1.next
            n2 = n2.next
        # final recover linked list
        n1 = n3.next
        n3.next = None
        while n1 != None:
            n2 = n1.next
            n1.next = n3
            n3 = n1
            n1 = n2
        return res

    def print_linked_list(self, node):
        print('Linked List: ')
        while node != None:
            print(node.value, ' ')
            node = node.next
        print()

    def main(self):
        head = Node(1)
        head.next = Node(2)
        head.next.next = Node(3)
        head.next.next.next = Node(1)
        self.print_linked_list(head)
        print(self.stack_method(head) , ' | ')
        print(self.stack_method2(head) , ' | ')
        print(self.no_stack_method(head) , ' | ')
        self.print_linked_list(head)
        print("1=========================")

        head = Node(1)
        head.next = Node(2)
        head.next.next = Node(3)
        head.next.next.next = Node(2)
        head.next.next.next.next = Node(1)
        self.print_linked_list(head)
        print(self.stack_method(head) , ' | ')
        print(self.stack_method2(head) , ' | ')
        print(self.no_stack_method(head) , ' | ')
        self.print_linked_list(head)
        print("2=========================")

a = IsPalindromeList()
a.main()


2、荷兰国旗链表问题

思路1: 直接将节点放入数组结构,排序后,遍历连接。空间复杂度O(N)

思路2: 空间复杂度o(1), 准备六个变量标记start和end的变量less, eq, more, 还有一个临时标记下一个数

  1. 遍历,将对应的值挂到对应遍历下面
  2. 最后将三个变量连接
class Node:
    def __init__(self, value, next=None):
        self.value = value
        self.next = next


class SmallerEqualBigger:
    def list_partition1(self, head, pivot):
        if head is None:
            return head
        cur = head
        i = 0
        while cur is not None:
            i += 1
            cur = cur.next
        node_arr = [i for i in range(i)]  # 构造总长度列表
        i = 0
        cur = head
        for i in range(len(node_arr)):
            node_arr[i] = cur
            cur = cur.next
        self.arr_partition(node_arr, pivot)
        for i in range(1, len(node_arr)):
            node_arr[i-1].next = node_arr[i]
        node_arr[i-1].next = None
        return node_arr[0]

    def arr_partition(self, node_arr, pivot):
        small = -1
        big = len(node_arr)
        index = 0
        while index != big:
            if node_arr[index].value < pivot:
                small += 1
                node_arr[small], node_arr[index] = node_arr[index], node_arr[small]
                index += 1
            elif node_arr[index].value == pivot:
                index += 1
            else:
                big -= 1
                node_arr[big], node_arr[index] = node_arr[index], node_arr[big]

    def list_partition2(self, head, pivot):
        sh, st, eh, et, bh, bt, next = [None for _ in range(7)]
        while head != None:
            next = head.next
            head.next = None
            if head.value < pivot:
                if sh is None:
                    sh,st = head,head
                else:
                    sh.next, st = head, head
            elif head.value == pivot:
                if eh is None:
                    eh,et = head,head
                else:
                    eh.next, et = head,head
            else:
                if bh is None:
                    bh,bt = head,head
                else:
                    bh.next,bt = head,head
            head = next
        if st is not None:
            st.next = eh
            et = st if et is None else et  # 不存在相等区域情况
        if et is not None:
            et.next = bh

        # return sh if sh is not None else eh if eh is not None else bh
        if sh is not None:
            return sh
        else:
            if eh is not None:
                return eh
            else:
                return bh


    def print_linked_list(self, node):
        print('Linked List: ')
        while node != None:
            print(node.value, '')
            node = node.next
        print()

    def main(self):
        head1 = Node(7)
        head1.next = Node(9)
        head1.next.next = Node(1)
        head1.next.next.next = Node(8)
        head1.next.next.next.next = Node(5)
        head1.next.next.next.next.next = Node(2)
        head1.next.next.next.next.next.next = Node(5)
        self.print_linked_list(self.list_partition1(head1, 5))
        self.print_linked_list(self.list_partition2(head1, 5))
        

SmallerEqualBigger().main()


3、 复制含有随机指针节点的链表

Node类中的value是节点值,next指针和正常单链表中next指针的意义
一 样,都指向下一个节点,rand指针是Node类中新增的指针,这个指
针可 能指向链表中的任意一个节点,也可能指向null。 给定一个由
Node节点类型组成的无环单链表的头节点head,请实现一个 函数完成
这个链表中所有结构的复制,并返回复制的新链表的头节点。 进阶:
不使用额外的数据结构,只用有限几个变量,且在时间复杂度为 O(N)
内完成原问题要实现的函数。

思路1:准备哈希表,将原节点和新节点以kv形式存入,遍历

思路2:复制原节点,
1、重新构造链表为1->1’->2->2’->3->3’
2、一次取出两个节点,假如节点1和1’,主要获取rand指针问题,这里1的rand指针为3,而3的next指针为3’
3、然后设置1’的rand指向3’,依次就可以完成全部复制

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


class CopyListWithRandom:
    def copy_random_linked(self, head):
        map = {}
        cur = head
        while cur is not None:
            map[cur] = Node(cur.value)
            cur = cur.next
        cur = head
        while cur is not None:
            map[cur].next = map[cur.next] if cur.next is not None else None
            map[cur].rand = map[cur.rand] if cur.next is not None else None
            cur = cur.next
        return map[head]

    def copy_random_linked2(self, head):
        if head is None:
            return None
        cur = head
        # 1-1'-2-2'-3-3'-None
        while cur is not None:
            nor_next = cur.next
            cur.next = Node(cur.value)
            cur.next.next = nor_next  # 然后1'->2
            cur = nor_next
        cur = head
        # 设置复制node rand
        while cur is not None:
            nor_next = cur.next.next
            cur_copy = cur.next
            cur_copy.rand = cur.rand.next if cur.rand is not None else None
            cur = nor_next
        res = head.next
        cur = head
        while cur is not None:
            old_node = cur.next.next
            copy_node = cur.next
            cur.next = old_node
            copy_node.next = old_node.next if old_node is not None else None
            cur = old_node
        return res



    def print_linked_list(self, node):
        print('Linked List: ')
        while node != None:
            print(f'next: {node.value}, rand: {node.rand.value if node.rand is not None else None}')
            node = node.next
        print()

    def main(self):

        """
        next: 1->2->3->None
        random: 1->3, 2->1, 3->None

        """
        head1 = Node(1)
        head1.next = Node(2)
        head1.next.next = Node(3)

        head1.rand = head1.next.next
        head1.next.rand = head1
        head1.next.next.rand = None

        self.print_linked_list(self.copy_random_linked(head1))
        self.print_linked_list(self.copy_random_linked2(head1))


CopyListWithRandom().main()


4、两个单链表相交问题

单链表可能有环,也可能无环。给定两个
单链表的头节点 head1和head2,这两个链表可能相交,也可能
不相交。请实现一个函数, 如果两个链表相交,请返回相交的
第一个节点;如果不相交,返回null 即可。 要求:如果链表1
的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外
空间复杂度请达到O(1)。

首先:判断有没有环

思路1:准备哈希表、先遍历A链表放入哈希表,再遍历B链表是否存在即可

思路2:准备两个变量,一个慢指针,一个快指针

  1. 快指针每次走两步,慢指针走一步
  2. 碰到即有环,然后快指针回到head,快慢各走一步就是入环的位置。反之碰到None为无环

a、都无环的情况

  1. 准备4个变量,head1的长度、end1、head2的长度、end2
  2. end1等于end2即有环,先遍历长的链表到等于另一个长度,然后一起遍历即可找出相同点

b、一有环、一无环,不可能相交,违背单链表定义

c、都有环的情况,交点三种情况: 无相交、一个交点、两个交点

  • 一个交点:准备4个变量,开始判断有无环的时候,获取到了入环节点loop,loop1和2相等
  • 无交点或两个交点:loop1和2不相等,继续让从loop1遍历看是否碰到loop2来判断
class Node:
    def __init__(self, data, next=None):
        self.value = data
        self.next = next


class GetIntersectNode:
    def get_intersect_node(self, head1, head2):
        if head1 is None or head2 is None:
            return None
        loop1 = self.get_loop_node(head1)
        loop2 = self.get_loop_node(head2)
        # 都无环
        if loop1 is None and loop2 is None:
            return self.no_loop(head1, head2)
        # 都有环
        elif loop1 is not None and loop2 is not None:
            return self.both_loop(head1, loop1, head2, loop2)
        # 一个有环一个无环
        return None

    def get_loop_node(self, head):
        if head is None or head.next is None or head.next.next is None:
            return None
        n1 = head.next  # slow pointer
        n2 = head.next.next  # fast pointer
        while n1 != n2:
            if n2.next is None or n2.next.next is None:
                return None
            n2 = n2.next.next
            n1 = n1.next
        n2 = head
        # 最后获取入环节点
        while n1 != n2:
            n1 = n1.next
            n2 = n2.next
        return n1

    def no_loop(self, head1, head2):
        if head1 is None and head2 is None:
            return None
        cur1 = head1
        cur2 = head2
        n = 0
        while cur1.next is not None:
            n += 1
            cur1 = cur1.next
        while cur2.next is not None:
            n -= 1
            cur2 = cur2.next
        if cur1 != cur2:
            return None
        cur1 = head1 if n > 0 else head2  # 长链表
        cur2 = head2 if cur1 == head1 else head2  # 短链表,相反
        n = abs(n)
        while n != 0:
            n -= 1
            cur1 = cur1.next
        while cur1 != cur2:
            cur1, cur2 = cur1.next, cur2.next
        return cur1

    def both_loop(self, head1, loop1, head2, loop2):
        cur1 = None
        cur2 = None
        if loop1 == loop2:
            cur1,cur2,n = head1,head2,0
            while cur1 != loop1:
                n += 1
                cur1 = cur1.next
            while cur2 != loop2:
                n -= 1
                cur2 = cur2.next
            cur1 = head1 if n>0 else head2
            cur2 = head2 if cur1==head1 else head1
            n = abs(n)
            while 0 != n:
                n -= 1
                cur1 = cur1.next
            while cur1 != cur2:
                cur1 = cur1.next
                cur2 = cur2.next
            return cur1
        else:
            cur1 = loop1.next
            while cur1 != loop1:
                if cur1 == loop2:
                    return loop1
                cur1 = cur1.next
            return None

    def main(self):
        # 一、都无环
        # 1-2-3-4-5-6-7-None
        head1 = Node(1)
        head1.next = Node(2)
        head1.next.next = Node(3)
        head1.next.next.next = Node(4)
        head1.next.next.next.next = Node(5)
        head1.next.next.next.next.next = Node(6)
        head1.next.next.next.next.next.next = Node(7)

        # 0-9-8-6-7-None
        head2 = Node(0)
        head2.next = Node(9)
        head2.next.next = Node(8)
        head2.next.next.next = head1.next.next.next.next.next  # 8->6
        print(self.get_intersect_node(head1, head2).value)  # 6

        # 相同环
        # 1->2->3->4->5->6->7->4...
        head3 = Node(1)
        head3.next = Node(2)
        head3.next.next = Node(3)
        head3.next.next.next = Node(4)
        head3.next.next.next.next = Node(5)
        head3.next.next.next.next.next = Node(6)
        head3.next.next.next.next.next.next = Node(7)
        head3.next.next.next.next.next.next = head3.next.next.next # 7->4

        # 0->9->8->2...
        head4 = Node(0)
        head4.next = Node(9)
        head4.next.next = Node(8)
        head4.next.next.next = head3.next # 8->2
        print(self.get_intersect_node(head3, head4).value)  # 2

        # 不相同环
        # 0->9->8->6->4->5->6..
        head5 = Node(0)
        head5.next = Node(9)
        head5.next.next = Node(8)
        head5.next.next.next = head3.next.next.next.next.next # 8->6
        print(self.get_intersect_node(head3, head5).value)  # 6
        # 6,2,6


GetIntersectNode().main()


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值