题目难度:普及+/提高
题目描述
您需要写一种数据结构,来维护一些数( 都是 10^9 以内的数字)的集合,最开始时集合是空的。其中需要提供以下操作,操作次数 q 不超过 10^4:
- 查询 x 数的排名(排名定义为比当前数小的数的个数 +1。若有多个相同的数,应输出最小的排名)。
- 查询排名为 xx的数。
- 求 x 的前驱(前驱定义为小于 x,且最大的数)。若未找到则输出 -2147483647。
- 求 x 的后继(后继定义为大于 x,且最小的数)。若未找到则输出 2147483647。
- 插入一个数 x。
输入输出样例
输入
7 5 1 5 3 5 5 1 3 2 2 3 3 4 3
输出:
2 3 1 5
思路:
用链表+二分答案来解决,链表(LinkedList类)来储存数据,这个类基本内置了链表的所有方法。先插入两个元素-2147483647,2147483647作为链表的下界与上界,在查询的时候可以防止链表越界,在插入元素的过程中可以先用二分答案来查找应该插入的位置,再调用Linkedlist类的add方法直接在该位置添加元素,该位置后面元素会自动后移,
求x的前驱后继也能用二分答案来解决。
同时注意理解题意,x可能是不存在于链表中的。
注意二分答案用法,需要厘清如何求满足目标条件的最大值,或者满足目标条件的最小值。
AC代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
public class Main {
static List<Integer> list=new LinkedList<>();
static int size=2;
public static void main(String[] args) throws Exception{
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));//快速输出
Read read=new Read();//快读
int n=read.nextInt();
list.add(-2147483647);//添加上界与下界
list.add(2147483647);
while(n-->0) {
int op=read.nextInt();
int num=read.nextInt();
switch (op) {
case 1: {
out.println(lower(num)+1);//注意,num可能不存在,所以要找到比num小的数中最大的一个的下标,再+1;
break;
}
case 2:{
out.println(list.get(num));
break;
}
case 3:{
int index=lower(num);
out.println(list.get(index));
break;
}
case 4:{
int index=higher(num);//二分答案
out.println(list.get(index));
break;
}
case 5:{
int index=higher(num); //二分答案
list.add(index, num);;
size++;
break;
}
}
}
out.flush();
}
//二分答案:查找小于目标数的最大数的下标, 例如 1 2 4 5 ,target为3,小于target的最大的数为2。
static int lower(int target) {
int left=0;
int right=size-1;
while(left<right) {
int mid=(left+right)/2;
if(list.get(mid)>=target)
right=mid;
else {
left=mid+1;
}
}
return left-1;
}
//二分答案,查找大于目标数的的最小的一个。
static int higher(int target){
int left=0;
int right=size-1;
while(left<right) {
int mid=(left+right)/2+1;
if(list.get(mid)<=target) {
left=mid;
}
else {
right=mid-1;
}
}
return left+1;
}
}
class Read{
StreamTokenizer st=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public int nextInt() throws Exception{
st.nextToken();
return (int)st.nval;
}
}