month4 yt-element selector

本文深入探讨了CSS选择器的解析与实现细节,通过对比50分与100分解题思路,剖析了常见错误理解与正确实现方法。介绍了如何使用树状结构和递归算法高效匹配元素,避免子代元素的误判。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

解题思路:

50分错误思路:最初理解题目有偏差,而且样例能过,测试了很多数据,找不到原因,因为对于我的理解,我的代码没有问题,后来和同学对的时候才发现问题所在,我理解的是子代会继承父代元素,而样例里面偏偏避开了这一块,样例的测试数据都是无子代的,所以我的代码能过测试数据。实际上就是,对于输入的查询选择器,我会输出直接对应的元素及它的所有子代的行数,但实际上,AC的代码只会该对应元素行号,不会输出它的子代元素行号。举个例子,查询html,正确输出是1 1,但是我会输出所有行号。我感觉这是题目的bug(虽然我不知道是不是…),感觉题目没有讲清这一块,我理解的html代码父代和子代样式是有继承关系的。我错误的思路就是构造行元素的完整字符串,从根一直到该行的元素,以空格分离,查询的时候,只要查询的字符串都是该行的某个子字符串即可。(要求顺序一致)

100分思路:本题类似于构造树的思想,每一个元素结构体会记录父元素的索引。构造结构体yuansu:id字符串,label字符串,fa(父亲索引)。find(int q,int j)是判断ys[j]是否和qslen[q]匹配,如果不匹配,沿着路径找父元素判断find(q,ys[j].fa),一直到根或者查找成功。
以‘.’的个数来区别元素级数,不确定是否有多个0级元素,所以为了不进行额外判断,将所有元素的级数升一级,同时,cur数组记录了当前每级的最新行号,所以有如下代码:cur[(cot>>1)+1]=i;ys[i].fa=cur[cot>>1]。
关键:最后查询的时候,从qs字符串数组的最后一个字符串,即qs[qlen-1]开始往前查询,如果是id,则判断ys[j].id是否等于qs[qlen-1],如果不是,这个元素就不匹配,continue;如果是,cot++,调用递归函数find(q-1,j),注意这里还是在j号元素进行判断,因为下一个字符串qs[q-1]可能就是ys[j].label。如果是标签判断过程基本上和id一样,只是匹配的话应该调用函数find(q-1,j-1)。
bug点:注意>>和算术运算符的优先级:>>小于-。

实验代码:

#include<iostream>
#include<sstream>
using namespace std;
struct yuansu
{
	string label;
	string id;
	int fa;			
};
yuansu ys[110];		 
int cur[110],qslen,cot,n,anstol,ans[110];		
string qs[222];		
bool matching(string str1,string str2)			
{
	int len1 = str1.length();
	int len2 = str2.length();
	if (len1 != len2)
		return false;
	int d = 'a' - 'A';
	for (int i = 0; i < len1; i++)
	{ 
		if (str1[i] == str2[i])	continue;
		if (str1[i] == str2[i] + d)	continue;
		if (str1[i] == str2[i] - d)	continue;
		return false;
	}
	return true;
}
void find(int goal,int j)		
{
	if(goal==-1||j==0)			
		return;
	if(qs[goal][0]=='#')		
	{
		if(ys[j].id==qs[goal])		
		{
			cot++;
			find(goal-1,j);				
		} 
		else
			find(goal,ys[j].fa);			
	} 
	else			
	{
		if(matching(qs[goal],ys[j].label))
		{
			cot++;
			find(goal-1,j-1);
		}
		else
			find(goal,ys[j].fa);
	}
}
int main(void)
{
	int m;
	string str;
	cin>>n>>m;
	getchar();
	for(int i=1;i<=n;i++)
	{
		getline(cin,str);			
		cot = 0;
		while (str[cot] == '.') {
			cot++;			
		} 
		cur[(cot>>1)+1]=i;		
		ys[i].fa=cur[cot>>1];	
		if(str.find('#')!=string::npos)
		{
			ys[i].id=str.substr(str.find('#'));
			ys[i].label=str.substr(cot,str.find('#')-cot-1);		
		}
		else 
		{
			ys[i].id="";
			ys[i].label=str.substr(cot);
		} 
	}
	for(int i=0;i<m;i++)
	{
		getline(cin,str);		
		stringstream qsin(str);		
		qslen=0,anstol=0;			
		while(qsin>>qs[qslen]) {
			qslen++;		
		}
		for(int j=1;j<=n;j++)
		{
			cot=0;
			int q=qslen-1;
			if(qs[q][0]=='#')			
			{
				if(ys[j].id!=qs[q])		
					continue;
				cot++;					
				find(q-1,j);				
			}
			else						
			{
				if(!matching(ys[j].label,qs[q]))
					continue;		
				cot++;			 
				find(q-1,ys[j].fa);		
			}
			if(cot==qslen)
				ans[anstol++]=j;
		}
		cout<<anstol<<" ";
		for(int k=0;k<anstol;k++)
			cout<<ans[k]<<" ";
		cout<<endl;
	} 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值