算法学习——LeetCode力扣补充篇13(662. 二叉树最大宽度、152. 乘积最大子数组、153. 寻找旋转排序数组中的最小值)

算法学习——LeetCode力扣补充篇13

在这里插入图片描述

662. 二叉树最大宽度

662. 二叉树最大宽度 - 力扣(LeetCode)

描述

给你一棵二叉树的根节点 root ,返回树的 最大宽度 。

树的 最大宽度 是所有层中最大的 宽度 。

每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。

题目数据保证答案将会在 32 位 带符号整数范围内。

示例

示例 1:

输入:root = [1,3,2,5,3,null,9]
输出:4
解释:最大宽度出现在树的第 3 层,宽度为 4 (5,3,null,9) 。

示例 2:

输入:root = [1,3,2,5,null,null,9,6,null,7]
输出:7
解释:最大宽度出现在树的第 4 层,宽度为 7 (6,null,null,null,null,null,7) 。

示例 3:

输入:root = [1,3,2,5]
输出:2
解释:最大宽度出现在树的第 2 层,宽度为 2 (3,2) 。

提示

树中节点的数目范围是 [1, 3000]
-100 <= Node.val <= 100

代码解析

层次补全(超时)
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
        int result = 0;
        queue<TreeNode*> myQueue;
        deque<int> myDeque;
        myQueue.push(root);

        int size = myQueue.size();
        while(myQueue.size() > 0)
        {
            size = myQueue.size();
            for(int i=0 ; i<size ; i++)
            {
                TreeNode* tmp = myQueue.front();
                myQueue.pop();
                myDeque.push_back(tmp->val);
               
                if(tmp->left != nullptr) myQueue.push(tmp->left);
                else 
                {
                    TreeNode* left_tmp = new TreeNode(-1);
                    myQueue.push(left_tmp);
                }

                if(tmp->right != nullptr) myQueue.push(tmp->right);
                else 
                {
                    TreeNode* right_tmp = new TreeNode(-1);
                    myQueue.push(right_tmp);
                }
            }
           

            while(myDeque.front() == -1) myDeque.pop_front();
            if(myDeque.size() == 0) return result;
            while(myDeque.back() == -1) myDeque.pop_back();

            // for(auto it=myDeque.begin() ; it!=myDeque.end();it++)
            //     cout<<*it<<' ';
            // cout<<"cont:"<<myDeque.size();
            // cout<<endl;

            if(result < myDeque.size()) result = myDeque.size();
            myDeque.clear();

        }

        return result;
    }
};
深度搜索

假设根节点的编号为1,左子节点为2,右子节点为3……以此类推,会得出如下结论:

root的编号=N
root.left的编号=2 * N
root.right的编号=2 * N + 1

那么我们通过编号就可以计算同层中两个节点直接的距离了。我们还是以root = [1,3,2,5,null,null,9,6,null,7]为例,看看通过编号怎么去解题。

在这里插入图片描述
由于深度优先,是先从最上层沿着一条父子关系链遍历的下层,类似一个分支一个分支的去遍历,那么,我们就需要一个Map来帮助我们存储层级与当前层级最小值的对应关系了——即:key=level,value=minValue。那么,我们每当遍历一个节点时,就可以通过当前的level值去获取最小节点值:

如果Map中不存在该level的最小值,则将该节点的值放入到map中作为当前level下的最小值;
如果存在,那么则用当前节点值node.val减去从Map中获取的当前level下的最小值;

我们还是以root = [1,3,2,5,null,null,9,6,null,7]为例,看看通过深度优先怎么去解题。请见下图:

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    unordered_map<int,unsigned long long> myMap;
    unsigned long long result = 0;
    void dfs( TreeNode* cur , int level , unsigned long long indox )
    {
        if(cur == nullptr) return;
        if(myMap.count(level) == 0) myMap[level] = indox;

        result = max( result , indox - myMap[level]  + 1);

        dfs(cur->left , level+1 , indox*2);
        dfs(cur->right , level+1 , indox*2 + 1);
    }
    int widthOfBinaryTree(TreeNode* root) {
        dfs(root,0,1);
        return result;
    }
};

152. 乘积最大子数组

152. 乘积最大子数组 - 力扣(LeetCode)

描述

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续
子数组
(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

示例

示例 1:

输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。

提示

1 <= nums.length <= 2 * 104
-10 <= nums[i] <= 10
nums 的任何前缀或后缀的乘积都 保证 是一个 32-位 整数

代码解析

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int result = 0;
        vector<vector<int>> dp(nums.size() , vector<int>(2,0));
       
        dp[0][0] = nums[0]; //最大队列初始化
        dp[0][1] = nums[0]; //最小队列初始化
        result = dp[0][0];
        for(int i=1 ; i<nums.size() ; i++)
        {
            dp[i][0] = max(dp[i-1][0]*nums[i] , max(nums[i] ,dp[i-1][1]*nums[i] ));
            dp[i][1] = min(dp[i-1][0]*nums[i] , min(nums[i] ,dp[i-1][1]*nums[i] ));
            if( dp[i][0]> result) result = dp[i][0];
        }
        return result;
    }
};

153. 寻找旋转排序数组中的最小值

153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode)

描述

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

提示

n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums 中的所有整数 互不相同
nums 原来是一个升序排序的数组,并进行了 1 至 n 次旋转

代码解析

在这里插入代码片![class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0 , right = nums.size()-1 ,  mid;

        while(left < right)
        {
            mid = left + (right - left)/2;

            // cout<<left<<' '<<mid<<' '<<right<<endl;

            if(nums[mid] < nums[right]) right = mid;
            else if(nums[mid] > nums[right]) left = mid + 1;

          
        }
        return nums[left];
    }
};
  • 18
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拉依达的嵌入式小屋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值