CCF201809-3 元素选择器 Python 递归实现 dfs 100分

思路:

这是一个树,可以类比数据结构中的二叉树。

二叉树有一个值(val),和不超过两个叶子节点

这个html树可能有多个值,id属性和 标签属性(div/p/h1这些),可能有多个节点

题目描述:

    可能出现 div #one 这种复合的后代选择器

 

于是我想直接用python嵌套的字典来完成

一:节点的表示:每个节点用dict表示,每个节点的关键属性是,dict['idTag']  id   ,dict['value']  标签属性  ,dict['childNode']  //关键,是列表类型,列表里仍然储存着  节点(递归)

二:创建的罗技逻辑:

 creat (root)函数:

    为了实现它,首先定义了一个linePointet【int】,指向待处理的html的第几行

    creat (root),可以把缓冲区(html字符串的第linePointer个)的节点,挂载在root下

    因此首先需要创建一个最大的,把html当作跟放进去,下面的语句起到这个作用

    htmlDom = dict()
    htmlDom['leval']=0
    htmlDom['value']=None

    然后呢,就可以递归的创建了,逻辑是这样的:

   循环    一直认为当前缓冲区的是 root的子节点{

       把缓冲区的字符串处理成定义的标准类型    

        IF这个新的节点是root的跟{

             1:把新节点(newNode)append到root的儿子列表里 

             2:调整下linePointer到下一个节点,注意,下一个可能是newNode的儿子,也可能是newNode的兄弟,也可能是是           newNode直接间接前驱,但是注意,只要 linePointer指的不是当前递归调用里的,当前递归调用层只会退出,直到linePointer指的确是是当前递归栈里的儿子

             3:递归调用creat (newNode),也就是 认为新节点是新的跟,这样可以处理多层嵌套

       }   

      ELSE{退出}

}

 

三:查询的逻辑,和创建有类似之处,参考注释即可

四:创建好的dict长什么样,以给出的样例为例子

样例输入:

11 0
html
..head
....title
..body
....h1
....p #subtitle
....div #main
......h2
......p #one
......div
........p #two

{
	"leval": 0,
	"value": null,
	"childNum": 1,
	"childNode": [{
		"leval": 1,
		"idTag": null,
		"value": "html",
		"lineNum": 1,
		"childNum": 2,
		"childNode": [{
			"leval": 2,
			"idTag": null,
			"value": "head",
			"lineNum": 2,
			"childNum": 1,
			"childNode": [{
				"leval": 3,
				"idTag": null,
				"value": "title",
				"lineNum": 3,
				"childNum": 0,
				"childNode": []
			}]
		}, {
			"leval": 2,
			"idTag": null,
			"value": "body",
			"lineNum": 4,
			"childNum": 3,
			"childNode": [{
				"leval": 3,
				"idTag": null,
				"value": "h1",
				"lineNum": 5,
				"childNum": 0,
				"childNode": []
			}, {
				"leval": 3,
				"idTag": "subtitle",
				"value": "p",
				"lineNum": 6,
				"childNum": 0,
				"childNode": []
			}, {
				"leval": 3,
				"idTag": "main",
				"value": "div",
				"lineNum": 7,
				"childNum": 3,
				"childNode": [{
					"leval": 4,
					"idTag": null,
					"value": "h2",
					"lineNum": 8,
					"childNum": 0,
					"childNode": []
				}, {
					"leval": 4,
					"idTag": "one",
					"value": "p",
					"lineNum": 9,
					"childNum": 0,
					"childNode": []
				}, {
					"leval": 4,
					"idTag": null,
					"value": "div",
					"lineNum": 10,
					"childNum": 1,
					"childNode": [{
						"leval": 5,
						"idTag": "two",
						"value": "p",
						"lineNum": 11,
						"childNum": 0,
						"childNode": []
					}]
				}]
			}]
		}]
	}]
}

 

def creat(root):
        #功能是,把缓冲区(html字符串的第linePointer个)的节点,挂载在root下
        root['childNum'] = 0
        root['childNode']=list()
        while True:
            global linePointer
            if linePointer>=n:
                return
            line = allData[linePointer]
            newNode=dict()
            newNode['leval']=int(line.count(".") / 2) + 1
            line=line.replace(".","")
            valueAndId=line.split()
            if len(valueAndId)==1:
                newNode['idTag']=None
            else:
                newNode['idTag']=valueAndId[1].replace("#",'')
            newNode['value']=valueAndId[0].lower()
            newNode['lineNum']=linePointer+1
            if newNode['leval']>root['leval']:
                root['childNum']+=1
                root['childNode'].append(newNode)
                linePointer+=1
                creat(newNode)
            else:
                #不是当前root的儿子,直接退出,linePointer指向的字符串 交给他真正的爸爸解决把
                return


## 选择器
def dfs(query, keyleval,node,lineArr):
    #query:list是查寻字符串的列表[div,div] ,keyleval:int,表示查询到query的第几层,node:dict,指的是这层递归要比较的节点,也就是要查看query[keyleval]是不是等于node的相关值
    isId=query[keyleval].startswith('#')
    if isId:
        key='idTag'
        rightVal=query[keyleval].replace('#','')
    else:
        key='value'
        rightVal=query[keyleval].lower()
    if rightVal==node.get(key):
         #这个node符合当前查寻得这一层
        if keyleval>=len(query)-1:
            #是最后一个节点,递归的时候仍然不修改keyleval
            lineArr.append(node['lineNum'])
            for i in node['childNode']:
                dfs(query, keyleval , i, lineArr)
        else:
            #不是最后一个节点,keyleval要+1,查询query的下一层
            for i in node['childNode']:
                dfs(query,keyleval+1,i,lineArr)
    else:
        #这层不是,看这层的儿子符合不符合
        for i in node['childNode']:
            dfs(query, keyleval, i, lineArr)

n, m = list(map(int, input().split()))
allData=list()
for i in range(n):
    allData.append(input())
htmlDom = dict()
htmlDom['leval']=0
htmlDom['value']=None
#重要,指示下一个要创建节点的下标
linePointer=0
creat(htmlDom)
for i in range(m):
    lineArr=list()
    query=input().split()
    #lineArr储存的是,符合条件的行号
    dfs(query,0,htmlDom,lineArr)
    lineArr.insert(0, len(lineArr))
    for i in lineArr:
        print(i, end=' ')
    print()

  

你可能感兴趣的:(简单的算法)