day20

1.剑指 Offer 07. 重建二叉树

  i.根据先序遍历(根节点 + 左子树 + 右子树)中序遍历(左子树 + 根节点 + 右子树)求出二叉树的思路就不写了(先序、中序、后序说的是根节点的位置顺序

 ii.dfs(preroot,inleft,inright):

  preroot:先序遍历时的根节点索引(用来找到中序遍历的根节点索引 inroot = dic[preorder[preroot]],preorder[preroot]:根节点的值

  inleft:中序遍历时最左边位索引

  inright:中序遍历时最右边索引

  这样就知道了中序遍历时左子树和右子树的范围了:

        左子树:(inleft,inroot - 1)         右子树:(inroot + 1,inright)

  要进行左右子树的递归还要知道左右子树先序遍历根节点的索引:

     先序遍历:根节点 + 左子树 + 右子树

      左子树:preroot + 1(先序遍历根节点后一个节点就是左子树根节点)

      右子树:preroot + (inroot - inleft) + 1(inroot - inleft:中序遍历时左子树节点个数,这样就求出了先序遍历左子树数目,因为二者数目是一样的;先序遍历右子树根节点 = 根节点 + 左子树节点个数 + 1

iii.这个递归,实质上是在不断的划分根节点、左子树和右子树,划分成很多个小的二叉树,最后回溯汇总成最终要求的二叉树,体现了分治的算法思想

 

 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     TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
13         this -> preorder = preorder;  //成员变量与形参重名了,所以用到了this
14         int n = inorder.size();
15         for(int i = 0;i < n;i ++)
16           dic[inorder[i]] = i;
17         return dfs(0,0,n - 1);
18     }
19 
20 private:
21     vector<int> preorder;
22     unordered_map<int,int> dic;
23     TreeNode* dfs(int preroot,int inleft,int inright){
24       if(inleft > inright) return nullptr;
25       TreeNode* root = new TreeNode(preorder[preroot]);
26       int inroot = dic[preorder[preroot]];
27       root -> left = dfs(preroot + 1,inleft,inroot - 1);
28       root -> right = dfs(preroot + (inroot - inleft) + 1,inroot + 1,inright);
29       return root;
30     }
31 };

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

 快速幂解法:利用二进制,举个栗子🌰:求311,11二进制表示为1011(1 -- 23,0 -- 22,1 -- 21,1 -- 20),11 = 8(23) + 2(21) + 1(20)

 1011:n & 1 == 1,x = 3

 0101:n & 1 == 1,x = 32

 0010:n & 1 == 0,x = 34(无用,舍去)

 0001:n & 1 == 1,x = 38

 0000:退出循环  ==> 311 = 3 * 32 * 38 

 1 class Solution {
 2 public:
 3     double myPow(double x, int n) {
 4        if(x == 0) return 0.0;
 5        double res = 1.0;
 6        if(n < 0){
 7            n = -n; // n < 0,要把n变为正数,正负数二进制码不同
 8            x = 1 / x; //变倒数
 9        }
10        while(n){
11          if(n & 1 == 1) // & 同位与,n和1同位与等于1 说明n二进制最低位为1
12           res *= x; 
13          x *= x;
14          n = n >> 1; //用完即右移出去
15        }
16        return res;
17     }
18 };

 上面那个通不过,因为int32 变量区间n∈[−2147483648,2147483647] ,所以当 n = -2147483648n=−2147483648 时执行 n = -n会因越界而赋值出错。解决方法是先将 n 存入 long 变量 b,后面用 b操作即可

 1 class Solution {
 2 public:
 3     double myPow(double x, int n) {
 4        if(x == 0) return 0.0;
 5        double res = 1.0;
 6        long b = n;
 7        if(b < 0){
 8            b = -b;
 9            x = 1 / x;
10        }
11        while(b){
12          if(b & 1 == 1)
13           res *= x;
14          x *= x;
15          b = b >> 1;
16        }
17        return res;
18     }
19 };

 

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

 后序遍历:左子树 + 右子树 + 根节点

 二叉搜索树:左子树 < 根节点,右子树 > 根节点

 采用分治算法,将二叉树划分成一个个小二叉树,若每个都满足二叉搜索树的条件,最后汇总的总二叉树即为二叉搜索树,得证

 1 class Solution {
 2 public:
 3     bool verifyPostorder(vector<int>& postorder) {
 4       return dfs(postorder,0,postorder.size() - 1);
 5     }
 6 
 7 private:
 8     bool dfs(vector<int>& postorder,int l,int r){
 9         if(l >= r)  return true;
10         int i = l;
11         while(postorder[i] < postorder[r])  i ++; //找到左子树部分,左子树 < 根节点
12         int j = i;
13         while(postorder[j] > postorder[r])  j ++; //找到右节点部分,右子树 > 根节点
14         if(j < r)  return false;
15         return dfs(postorder,l,i - 1)/* 左子树 */ && dfs(postorder,i,r - 1)/* 右子树(去除最后根节点) */;
16     }
17 };

 

posted @ 2022-07-16 17:57  balabalahhh  阅读(33)  评论(0)    收藏  举报