剑指 offer day19-20

剑指 Offer 64. 求1+2+…+n

题目:

1+2+...+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

题解:

关于逻辑运算符&&||

A&&B为例,如果A为真则会继续执行B,如果A为假则不再执行B,直接返回false;

A||B为例,如果A为真则不再执行B,直接返回true,如果A为假则执行B;

1.使用&&,当n为0时,&&的左端为 false,将不再执行递归调用;

public int sumNums(int n) {
        boolean flag = n > 0 && (n += sumNums(n - 1)) > 0;//当n为0时,跳出递归
        return n;
    }

2.使用||,当n=0时,||的左端为true,将不再执行递归调用。

 public static int sumNums(int n){
        
        boolean flag = (n == 0) || (n+=sumNums(n - 1))>0;
        return n;
    }

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先

题目:

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

最近公共祖先:对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。

题解:

1.getPath函数:遍历二叉搜索树,找到从根节点root到目的节点target所有的节点集合;

2.将节点p的节点集合存储在list集合中,节点q的节点存储在map集合中(便于查找是否存在公共节点);

注意: 遍历list集合并在map集合中查看是否存在时,要从后往前查找,否则函数将会返回root节点。

  public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        List<TreeNode> path1 = getPath(root,p);
        Map<TreeNode,Integer> path2 = getPath2(root,q);
        for (int i = path1.size()-1; i >=0 ;i--){//注意:从后往前开始查找
            TreeNode res = new TreeNode();
            res = path1.get(i);
            if (path2.containsKey(res)){
                return res;
            }
        }
        return root;
    }

    public List<TreeNode> getPath(TreeNode root, TreeNode target) {

        List<TreeNode> list = new ArrayList<>();
        TreeNode node = root;
        while (node!=target){
            list.add(node);
            if (node.val>target.val){
                node = node.left;
            }else node = node.right;
        }
        list.add(node);
        return list;
    }

    public Map<TreeNode,Integer> getPath2(TreeNode root, TreeNode target) {

        Map<TreeNode,Integer> map = new HashMap<>();
        TreeNode node = root;
        while (node!=target){
            map.put(node,1);
            if (node.val>target.val){
                node = node.left;
            }else node = node.right;

        }
        map.put(node,1);
        return map;
    }

剑指 Offer 68 - II. 二叉树的最近公共祖先

题目:

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

题解:

DFS ,清晰图解

1.采用深度遍历去寻找目标节点p和q;

2.当满足以下三个条件时终止递归:

  • root为空,即遍历到叶子节点时;

  • root为p,即已经找到p不再需要找q,原因:

    • 假设q是p的子节点,则返回 p即可没有q的事,不需要继续向下递归;

在这里插入图片描述

  • 假设q不是p的子节点,则需要遍历上一个节点的右子树去寻找q,同样不需要继续向下递归。

在这里插入图片描述

  • root为q,同理;
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q) return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left == null) return right;
        if(right == null) return left;
        return root;
    }
}

剑指 Offer 07. 重建二叉树

题目:

输入某二叉树的前序遍历中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

题解(分治思想):

分治算法,清晰图解

1.recur函数中的变量:

  • root---->前序遍历数组下root的下标
  • left---->中序遍历数组下子树的左边界
  • right---->中序遍历数组下子树的右边界

2.左右子树递归

在这里插入图片描述

依照上图可以确定递归调用时需要传递的参数:

  • node.left = recur(root + 1, left, i - 1);
  • node.right = recur(root + i - left + 1, i + 1, right);

3.递归结束的条件为left > right

class Solution {
    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for(int i = 0; i < inorder.length; i++)
            dic.put(inorder[i], i);
        return recur(0, 0, inorder.length - 1);
    }
    TreeNode recur(int root, int left, int right) {
        if(left > right) return null;                          // 递归终止
        TreeNode node = new TreeNode(preorder[root]);          // 建立根节点
        int i = dic.get(preorder[root]);                       // 划分根节点、左子树、右子树
        node.left = recur(root + 1, left, i - 1);              // 开启左子树递归
        node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
        return node;                                           // 回溯返回根节点
    }
}

剑指 Offer 16. 数值的整数次方

题目:

实现 pow(x, n) ,即计算 x 的 n 次幂函数。不得使用库函数,同时不需要考虑大数问题。

题解(快速幂):

快速幂,清晰图解

在这里插入图片描述

public double myPow(double x, int n) {
        if(x == 0) return 0;
        long b = n;//避免 n = -2147483648 时执行 n = -n 会因越界而赋值出错
        double res = 1.0;
        if(b < 0) {
            x = 1 / x;
            b = -b;
        }
        while(b > 0) {
            if((b & 1) == 1) res *= x;//b%2==1
            x *= x;
            b >>= 1;                  //b=b/2
        }
        return res;
    }

剑指 Offer 33. 二叉搜索树的后序遍历序列

题目:

输入一个整数数组,判断该数组是不是某二叉搜索树后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

题解:

递归分治 / 单调栈,清晰图解

1.对于二叉搜索树来讲,最后一个节点为根节点,从左到右第一个比根节点大的是右子树的最左下角的节点,是右子树的开始,如图
在这里插入图片描述

2.recur函数的参数:

  • int[] postorder 后续遍历的数组
  • i ---->树的起始下标
  • j —>树的末尾下标

3.recur函数的思想:

  • 从下标i开始遍历,直到下标p增加至m时,此时当前节点值比根节点值大为止,证明i~m-1为左子树;

  • 下标p从m继续遍历,只要当前值比根节点值大则继续前进;

  • 如果最后p==j则证明当前这棵树为二叉搜索树,此时继续向下递归它的左右子树,recur(postorder, i, m - 1)
    recur(postorder, m, j - 1)
    参数如下图:

在这里插入图片描述

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return recur(postorder, 0, postorder.length - 1);
    }
    boolean recur(int[] postorder, int i, int j) {
        if(i >= j) return true;
        int p = i;
        while(postorder[p] < postorder[j]) p++;//对右子树进行遍历,判断右子树是否都比根节点小
        int m = p;
        while(postorder[p] > postorder[j]) p++;//对右子树进行遍历,判断右子树是否都比根节点大
      return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
    }
}

平时卖米粉的阿姨今天在卖米饭,一看是我又多加了半碗,转身真的泪目了,配上姐妹一早点的奶茶,绝绝子啊!!!
平时上楼走过4楼门禁的时候要是听到后面有人,我就会摁一下开关,省得后面的小姐姐再拿钥匙。今天回宿舍走到门禁那我还没等拿钥匙门就开了,只看到了一个背影,下次我一定大喊谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值