1. 解析
题目大意,给定一个','分割开的字符串,判断是否是先序遍历。树的3种遍历递归都比较简单,然而这题反其道而行之,未必就会啦~~~
2. 分析
我想到的一种解法就是,采用非递归方式的先序遍历,将解析字符串的过程看做是先序遍历的过程,不断将左节点进栈,即不停地从前往后解析字符串,每个','分割开的字符串就是一个节点,'#'代表空节点,直到碰到空节点。然后回溯,返回栈顶节点,即根节点,然后检索右边节点,...依次检索,如果是先序遍历,那整个过程就会一直执行到底;反之,如果栈中还有元素,可是字符串已经解析到尾部,说明不属于先序遍历。例如"2,3,4,#",左节点全部进栈,可是当回溯在根节点'4'的时候,整个字符串已经解析完,很明显,其他空节点还没有放上去,即不满足先序遍历.结果虽然AC,但是效率很低
class Solution {
public:
bool isValidSerialization(string preorder) {
preorder += ',';
stack<string> nums{{""}};
int pos;
while(!nums.empty()){
string str = nums.top();
nums.pop();
if (str != "#"){ //右边节点不为空
pos = preorder.find(',');
if (pos == string::npos) return false;
while (pos != string::npos){ //左节点进栈
str = preorder.substr(0, pos);
preorder = preorder.substr(pos+1);
if (str == "#") break;
nums.push(str);
pos = preorder.find(',');
}
}
}
return preorder.empty() ? true : false;
}
};
3. 别的解法
@Grandyang大家可以时常查看他的博客,很多题都讲解的很到位,我就经常光顾,不会就学嘛,多参考别人优秀的思想~~~哈哈。如果我们仔细观察就会发现:
①如果不考虑最后一个节点,是不会出现3个'#'紧挨在一块的情况,例如"3,#,#,#,3,#",如果出现这种情况一定不是先序遍历。
②不考虑最后一个'#',如果满足先序遍历,那么'#'和'数字'出现的次数一定是相等的,且总是先出现'数字'然后才出现'#'
综上两种情况,我们可以设置cnt表示'数字'出现的个数,如果cnt为0,且nums还未遍历完,那么意味着'数字'出现的次数小于'#',即不满足先序遍历,直接返回false。因为我们之前是不考虑最后一个'#'的,所以在最后我们要判断一下
class Solution {
public:
bool isValidSerialization(string preorder){
istringstream in(preorder);
vector<string> nums;
string str = "";
int cnt = 0;
while (getline(in, str, ',')) nums.push_back(str); //根据','解析节点值,放在数组当中
for (int i = 0; i < nums.size() - 1; ++i){
if (nums[i] == "#"){
if (cnt == 0) return false;
cnt--;
} else{
cnt++;
}
}
return cnt == 0 && nums.back() == "#";
}
};
这种解法实际上和上一种解法大同小异,整个字符串由','和0-9的字符与'#'组成,故可以以','作为分隔字符的标记,capacity代表'#'的容量,每增加一个节点就会增加两个空节点(即'#').
class Solution {
public:
bool isValidSerialization(string preorder){
preorder += ',';
int capacity = 1;
for (int i = 0; i < preorder.length(); ++i){
if (preorder[i] != ',') continue;
if (--capacity < 0) return false;
if (preorder[i-1] != '#') capacity += 2;
}
return capacity == 0;
}
};