洛谷-P1160 队列安排-java解题方法

P1160 队列安排

题目描述

一个学校里老师要将班上N个同学排成一列,同学被编号为1∼N,他采取如下的方法:

  1. 先将1号同学安排进队列,这时队列中只有他一个人;
  2. 2-N2−N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;
  3. 从队列中去掉M(M<N)个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

输入格式

第1行为一个正整数N,表示了有N个同学。

第2-N行,第ii行包含两个整数k,p,其中k为小于ii的正整数,p为0或者1。若p为0,则表示将ii号同学插入到k号同学的左边,p为1则表示插入到右边。

第N+1行为一个正整数M,表示去掉的同学数目。

接下来M行,每行一个正整数x,表示将x号同学从队列中移去,如果xx号同学已经不在队列中则忽略这一条指令。

输出格式

1行,包含最多N个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。

题解

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
	static BufferedReader scan = new BufferedReader(new InputStreamReader(System.in));
	public static void main(String[] args) throws IOException {
		int N = Integer.parseInt(scan.readLine());
		int count[] = new int[N];
		int [][]operation = new int[N+1][2];
		String []s = new String[2];
		for(int i=2;i<operation.length;i++) {
			s= scan.readLine().split(" ");
			operation[i][0] = Integer.parseInt(s[0]);
			operation[i][1] = Integer.parseInt(s[1]);
		}
		int M = Integer.parseInt(scan.readLine());
		int []numb = new int[M];
		for(int i=0;i<numb.length;i++) {
			numb[i] = Integer.parseInt(scan.readLine());
		}
		scan.close();
		
		LNode list = new LNode();
		LNode p= new LNode();
		LNode first = new LNode(1);
		list.next=first;
		first.prime = list;

		for(int i=2;i<operation.length;i++) {
			p = list.next;
			p.insert(p, i, operation[i][0], operation[i][1]);
		}
		
		for(int i=0;i<numb.length;i++) {
			p = list.next;
			p.delete(p,numb[i],count);
		}
		
		p = list.next;
		
		while(p!=null) {
			System.out.print(p.data+" ");
			p=p.next;
		}
	}
}

class LNode {
	public int data;
	public LNode prime;
	public LNode next; 
	
	public LNode(int data) {
		this.data = data;
	}
	public LNode() {
	}
	
	void insert(LNode p,int i,int location,int direction) {
		LNode l = new LNode(i);
		while(p.data!=location) {
			p=p.next;
		}
		if(direction== 0) {         //向左插
			l.next = p.prime.next;
			l.prime = p.prime;
			p.prime.next = l;
			p.prime = l;
		}else { 					//向右插
			if(p.next==null) {
				l.prime = p;
				p.next = l;
			}else {
				l.prime = p;
				l.next = p.next;
				p.next.prime = l;
				p.next = l;
			}
		}
	}
	
	void delete(LNode p,int data,int []count) {
		if(count[data]==1) {
			return;
		}
		while(p!=null) {
			if(p.data==data) {
				if(p.next==null) {
					p.prime.next=null;
				}else {
					p.prime.next=p.next;
					p.next.prime=p.prime;
				}
				count[data] = 1;
				break;
			}
			p=p.next;
		}
	}

	@Override
	public String toString() {
		return this.data+"";
	}
}

注解

该题解后三个点为超时点目前还没有解决。仅提供解题思路。

2023.5.29修改(java已过100%)

一种基于LinkedList和HashMap的解决方案。在这个解决方案中,使用一个HashMap来存储值和相应节点的映射关系,使得查找操作时间复杂度为O(1)。而LinkedList用于存储数据并保持插入的顺序。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

class Node {
    int value;
    Node prev, next;

    Node(int value) {
        this.value = value;
    }
}

public class Main {
    static BufferedReader scan = new BufferedReader(new InputStreamReader(System.in));

    public static void main(String[] args) throws IOException {
        int N = Integer.parseInt(scan.readLine());

        Map<Integer, Node> nodeLookup = new HashMap<>();
        Node head = new Node(1);
        nodeLookup.put(1, head);
        //首先读取一个整数N,然后读取N行输入。每一行都包含一个整数X和一个标志B。
        //它在列表中查找值为X的元素,然后在其之前(如果B为0)或者之后(如果B为1)插入新的元素。
        //新元素的值为当前的循环次数(从2开始)。如果找不到值为X的元素,那么新元素将不会被插入。
        for (int i = 2; i <= N; i++) {
            String[] input = scan.readLine().split(" ");
            int X = Integer.parseInt(input[0]);
            int B = Integer.parseInt(input[1]);

            Node newNode = new Node(i);
            Node oldNode = nodeLookup.get(X);

            if (B == 0) {
                newNode.next = oldNode;
                newNode.prev = oldNode.prev;
                if (oldNode.prev != null) {
                    oldNode.prev.next = newNode;
                }
                oldNode.prev = newNode;
                if (oldNode == head) {
                    head = newNode;
                }
            } else {
                newNode.prev = oldNode;
                newNode.next = oldNode.next;
                if (oldNode.next != null) {
                    oldNode.next.prev = newNode;
                }
                oldNode.next = newNode;
            }

            nodeLookup.put(i, newNode);
        }
        //然后,读取一个整数M,然后读取M行输入。每一行包含一个整数,表示需要从列表中删除的元素。
        int M = Integer.parseInt(scan.readLine());
        for (int i = 0; i < M; i++) {
            int data = Integer.parseInt(scan.readLine());
            Node nodeToRemove = nodeLookup.get(data);
            if (nodeToRemove != null) {
                if (nodeToRemove.prev != null) {
                    nodeToRemove.prev.next = nodeToRemove.next;
                }
                if (nodeToRemove.next != null) {
                    nodeToRemove.next.prev = nodeToRemove.prev;
                }
                if (nodeToRemove == head) {
                    head = nodeToRemove.next;
                }
                nodeLookup.remove(data);
            }
        }

        for (Node node = head; node != null; node = node.next) {
            System.out.print(node.value + " ");
        }
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杜柠函

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值