一、题目
二、分析
题目比之前的CIDR合并好读很多,这题第一步同样也是处理输入,然后直接将三种选择的选择方法编写出来,依次选择即可。
1、输入
输入主要是n行HTML文档和m行元素选择器。对于HTML文档,每一行需要记录的信息有级别、元素以及属性。对于元素选择器,每一行需要记录的有种类,后代等级(对于后代选择器来说)以及选择器的具体内容。
清晰了输入的重点信息,就可以建立HTML的元素选择器的数据结构了,然后分别用两个链表存储它们,方便遍历。
class HtmlLine {
int rank;
String factor;
String attribute;
public HtmlLine(int rank,String factor,String attribute)
{
this.rank=rank;
this.factor=factor;
this.attribute=attribute;
}
}
class Select {
int kind; //1:标签选择器 2:id选择器 3:后代选择器
int c; //后代选择器的等级,若是不是后代选择器,默认为0
String s;
public Select(int kind,int c,String s)
{
this.kind=kind;
this.c=c;
this.s=s;
}
}
2.处理标签选择器和id选择器
这两类的处理过程十分类似,需要注意的就是,一个区分大小写,一个不区分大小写
3.处理后代选择器
这里题目其实已经提示了,对于除最后一级之外的,采用贪心策略,每一次选择HTML等级最小的对应行,然后后面的搜索从上一次行的下一行开始即可。
三、代码
package 元素选择器3;
/* 测试数据
输入:
11 5
html
..head
....title
..body
....h1
....p #subtitle
....div #main
......h2
......p #one
......div
........p #two
p
#subtitle
h3
div p
div div p
输出:
3 6 9 11
1 6
0
2 9 11
1 11
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
class HtmlLine {
int rank;
String factor;
String attribute;
public HtmlLine(int rank,String factor,String attribute)
{
this.rank=rank;
this.factor=factor;
this.attribute=attribute;
}
}
class Select {
int kind; //1:标签选择器 2:id选择器 3:后代选择器
int c; //后代选择器的等级,若是不是后代选择器,默认为0
String s;
public Select(int kind,int c,String s)
{
this.kind=kind;
this.c=c;
this.s=s;
}
}
public class Main {
static int n,m;
static List<HtmlLine> html = new ArrayList<HtmlLine>();
static List<Select> select = new ArrayList<Select>();
private static void storehtml(String line) //存储每一行HTML
{
int pnum = 0;
boolean flag = false;
String factor="";
String attribute="#";
for(int j=0;j<line.length();j++)
{
char pos = line.charAt(j);
if(pos=='.')
pnum++;
else if(!flag&&pos!=' '&&pos!='#')
factor+=pos;
else if(pos==' '||pos=='#')
flag=true;
else if(flag)
attribute+=pos;
else continue;
}
html.add(new HtmlLine(pnum/2,factor,attribute));
}
private static void storeselect(String s) //存储每一行元素选择器
{
int num=0; //空格数量
boolean flag = false; //是否有#
for(int j=0;j<s.length();j++)
{
char pos = s.charAt(j);
if(pos==' ')
num++;
if(pos=='#')
flag=true;
}
if(!flag&&num==0) //标签选择器
select.add(new Select(1,0,s));
else if(flag) //id选择器
select.add(new Select(2,0,s));
else if(!flag&&num!=0) //后代选择器
select.add(new Select(3,num+1,s));
}
private static void labelSelect(String label) //标签选择器,大小写不敏感
{
List<Integer> number = new ArrayList<Integer>();
for(int i=0;i<n;i++)
if(html.get(i).factor.equalsIgnoreCase(label))
number.add(i+1);
System.out.print(number.size()+" ");
for(int i=0;i<number.size();i++)
System.out.print(number.get(i)+" ");
System.out.println("");
}
private static void idSelect(String id) //id选择器,大小写敏感
{
List<Integer> number = new ArrayList<Integer>();
for(int i=0;i<n;i++)
if(html.get(i).attribute.equals(id))
number.add(i+1);
System.out.print(number.size()+" ");
for(int i=0;i<number.size();i++)
System.out.print(number.get(i)+" ");
System.out.println("");
}
private static void offspringSelect(String o,int c) //后代选择器,贪心策略
{
String[] str = o.split(" ");
int start=0;
for(int i=0;i<c-1;i++)
{
String l = str[i].trim();
for(int j=start;j<n;j++)
{
if(html.get(j).factor.equalsIgnoreCase(l))
{
start=j+1;
break;
}
}
}
List<Integer> number = new ArrayList<Integer>();
for(int k=start;k<n;k++)
{
if(html.get(k).factor.equalsIgnoreCase(str[c-1]))
number.add(k+1);
}
System.out.print(number.size()+" ");
for(int i=0;i<number.size();i++)
System.out.print(number.get(i)+" ");
System.out.println("");
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
in.nextLine(); //这里要换一下行,否则会读入一个空行
for(int i=0;i<n;i++)
storehtml(in.nextLine());
for(int i=0;i<m;i++)
storeselect(in.nextLine());
for(int i=0;i<m;i++)
{
Select t = select.get(i);
if(t.kind==1) //标签选择器
labelSelect(t.s);
else if(t.kind==2) //id选择器
idSelect(t.s);
else //后代选择器
offspringSelect(t.s,t.c);
}
}
}