算法学习——LeetCode力扣补充篇13
662. 二叉树最大宽度
描述
给你一棵二叉树的根节点 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. 乘积最大子数组
描述
给你一个整数数组 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];
}
};