剑指offer 打卡计划 | 每日进步一点点 | 第二十天

107 阅读2分钟

图片.png 一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

剑指 Offer 53 - II. 0~n-1中缺失的数字

思路

(二分) O(logn)

假设数组中第一个缺失的数是 x,那么数组中的数如下所示:

图片.png

从中可以看出,数组左边蓝色部分都满足nums[i] == i,数组右边橙色部分都不满足nums[i] == i,因此我们可以二分出分界点 x的值。

具体过程如下:

1、初始化l = 0r = nums.size() - 1,二分nums[i] !=i的最左边界。

2、当nums[mid] != mid , 说明答案在左半部分,往左边区域找,则r = mid

3、当nums[mid] == mid , 说明答案在右半部分,往右边区域找,则l = mid + 1

图片.png

4、当只剩下一个数时,就是缺失数字,我们返回r

实现细节:

当所有数都满足nums[i] == i时,表示缺失的是 n

时间复杂度分析: 二分的时间复杂度是 O(logn)。

c++代码

 class Solution {
 public:
     int missingNumber(vector<int>& nums) {
         int l = 0, r = nums.size() - 1;
         while(l < r){
             int mid = (l + r) / 2;
             if(nums[mid] != mid) r = mid;
             else l = mid + 1;
         }
         if(nums[r] == r)  r++;  //缺失的是n 
         return r;
     }
 };

剑指 Offer 54. 二叉搜索树的第k大节点

思路

(dfs) O(n)

什么是二叉搜索树 ?

二叉搜索树是一棵有序的二叉树,所以我们也可以称它为二叉排序树。具有以下性质的二叉树我们称之为二叉搜索树:若它的左子树不为空,那么左子树上的所有值均小于它的根节点;若它的右子树不为空,那么右子树上所有值均大于它的根节点。它的左子树和右子树分别也为二叉搜索树。

二叉搜索树的中序遍历是:左=>根=>右; 二叉搜索树的中序遍历从小到大是有序的。

中序遍历模板

 //打印中序遍历
 void dfs(TreeNode* root ) 
 {
     if(!root) return;
     dfs(root->left);    //左
     print(root->val);   //根
     dfs(root->right);   //右
 }

如图所示

图片.png

因此求二叉搜索树第 k大的节点” 可转化为求 “二叉搜索树的中序遍历倒序的第k 个节点”。

过程如下:

  • 1、按照右->根->左的顺序(中序遍历倒序)遍历二叉树
  • 2、我们每次遍历一个节点的时候就让k--,当k减为0时,我们就找到了第k大的节点。

具体实现细节看代码。

时间复杂度分析: 每个节点最多只会被遍历1次,因此n个节点,时间复杂度为O(n) 。

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: 
     int res;
     int kthLargest(TreeNode* root, int k) {
         dfs(root,k);
         return res;
     }
     void dfs(TreeNode* root ,int &k) //传引用 这里需要保证所有dfs函数共用一个k 
     {
         if(!root) return;
         dfs(root->right,k);
         k--;
         if(!k) res = root->val;
         dfs(root->left,k);
     }
 };

剑指 Offer 55 - I. 二叉树的深度

思路

(递归) O(n)

一棵二叉树的最大深度 == max(左子树最大深度, 右子树最大深度) + 1

图片.png

时间复杂度分析: O(n)

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:
     //一棵二叉树的最大深度 == max(左子树最大深度, 右子树最大深度) + 1
     int maxDepth(TreeNode* root) {
         if(!root) return 0;
         int lh = maxDepth(root->left), rh = maxDepth(root->right);
         return max(lh, rh) + 1;
     }
 };