leetcode 101
判断一颗二叉树是否 镜像对称。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 bool isSymmetric(TreeNode* root) { 13 if(root == NULL) 14 return true; 15 return isSymmetric(root->left,root->right); 16 } 17 bool isSymmetric(TreeNode* left,TreeNode* right) 18 { 19 if(left == NULL && right == NULL) return true; 20 if(left == NULL || right == NULL) return false; 21 if(left->val != right->val) 22 return false; 23 return isSymmetric(left->left,right->right) && isSymmetric(left->right,right->left); 24 } 25 };
leetcode 100
简单题,判断两棵树是否是一样的。递归判断。
- class Solution {
- public:
- bool isSameTree(TreeNode *p, TreeNode *q) {
- if(p==NULL&&q==NULL)
- return true;
- else if(p==NULL&&q!=NULL)
- return false;
- else if(p!=NULL&&q==NULL)
- return false;
- else if(p!=NULL&&q!=NULL&&p->val!=q->val)
- return false;
- else
- return (isSameTree(p->left,q->left))&&(isSameTree(p->right,q->right));
- }
- };
leetcode 226
Invert a binary tree.
4
/ \
2 7
/ \ / \
1 3 6 9
- 1
- 2
- 3
- 4
- 5
to
4
/ \
7 2
/ \ / \
9 6 3 1
- 1
- 2
- 3
- 4
- 5
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* invertTree(TreeNode* root) { if(root == NULL) return NULL; else { TreeNode* newleft=root->left; TreeNode* newright=root->right;
newleft=invertTree(root->right);invertTree(root-> left);
return root; } }};
反转树:对根节点左右取两个新的指针,然后对右子树做递归反转,接到左子树新指针下,这个其实就相当于
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(root==NULL)
return NULL;
TreeNode * leftTree=NULL;
TreeNode * rightTree=NULL;
if(root->left)
leftTree=invertTree(root->left);
if(root->right)
rightTree=invertTree(root->right);
root->left=rightTree;
root->right=leftTree;
return root;
}
};
leetcode 222
思路:首先想到的是直接的递归,二叉树的节点个数 = 左子树的节点个数 + 右子树的节点个数 + 1
Java 代码如下:
- public class Solution {
- // 二叉树的节点数 = 左子树的节点数 + 右子树的节点数 + 1
- public int countNodes(TreeNode root) {
- if(root == null){
- return 0;
- }
- return countNodes(root.left) + countNodes(root.right) + 1;
- }
- }
遍历了整个二叉树,时间复杂度为O(N)。然后超时了,因为上述方法并没有使用“完全二叉树”这个条件。
接下来考虑,对于完全二叉树,其左子树和右子树中至少有一个子树是满二叉树,而满二叉树的节点个数可以直接由 2^n-1得到,因此,是满二叉树的那一部分就不需要再遍历,因此可以提高效率。算法思路如下:首先计算出二叉树的最左侧分支和最右侧分支的层数,如果二者相等,则整个二叉树是满二叉树;若不相等,则递归的计算左右子树的节点数,总结点数=左子树节点数+右子树节点数+1。
Java代码如下:
- public class Solution {
- // 获取左子树的高度(其实是最左侧分支)
- public int getLeftHeight(TreeNode root) {
- int count = 0;
- while (root != null) {
- count++;
- root = root.left;
- }
- return count;
- }
- // 获取右子树的高度(其实是最右侧分支的高度)
- public int getRightHeight(TreeNode root) {
- int count = 0;
- while (root != null) {
- count++;
- root = root.right;
- }
- return count;
- }
- public int countNodes(TreeNode root) {
- if (root == null) {
- return 0;
- }
- int leftHeight = getLeftHeight(root);
- int rightHeight = getRightHeight(root);
- if (leftHeight == rightHeight) {
- // 表示是满二叉树,二叉树的节点数直接由公式2^n-1得到
- // leftHeight即为层数, 1 << leftHeight使用位运算计算2^leftHeight,效率更高
- // 注意(1 << leftHeight) - 1 的括号必须有!!
- return (1 << leftHeight) - 1;
- } else {
- // 若该二叉树不是满二叉树,递归的调用该方法,计算左子树和右子树的节点数
- //分别对左右子树做递归,右子树在极大可能下是满二叉树,这样在每一次递归下都剋缩减规模,找到最大的满二叉树,使过程更简洁
- return countNodes(root.left) + countNodes(root.right) + 1;
- }
- }
- }
leetcode 110
- // 104ms过大集合
- /**
- * Definition for binary tree
- * struct TreeNode {
- * int val;
- * TreeNode *left;
- * TreeNode *right;
- * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
- * };
- */
- class Solution {
- public:
- int height(TreeNode* root) {
- if(root==NULL)
- return 0;
- else{
- int l=height(root->left);
- int r=height(root->right);
- return 1+((l>r)?l:r);
- }
- }
- bool isBalanced(TreeNode *root) {
- if(root==NULL)
- return true;
- else{
- int l,r;
- l=height(root->left);
- r=height(root->right);
- if((l>r+1)||(r>l+1))
- return false;
- else
- return isBalanced(root->left)&&isBalanced(root->right);
- }
- }
- };
- 为什么会去建立一个函数来找当前点左右子树中最深的呢,因为要这样考虑,想知道根节点是不是平衡术,
- 就要在他的左右子树中分别找到最高的叶子,那么对于左结点同样有左右树,找到最高的叶子。
leetcode 112
Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
For example: Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.
题目大意:给定一个二叉树和一个值sum,判断是否存在一个从根节点到叶子节点的路径,使得路径上每个节点值之和等于sum?
难度系数:容易 (共3级别:容易,中等,困难)
看到这个题目,大体思路就是遍历从根到叶子的每一条路径,并求和。只要相等,就返回true,否则一直遍历下去,最后返回false。
这一次,我没有编译,测试,全在脑子里演算。共3次提交通过,一次是特殊情况没考虑到,一次是被上面的例子误导了,以为sum是正数。 第三次提交通过了。代码如下:
bool hasPathSum(TreeNode *root, int sum) {
if (root == NULL)
return false;
else if (root->left == NULL && root->right == NULL && root->val == sum)
return true;
else {
return hasPathSum(root->left, sum-root->val) || hasPathSum(root->right, sum - root->val);
}
}
10行不到。做完后我搜索了下,看看别人是怎么做的,发现好多人写了30行左右的代码,看到这样的代码,我也无力吐槽了。我觉得 精简可读还是很重要的,毕竟是写给人看的。Martin Fowler有句名言:
任何傻瓜都能写出计算机可以理解的代码。好的程序员能写出人能读懂的代码
一般来说,写的复杂,冗长的代码,往往是用的解法不够好。而且实际项目中,往往时间紧迫,确实让人很难做到写出可读性好的代码来。
很久没有去游玩了。希望有一天,能摆脱金钱的烦恼,边写代码,边赏风景。 登临险峰观赏无限的风光,骑行西藏感悟人生的真谛;闲看路上匆匆的行人,静听山涧叽叽的鸟声。。。
leetcode 404
递归解决这个问题
问题描述:所有左叶子结点的和
注:左叶子结点;root->left,然后他的左右都为空。
0
public static int sumOfLeftLeaves3(TreeNode root) {
if(root==null)
return 0;
else if(root.left!=null && root.left.left==null && root.left.right==null)
return root.left.n+sumOfLeftLeaves(root.right);
else
return sumOfLeftLeaves(root.left)+sumOfLeftLeaves(root.right);
}
leetcode 257
//自己创建一个函数,用来递归,参数是两个list<string>,res每次在遍历到根节点时把singleResult,也iu是所有路径,而singleResult是一条路径,每次都把当前路径值都存在singleResult,直到到达叶子结点,
把singleResult存放在res中
public List<String> resultList = new ArrayList<String>();
- 1
/**
* 递归方式
*
* <br />
*
* Run Time : 4ms
*
* @param root
* @return
*/
public List<String> binaryTreePaths(TreeNode root) {
if (root == null) {
return resultList;
}
List<String> singleResult = new ArrayList<>();
getTreePath(root, singleResult);
return resultList;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
/**
* DFS
*
* @param resultList
* @param node
* @param singleResult
*/
private void getTreePath(TreeNode node, List<String> singleResult) {
singleResult.add(node.val + "");
if (node.left == null && node.right == null) {
resultList.add(singleResult);
}
if (node.left != null) {
getTreePath(node.left, new ArrayList<>(singleResult));
}
if (node.right != null) {
getTreePath(node.right, new ArrayList<>(singleResult));
}
}
leetcode 113
Link: https://leetcode.com/problems/path-sum-ii/
Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum.
For example:
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
return
[
[5,4,11,2],
[5,8,4,5]
]
- 1
- 2
- 3
- 4
- 5
g因为他是257的变形题,所以可以在求解的过程中,应用257的现成解法,只要添加一个sum(参数),每次遍历一条路径,
把该条路径的sum值计算出来,并比较和给定值是否相等,
递归方法:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int> > pathSum(TreeNode* root, int sum) {
vector<vector<int> > result;
vector<int> nums;
getPath(result,nums,sum,0,root);
return result;
}
void getPath(vector<vector<int> > &res, vector<int> &nums, int target, int sum, TreeNode *root) {
if(root==NULL) return;
sum += root->val;
nums.push_back(root->val);
if(sum == target && !root->left && !root->right){
res.push_back(nums);
}
if(root->left!=null)
getPath(res, nums, target, sum, root->left);
if(root->right!=null)
getPath(res, nums, target, sum, root->right);
//如果到达叶子结点,但此时的sum!=target,就要把数组pop一个,sum值也要减一个
nums.pop_back();
sum -= root->val;
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 3
leetcode 129
Given a binary tree containing digits from 0-9
only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3
which represents the number 123
.
Find the total sum of all root-to-leaf numbers.
For example,
1 / \ 2 3
The root-to-leaf path 1->2
represents the number 12
.
The root-to-leaf path 1->3
represents the number 13
.
Return the sum = 12 + 13 = 25
.
Subscribe to see which companies asked this question
用树的dfs来解决,每次传入当前结点和到当前结点的数的num值,最后维护一个sum
算法实现类
public class Solution {
private int result = 0; // 记录总的结果
private int num = 0; // 记根到叶子的数字
public int sumNumbers(TreeNode root) {
sum(root);
return result;
}
private void sum(TreeNode root) {
if (root != null) {
num = num*10 + root.val;
// 已经到了根结点了
if (root.left == null && root.right == null) {
result += num;
}
sum(root.left);
sum(root.right);
num /= 10;//这个好,直接求余
}
}
}
我自己写的
public list<string>getpath(Treenode *root)
{
int res;
if(root==null)
return res;
treepath(root,0,0);
return res;
}
private void treepath(Treenode *root,int sum,int taget)
{
sum+=sum*10+root->val;
if(root->left==null&&root->right==null)
{
taget+=sum;
}
if(root->left!=null)
{
treepath(root->left, sum, taget);
}
if(root->right!=null)
{
treepath(root->left, sum, taget);
}
sum=(sum-root->val)/10;//这个地方太智障了 不好
leetcode 437
2 原题
You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.
Example:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
给定一颗二叉树,找出路径和等于sum的路径数。这里的路径是指从父节点到子节点的路径,不必一定是从根节点到叶子节点。马上想到深度优先搜索,但是要注意路径不一定从根节点开始。所以对于一个父节点来说,它所在路径上满足题设要求的路径,除了包括左右子树中路径和为sum-root->val的路径外,还应包括左右子树中路径和为sum的路径。
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: int pathSum(TreeNode* root, int sum) { if(!root) return 0; return pathSum(root->left,sum)+pathSum(root->right,sum)+pathSumRoot(root,sum); } int pathSumRoot(TreeNode* root, int sum) { if(!root) return 0; int count=(sum==root->val?1:0); return pathSumRoot(root->left,sum-root->val)+ pathSumRoot(root->right,sum-root->val)+count; } };
leetcode 235
Lowest Common Ancestor of a Binary Search Tree(二叉查找树的最近公共父亲节点)
【难度:Easy】
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. Another example is LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.
给定一个二叉查找树和所要查找的两个节点,找到这两个节点的最近公共父亲节点。如图,节点2和8的LCA是6,节点2和4的LCA是2。
解题思路
根据LCA的定义和BST的特性,当root非空时可以区分为三种情况:1)两个节点均在root的左子树,此时对root->left递归求解;2)两个节点均在root的右子树,此时对root->right递归求解;3)两个节点分别位于root的左右子树,此时LCA为root。
c++代码如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == NULL)
return root;
if (p->val > root->val && q->val > root->val) {
return lowestCommonAncestor(root->right,p,q);
} else if (p->val < root->val && q->val < root->val) {
return lowestCommonAncestor(root->left,p,q);
}
return root;
}
};
leetcode 98
判断是否是查找二叉树,三种方式。
原题
Given a binary tree, determine if it is a valid binary search tree (BST).
Assume a BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node’s key.
The right subtree of a node contains only nodes with keys greater than the node’s key.
Both the left and right subtrees must also be binary search trees.
判断一棵二叉树是否为二叉查找树(BST)。
二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。
我自己的总结;
注意两点:
1.根节点的值比左孩子值比大,比右孩子小
2.下一层的数中比如以temp=root->left为根节点,那么此时temp的右孩子比它大,但是要比root小,同理对与右孩子也一样
所以设置两个值,
min_max:当前左子树(比根节点小)跟节点值,左子树中大值,也就是小个子里拔高个
max_min
设置一个
方法一,记录子树的上界和下界,root的左子树一定小于root的值,root的右子树一定大于root的值,然后递归左子树和右子树
public class Solution { public boolean isValidBST(TreeNode root) { return isValid(root, null, null); } public boolean isValid(TreeNode root, Integer min, Integer max) { if(root == null) return true; if(min != null && root.val <= min) return false; if(max != null && root.val >= max) return false; return isValid(root.left, min, root.val) && isValid(root.right, root.val, max); }
}
我自己写的
public bool justicetree(treenode *root) { return isBST(root,null,null)//实在不知道怎么进入第一次循环,就加入标志,来帮助异常情况 } private bool isBST(Treenode *root,int min_max,int max_min) { if(root==null) return true; if(min_max!=null&&root->right->val>min_max) return false; if(max_min!=null&&root->left->val<max_min) return false;
//这个位置可以加个flag帮助自己度过上面两个判断 if(root->right->val>root->val&&root->left-val<root->val) { return isBst(root->left,root->val,max_min)&&isBST(root->right,min_max,root->val); }
二叉查找树有一个重要的性质:即中序遍历递增(不存在两个节点值相等),根据此,中序遍历完成后,查看序列是否有序即可知道是否是二叉查找树。
代码
class Solution {
private:
void helper(TreeNode* root,vector<int>&result)//中序遍历
{
if (root == NULL)
return;
helper(root->left, result);
result.push_back(root->val);
helper(root->right, result);
}
public:
bool isValidBST(TreeNode* root) {
vector<int>result;
helper(root, result);
for (int i = 0; i < result.size()-1; i++)
{
if (result[i]>result[i + 1])
return false;
}
return true;
}
};
/** *
Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int pathSum(TreeNode root, int sum) {
if(root == null)
return 0;
return dfs(root, sum)+pathSum(root.left, sum)+pathSum(root.right, sum);
}
private int dfs(TreeNode root, int sum){
int res = 0;
if(root == null)
return res;
if(sum == root.val)
res++;
res+=dfs(root.left,sum - root.val);
res+=dfs(root.right,sum - root.val);
return res;
}
}
leetcode 450
题目链接: https://leetcode.com/problems/delete-node-in-a-bst/
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
- Search for a node to remove.
- If the node is found, delete the node.
Note: Time complexity should be O(height of tree).
Example:
root = [5,3,6,2,4,null,7] key = 3 5 / \ 3 6 / \ \ 2 4 7 Given key to delete is 3. So we find the node with value 3 and delete it. One valid answer is [5,4,6,2,null,null,7], shown in the following BST. 5 / \ 4 6 / \ 2 7 Another valid answer is [5,2,6,null,4,null,7]. 5 / \ 2 6 \ \ 4 7
1. 如果要删除的节点有左孩子, 则可以直接让左孩子替换其位置, 并且让左孩子的右子树连接到要删除节点的右孩子的最左端
2. 如果要删除的节点有右孩子, 则可以让右孩子替换其位置, 并且让右孩子的左子树连接到要删除节点的左孩子的最右端
3. 如果要删除的节点有左孩子, 则可以取左孩子的最右节点替换要删除的节点
4. 如果要删除的节点有右孩子, 则可以去右孩子的最左节点替换要删除的节点.
在这里我采用的第二种解法.
代码如下:
- /**
- * Definition for a binary tree node.
- * struct TreeNode {
- * int val;
- * TreeNode *left;
- * TreeNode *right;
- * TreeNode(int x) : val(x), left(NULL), right(NULL) {}
- * };
- */
- class Solution {
- public:
- TreeNode* deleteNode(TreeNode* root, int key) {
- if(!root) return root;
- if(root->val > key){
- root->left = deleteNode(root->left, key);
- return root;
- }
- else if(root->val < key){
- root->right = deleteNode(root->right, key);
- return root;
- }
- TreeNode* left = root->left, *right = root->right, *tem = left;
- delete root;
- if(!left || !right) return left?left: right; //左右子树只能存在一个的时候,都存在跳到下步
- while(tem->right) tem = tem->right; //在左子树中向右遍历,找到最大
- tem->right = right->left, right->left = left;
- return right;
- }
- };
而替换策略就是:
1、当前删除位置,用左边子树的最大值的节点替换
2、或者是,用右边子树的最小值的节点替换
用上面的策略就可以保证删除后性质不变,并且调整开销也很少
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int findReplacement(TreeNode parent,TreeNode node,boolean isLeft){
if(node.right == null){
if (isLeft)
parent.left = node.left;
else parent.right = node.left;
return node.val;
}
return findReplacement(node,node.right,false);
}
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null)
return null;
if(root.val == key){
if(root.left == null)
return root.right;
if(root.right == null)
return root.left;
root.val = findReplacement(root,root.left,true); // 选择左边最大的,或者右边最小的
} else{
if(root.val > key)
root.left = deleteNode(root.left,key);
else
root.right = deleteNode(root.right,key);
}
return root;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38