331. 验证二叉树的前序序列化(栈计数模拟,树的性质)

题目

在这里插入图片描述

解法:

1.栈模拟

(1).前序遍历(NLR)

前序遍历就是 首先访问根结点然后遍历左子树,最后遍历右子树。
在这里插入图片描述

  1. 对于字符串s判断其是否为先序遍历的二叉树,可以模拟先序遍历,可以按规则将字符串全部遍历返回true;
  2. 左结点遍历到底,遍历右结点需要栈来辅助,退栈到这个结点的父结点在遍历右结点。由于这个题是判断,所以没必要入栈具体的结点,只需要计数来确保有父结点可以退就ok。
  • ps:计数栈初始值:因为当退回到根节点,退栈到0 但右结点还可以遍历,所以要设置为1;

(2).代码

//初值设置为1
class Solution {
    public boolean isValidSerialization(String preorder) {
            
        int stack = 1, i = 0, n = preorder.length() ;
	    if(n<1) return false;
	        
	    while(i<n)
	    {
	        if(stack==0) return false;
	        char ch = preorder.charAt(i);
	        if(ch!='#')
	        {
	            stack++;
				while(i+1 < n && preorder.charAt(i+1)!=',')
					++i;   //跳跃数字
	        	i+=2;  //省略,
	        }else
	        {
	        	stack--;
	        	i+=2;
	        }
	    }
	       
	    return stack==0;
        
    }
}

时间复杂度 : O ( n ) O(n) O(n) ,一次遍历
空间复杂度 : O ( 1 ) O(1) O(1) ,常数辅助空间
在这里插入图片描述

// 初值设为0的情况,要特殊处理根结点,并且退栈是是在访问过#空结点后进行。
class Solution {
    public boolean isValidSerialization(String preorder) {
         int stack = 0, i = 0, n = preorder.length() ;  
        boolean pop = false;
        if(n<1) return false;
        if(preorder.charAt(i)!='#') {
        	while(i+1 < n && Character.isDigit(preorder.charAt(i+1)))
        		++i;
        	i+=2;
        	stack++;
        }else
        {
        	if(n==1) return true;
        	return false;
        }
        
        while(i<n && stack!=0)
        {
        	if(pop) { stack--; pop = false; }
        	char ch = preorder.charAt(i);
        	if(ch!='#')
        	{
        		stack++;
				while(i+1 < n && Character.isDigit(preorder.charAt(i+1)))
					++i;   //跳跃数字
        		i+=2;  //省略,
        	}else
        	{
        		pop = true;
        		i+=2;
        	}
        }
      
        if(i==(n+1) && stack == 0) return true;
        return false;
    }
}

时间复杂度 : O ( n ) O(n) O(n) ,一次遍历
空间复杂度 : O ( 1 ) O(1) O(1) ,常数辅助空间

2.入度出度统计

(1) 树的性质:

  • 所有顶点的出度之和总是等于入度之和
  1. 本题的空结点也当做结点,所以(1)这个结点是没有出度的, (2)所有非空结点的出度一定为2
  2. 故可以将非空结点的入度设为1,出度设为2,空结点的入度设为1,出度设为0. 一次遍历,判断出度之和是否等于入度之和

(2). 代码

class Solution {
    public boolean isValidSerialization(String preorder) {
        char[] str=preorder.toCharArray();
        int out=0,in=-1;
        for(int i=0;i<str.length;i++){
            if(str[i]==',') continue;
            in++;
            if(out-in<0) return false; //空结点后接上了非空结点。
            if(str[i]<='9'&&str[i]>='0'){
                out+=2;
                while(i<str.length-1&&str[i+1]!=',') i++;  //跳过数字
            }
        }
        return out-in==0;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值