前言
刷5月15日的老题。今天刷的是501.中序遍历二叉树找众数、94.二叉树的中序遍历、65.有效数字。
501.中序遍历二叉树找众数(容易):
题目描述:
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
·结点左子树中所含结点的值小于等于当前结点的值
·结点右子树中所含结点的值大于等于当前结点的值
·左子树和右子树都是二叉搜索树
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-mode-in-binary-search-tree
题解:
由于给定的二叉树是BST,中序遍历可以很好地利用它的特性,按升序获得序列。寻找众数,可以即时记录一个结果数组和一个max值,判断当前值和上一个值是否相等。不相等,则将计数器置1,并清空;加入相等,则继续计数。当计数器大于max值,就清空并更新结果数组;假如出现多个众数,则在原有基础上更新结果数组。
Code
var findMode = function(root) {
let preNode=null;
let count=1;
let max=1;
let res=[];
const helper=(root)=>{
if(!root) return;
helper(root.left);
if(preNode){
if(root.val==preNode.val) count++;
else count=1;
}
if(count>max){
max=count;
res=[];
res.push(root.val);
}else if(count==max){
res.push(root.val);
}
preNode=root;
helper(root.right);
}
helper(root);
return res;
};
94.二叉树的中序遍历(中等):
题目描述:
给定一个二叉树,返回它的中序遍历。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal
题解:
跟着上一题用了递归,时间复杂度是O(n)。除此之外还可以使用莫里斯遍历(维持树的原有结构)。
榜一的迭代法也比较快,有两个比较好理解的,也放上来。
Code
//递归
var inorderTraversal = function(root) {
let res=[];
const helper=(root)=>{
if(!root) return;
helper(root.left);
res.push(root.val);
helper(root.right);
}
helper(root);
return res;
};
//莫里斯遍历
var inorderTraversal = function(root) {
let res=[],cur=root;
let mostRight=null;
while(cur){
if(!cur.left){
res.push(cur.val);
cur=cur.right;
}else{
mostRight=cur.left;
while(mostRight.right&&mostRight.right!=cur){
mostRight=mostRight.right;
}
if(!mostRight.right){
mostRight.right=cur;
cur=cur.left;
}else{
res.push(cur.val);
mostRight.right=null;
cur=cur.right;
}
}
}
return res;
};
//40ms,将节点和值都存入栈里进行判断,比较巧妙。
var inorderTraversal = function(root) {
var s = [root];
var l = [];
while(s.length) {
var n = s.pop();
if (n && n.val) {
var {left, right, val} = n;
if (right) s.push(right);
s.push(n.val);
if (left) s.push(left);
} else if (n) {
l.push(n);
}
}
return l;
};
//44ms,栈存储所有的根节点,逐层遍历。
var inorderTraversal = function(root) {
if (!root) return []
const res = []
const stack = []
let curr = root
while(curr || stack.length) {
while(curr) {
stack.push(curr)
curr = curr.left
}
curr = stack.pop()
res.push(curr.val)
curr = curr.right
}
return res
};
65.有效数字(困难):
题目描述:
验证给定的字符串是否可以解释为十进制数字。
例如:
“0” => true
" 0.1 " => true
“abc” => false
“1 a” => false
“2e10” => true
" -90e3 " => true
" 1e" => false
“e3” => false
" 6e-1" => true
" 99e2.5 " => false
“53.5e93” => true
" --6 " => false
“-+3” => false
“95a54e53” => false
说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表:
数字 0-9
指数 - “e”
正/负号 - “+”/"-"
小数点 - “.”
当然,在输入中,这些字符的上下文也很重要。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-number
题解:
这种题真是我的噩梦,常规解法是处理字符串,可以用正则表达式。不过看到有状态机的解法,大呼过瘾(学以致用,大佬太强了)。其实状态机和正则表达式是可以相互转化的,不难理解。另外还有一些奇技淫巧…mark下来。
Code
//巧解
var isNumber = function(s) {
return !Number.isNaN(s.trim().length ? + s : NaN)
};
//正则表达式
var isNumber = function(s) {
// 直接先去除两头空格就不用考虑两头有空格的情况了
s = s.trim();
// 加上^$确保匹配的是整个字符串而不是字符串中的一部分
// 1. 和.1都是true,所以要这样判断
// 后面是e的部分e后面跟的数字可正可负但是必须为整数
const flag = /^([-+]?(\d+(\.\d*)?|\.\d+)(e[-+]?\d+)?)$/.test(s);
return flag;
};
//状态机
var isNumber = function(s) {
let state = 0,
finals = [0,0,0,1,0,1,1,0,1],
transfer = [[ 0, 1, 6, 2,-1,-1],
[-1,-1, 6, 2,-1,-1],
[-1,-1, 3,-1,-1,-1],
[ 8,-1, 3,-1, 4,-1],
[-1, 7, 5,-1,-1,-1],
[ 8,-1, 5,-1,-1,-1],
[ 8,-1, 6, 3, 4,-1],
[-1,-1, 5,-1,-1,-1],
[ 8,-1,-1,-1,-1,-1]],
make = (c) => {
switch(c) {
case " ": return 0;
case "+":
case "-": return 1;
case ".": return 3;
case "e": return 4;
default:
let code = c.charCodeAt();
if(code >= 48 && code <= 57) {
return 2;
} else {
return 5;
}
}
};
for(let i=0; i < s.length; ++i) {
state = transfer[state][make(s[i])];
if (state < 0) return false;
}
return finals[state];
};
作者:user8973
链接:https://leetcode-cn.com/problems/valid-number/solution/biao-qu-dong-fa-by-user8973/