1.求解二叉树的深度
二叉树深度:从根节点到叶子结点一次经过的结点(含根和叶子结点)形成树的一条路径,最长路径的长度为树的深度(即最长路径上结点的数目)
二叉数的深度求解思路:
- 空数的深度为0;
- max(左子树最大深度,右子树最大深度)+1
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public int TreeDepth(TreeNode root) {
if(root == null){
return 0;
}
int leftLen = TreeDepth(root.left);
int rightLen = TreeDepth(root.right);
if(leftLen > rightLen){
return leftLen + 1;
}else{
return rightLen + 1;
}
}
}
2.判断一个二叉树是否为平衡二叉数
平衡二叉树:又称AVL树,它或者是一棵空数,或者是左子树和右子树都是平衡二叉树且左子树和右子树的深度之差的绝对值不超过1.
判断平衡二叉树的思路:
- 空树是平衡二叉树;
- 求当前结点作为根节点的树的左右子树深度之差的绝对值;
- 若当前结点左右子树的深度之差的绝对值大于1,则该树不是平衡二叉树;
- 若当前结点左右子树的深度之差的绝对值不大于1,继续判断其左子树和右子树是否是平衡二叉树;
- 该树上所有结点作为根节点的树都是平衡二叉树,那么该二叉树就是平衡二叉树
import java.util.*;
public class Solution {
public int TreeDepth(TreeNode root){
if(root == null){
return 0;
}
int l = TreeDepth(root.left);
int r = TreeDepth(root.right);
return l>r? l+1: r+1;
}
public boolean IsBalanced_Solution(TreeNode root) {
if(root == null){
return true;
}
int l = TreeDepth(root.left);
int r = TreeDepth(root.right);
if(Math.abs(l-r) > 1){
return false;
}
boolean lb = IsBalanced_Solution(root.left);
boolean rb =IsBalanced_Solution(root.right);
return lb && rb;
}
}
3.和为S的联系正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? 输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序。
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
int bound = (int) (Math.ceil((Math.sqrt(8*sum+1)-1)/2));
if(sum%2 == 0){
for(int i = 4; i<=bound;i = 2*i){
ArrayList<Integer> temp = new ArrayList<>();
if((2*sum)%i==0 && (2*sum/i)%2 == 1){
int start = (2*sum/i - 1)/2 - i/2 +1;
if(start < 1){
break;
}
for(int k = 0; k < i; k++){
temp.add(Integer.valueOf(start+k));
}
ans.add(temp);
}
}
}else {
for(int i = 2; i<= bound; i= i+2) {
ArrayList<Integer> temp = new ArrayList<>();
if((2*sum)%i==0 && (i/2)%2 == 1){
int start = (2*sum/i - 1)/2 - i/2 +1;
if(start < 1){
break;
}
for(int k = 0; k < i; k++){
temp.add(Integer.valueOf(start+k));
}
ans.add(temp);
}
}
}
for(int i = 3;i<=bound ; i = i + 2){
ArrayList<Integer> temp = new ArrayList<>();
if(sum%i == 0){
int start = sum/i - i/2;
if(start < 1){
break;
}
for(int k = 0; k < i; k++){
temp.add(Integer.valueOf(start+k));
}
ans.add(temp);
}
}
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
ArrayList<Integer> t = new ArrayList<>();
while(ans.size() != 0) {
t = ans.get(0);
for(int n = 1; n < ans.size(); n++) {
if(ans.get(n).get(0) < t.get(0)) {
t = ans.get(n);
}
}
result.add(t);
ans.remove(t);
}
return result;
}
}
发现自己虽然实现的功能,但是代码太过冗余:下面是借鉴一下其他同学的
1)由于我们要找的是和为S的连续正数序列,因此这个序列是个公差为1的等差数列,而这个序列的中间值代表了平均值的大小。假设序列长度为n,那么这个序列的中间值可以通过(S / n)得到,知道序列的中间值和长度,也就不难求出这段序列了。
2)满足条件的n分两种情况:
n为奇数时,序列中间的数正好是序列的平均值,所以条件为:(n & 1) == 1 && sum % n == 0;
n为偶数时,序列中间两个数的平均值是序列的平均值,而这个平均值的小数部分为0.5,所以条件为:(sum % n) * 2 == n.
3)由题可知n >= 2,那么n的最大值是多少呢?我们完全可以将n从2到S全部遍历一次,但是大部分遍历是不必要的。为了让n尽可能大,我们让序列从1开始,
根据等差数列的求和公式:S = (1 + n) * n / 2,得到.
最后举一个例子,假设输入sum = 100,我们只需遍历n = 13~2的情况(按题意应从大到小遍历),n = 8时,得到序列[9, 10, 11, 12, 13, 14, 15, 16];n = 5时,得到序列[18, 19, 20, 21, 22]。
完整代码:时间复杂度为
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
for (int n = (int) Math.sqrt(2 * sum); n >= 2; n--) {
if ((n & 1) == 1 && sum % n == 0 || (sum % n) * 2 == n) {
ArrayList<Integer> list = new ArrayList<>();
for (int j = 0, k = (sum / n) - (n - 1) / 2; j < n; j++, k++) {
list.add(k);
}
ans.add(list);
}
}
return ans;
}
}