【剑指Offer】分治算法

剑指 Offer 07. 重建二叉树

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

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

示例 1:

img

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]

示例 2:

Input: preorder = [-1], inorder = [-1]
Output: [-1]

限制:

0 <= 节点个数 <= 5000
/**
 * 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* bulid(vector<int>& preorder, vector<int>& inorder, int b1, int e1, int b2, int e2){
        if(b1 >= e1)return nullptr;
        TreeNode *t = new TreeNode;
        t->val = preorder[b1];
        int i;
        for(i = b2; i < e2; ++ i){
            if(inorder[i] == t->val){
                break;
            }
        }
        t->left = bulid(preorder, inorder, b1 + 1, b1 + i - b2 + 1, b2,  i);
        t->right = bulid(preorder, inorder, b1 + i - b2 + 1, e1, i + 1, e2);
        return t;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        if(n == 0)return nullptr;
        TreeNode* root;
        root = bulid(preorder, inorder, 0, n, 0, n);
        return root;
    }
};

算法思路

一棵二叉树前序遍历的结果一根节点为首,然后两棵子树的的前序遍历结果分别位于剩余数组的两侧;而中序遍历的结果根节点在数组中间,左右子树的中序遍历结果位于根节点左右两边。知道这个特点后,我们就可以对数组进行分治,对两段数组,一段前序一段中序,我们可以在前序中找到根节点,然后在中序中找到左右结点的个数,然后继续向子树遍历,直到数组大小变为1开始回溯。

题目一结果

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

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

示例 1:

输入:x = 2.00000, n = 10
输出:1024.00000

示例 2:

输入:x = 2.10000, n = 3
输出:9.26100

示例 3:

输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25

提示:

  • -100.0 < x < 100.0
  • -231 <= n <= 231-1
  • -104 <= xn <= 104
class Solution {
public:
    double myPow(double x, int n) {
        if(n == 0){
            return 1;
        }else if(abs(n % 2) == 1){
            if(n > 0){
                return myPow(x, n - 1) * x;
            }else{
                return myPow(x, n + 1) / x;
            }
        }else{
            double tmp = myPow(x, n / 2);
            return tmp * tmp;
        }
    }
};

算法思路

这里我用的是快速幂,快速幂的大概原理就是a^2n = a^n * a^n,就是不用乘2n次,某些情况下可以通过自乘达到减少大量乘法的效果,有点向昨天说的倍增,达到n不一定要走n次,logn就可以搞定。

题目二结果

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

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

参考以下这颗二叉搜索树:

     5
    / \
   2   6
  / \
 1   3

示例 1:

输入: [1,6,3,2,5]
输出: false

示例 2:

输入: [1,3,2,6,5]
输出: true

提示:

  1. 数组长度 <= 1000
class Solution {
public:
    bool check(vector<int> &postorder, int beg, int end){
        if(beg > end){
            return true;
        }
        int i = beg;
        while(i < end && postorder[i] < postorder[end])i ++;
        for(int j = i + 1; j < end; ++ j){
            if(postorder[j] < postorder[end]){
                return false;
            }
        }
        if(i == end || i == beg){
            return check(postorder, beg, end - 1);
        }else{
            return check(postorder, beg, i - 1) && check(postorder, i, end - 1);
        }
    }
    bool verifyPostorder(vector<int>& postorder) {
        int n = postorder.size();
        return check(postorder, 0, n - 1);
    }
};

算法思路

这一题和第一题很像,用的是分治的思想,后序遍历序列的特点是序列最后一个元素为根,两棵子树的元素位于剩余序列的前后两个部分,又因为是二叉搜索树,所以剩余序列的前半部分小于根,后半部分大于根,因此我们可以很快地写出递归函数。不是二叉搜索树的条件是除根节点外剩余序列可以分为大于根和小于根两部分;是二叉搜索树的条件是剩余序列满足条件且两部分都能作为单独的二叉搜索树后序序列。

题目三结果

【剑指Offer】系列:
【剑指Offer】栈
【剑指Offer】链表
【剑指Offer】字符串
【剑指Offer】查找算法
【剑指Offer】查找算法(1)
【剑指Offer】搜索与回溯算法
【剑指Offer】搜索与回溯算法(1)
【剑指Offer】动态规划
【剑指Offer】动态规划(1)
【剑指Offer】动态规划(2)
【剑指Offer】双指针
【剑指Offer】双指针(1)
【剑指Offer】双指针(2)
【剑指Offer】搜索与回溯算法(2)
【剑指Offer】搜素与回溯算法(3)
【剑指Offer】排序
【剑指Offer】排序(1)
【剑指Offer】搜索与回溯算法(4)
【剑指Offer】搜索与回溯算法(5)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值