洛谷 P1160 队列安排【Python】

题目链接
浅浅地记录我自己的洛谷刷题情况
这一题做的可真是花费了我九六二虎之力,因为python容易超时,不管我自己怎么苦思冥想,都总是不能AC,后面终于找到用Python做的方法了,也学到了许多


目录

一、问题重述

1.题目描述

2.输入格式

3.输出格式

4.输入输出样例

5.说明/提示

二、大概思路

三、完整AC代码

四、收获与心得


问题重述

题目描述

洛谷 P1160 队列安排【Python】_第1张图片

输入格式

洛谷 P1160 队列安排【Python】_第2张图片

输出格式

输入输出样例

#样例1
输入:
4
1 0
2 1
1 0
2
3
3
输出:
2 4 1

说明/提示

洛谷 P1160 队列安排【Python】_第3张图片


大概思路

  1. 看到这第题第一眼,我轻蔑的看一眼,就这?不就一个列表搞定嘛,所以我果断敲出了下面的代码
N = int(input())
queue = [1]
def put(people, k, p):
    # people:入队的人
    # k:要在几号同学旁边入队
    # p:在他的左边还是右边
    idx = queue.index(k)        # 找到k的下标
    if p == 0:                  # 如果要在k同学的左边入队
        queue.insert(idx, people)
    else:
        queue.insert(idx + 1, people)

def out(s):
    for i in s:
        queue.remove(i)

for people in range(2, N + 1):
    k, p = map(int, input().split())
    put(people, k, p)

M = int(input())
s = set()
for i in range(M):
    s.add(int(input()))
out(s)
n = len(queue)
for i in range(n):
    if i != n - 1:
        print(queue[i], end=" ")
    else:
        print(queue[i])

然而我小看了普及难度的题目,他果断给我抛出了
洛谷 P1160 队列安排【Python】_第4张图片
后面我看了以下数据大小,100000这说大不大说小不小的数字,让进行插入和删除操作的时候,因为列表是在内存空间里面一段连续的区域,每次插入删除都要移动后面的数据,100000这么多次反复操作,时间损耗可想而知

2.于是我查了以下,发现这题应该用链表实现,因为链表的插入和删除不用移动后面的数据,这样他的时间复杂度应该是可以大大缩小的,然而,当我满是自信的交出下面的代码时

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

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

    def append(self):
        node = Node(1)
        self.head = node

    def insert(self, number, k, p):
        node = Node(number)
        cur = self.head
        while cur:
            if cur.item == k:           # 找到要插入的位置
                if p == 0:              # 如果要站在他的左边
                    if not cur.pre:
                        self.head = node
                        node.next = cur
                        cur.pre = node
                        return
                    else:
                        cur.pre.next = node
                        node.pre = cur.pre
                        node.next = cur
                        cur.pre = node
                        return
                else:
                    node.next = cur.next
                    cur.next.pre = node
                    cur.next = node
                    node.pre = cur
                    return
            cur = cur.next


    def pop(self, lst):
        count = 0           # 已经删除的元素的个数
        while count < len(lst):
            cur = self.head
            while cur:
                if cur.item in lst:
                    if not cur.pre:
                        self.head = cur.next
                        cur.next.pre = None
                    elif not cur.next:
                        cur.pre.next = None
                    else:
                        cur.pre.next = cur.next
                        cur.next.pre = cur.pre
                    count += 1
                cur = cur.next

    def print_llst(self):
        cur = self.head
        while cur:
            if cur.next:
                print(cur.item, end=" ")
            else:
                print(cur.item)
            cur = cur.next


L = LinkList()
L.append()
N = int(input())
for number in range(2, N + 1):
    k, p = map(int, input().split())
    L.insert(number, k, p)
M = int(input())
del_s = set()
for i in range(M):
    del_s.add(int(input()))
L.pop(del_s)
L.print_llst()

OJ给了我狠狠的一把掌,让我无限接近与崩溃边缘
洛谷 P1160 队列安排【Python】_第5张图片
这让我百思不得其解,到底是什么问题呢?于是我认真的反思我的这些代码,发现每次插入和删除的时候我都需要遍历整个链表,这使得我的代码执行效率大大降低,终于,让我发现了别人的优秀的代码,我发现他用列表巧妙的处理了这一问题,最终,得出了我的AC代码


完整AC代码

class Node:
    def __init__(self, date, prev, next):
        self.date = date
        self.prev = prev
        self.next = next
        self.flag = True

N = int(input())
a = [None] * (N + 1)
a[0] = Node(0, a[0], a[0])
a[1] = Node(1, a[0], a[0])
a[0].next = a[1]
a[0].prev = a[1]
for i in range(2, N + 1):
    k, p = map(int, input().split())
    if p == 0:
        a[i] = Node(i, a[k].prev, a[k])
        a[k].prev.next = a[i]
        a[k].prev = a[i]
    else:
        a[i] = Node(i, a[k], a[k].next)
        a[k].next.prev = a[i]
        a[k].next = a[i]
M = int(input())
for i in range(M):
    x = int(input())
    a[x].flag = False

cur = a[0]
while cur.next != a[0]:
    cur = cur.next
    if cur.flag != False:
        print(cur.date, end=" ")
    # if cur.next == a[0]:  # 可以不要
    #     print()
    

收获与心得

  1. 已知N的大小后,马上创建一个列表,也就是像内存申请一片连续的空间,这样既避免了内存的浪费,也极大的便利了后续的插入和删除的相关操作
  2. 在进行插入和删除时,对应的人的编号就是他在列表中对应的下标,同时用指针来表示他们的站位关系,也用flag来表示同学是否还在队列中,当该同学要出队的时候,只需要将他的flag变为False这样在后续输出的时候我们只需要判断flag即可,避免了删除的时候移动这些后续的数据或则不断的改变他们的指针指向而增加了时间,因为我们只需要在输出的时候跳过flag为False的结点即可
  3. 这里的输出值得一提的是,即使不要最后的print()也一样能通过

你可能感兴趣的:(洛谷python题解,python,开发语言,链表)