102. 二叉树的层序遍历
难度中等589收藏分享切换为英文关注反馈
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
返回其层次遍历结果:
[ [3], [9,20], [15,7] ]
class Solution {
public:
vector> levelOrder(TreeNode* root) {
vector> res;
queue queue;
if (root != nullptr) queue.push(root);
while (!queue.empty()) {
int n = queue.size();
vector level;
for (int i = 0; i < n; ++i) {
TreeNode* node = queue.front();
queue.pop();
level.push_back(node->val);
if (node->left != nullptr) queue.push(node->left);
if (node->right != nullptr) queue.push(node->right);
}
res.push_back(level);
}
return res;
}
};
104. 二叉树的最大深度
难度简单660收藏分享切换为英文关注反馈
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7]
,
3 / \ 9 20 / \ 15 7
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL) return 0;
else return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
105. 从前序与中序遍历序列构造二叉树
难度中等607收藏分享切换为英文关注反馈
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3 / \ 9 20 / \ 15 7
class Solution {
public:
void get(TreeNode* &root,int lp,int rp,int li,int ri,vector preorder,vector inorder){
if(lp>rp) return;
int val=preorder[lp];
root=new TreeNode(val);
int zhi=li;
for(int j=li;j<=ri;j++){
if(inorder[j]==val){
zhi=j;break;
}
}
int len=zhi-li;//len=1
get(root->left,lp+1,lp+len,li,zhi-1,preorder,inorder);
get(root->right,lp+len+1,rp,zhi+1,ri,preorder,inorder);
}
TreeNode* buildTree(vector& preorder, vector& inorder) {
TreeNode* root=NULL;
get(root,0,preorder.size()-1,0,inorder.size()-1,preorder,inorder);
return root;
}
};
114. 二叉树展开为链表
难度中等499收藏分享切换为英文关注反馈
给定一个二叉树,原地将它展开为一个单链表。
例如,给定二叉树
1 / \ 2 5 / \ \ 3 4 6
将其展开为:
1 \ 2 \ 3 \ 4 \ 5 \ 6
解题思路
题目本质就是把树的左子树全部并到右子树中,虽然没说顺序,但按示例,就是前序了。
也就是说,要把root的右子树,放到左子树的最后一个结点的右子树中。至于左右子树,各自的处理,就是标准的递归了。
所以递归函数的步骤可以理解如下:
当root为空时,不处理;
递归处理root的左子树;
递归处理root的右子树;(当然左右子树也可以后面再处理)
当root没有左子树时,无需处理;
当root有左子树时,要找到最后一个结点last,从root.left开始往下找(因为是已经处理完的,所以root.left只有右子树),循环找right直到最后一个结点即可;
关键:
将root的右子树移到last的右指针,last.right = root.right;
root的左子树移到root的右指针:root.right = root.left;
清空root的左指针:root.left = null;
作者:gousiqi
链接:https://leetcode-cn.com/problems/flatten-binary-tree-to-linked-list/solution/na-ge-wai-mai-de-gong-fu-tu-ran-xiang-tong-liao-by/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public void flatten(TreeNode root) {
if (root == null) return;
flatten(root.left);
flatten(root.right);
if (root.left != null) {
TreeNode last = root.left;
while (last.right != null) last = last.right; // 找到左子树最后一个节点
// 子树的移动三连
last.right = root.right;
root.right = root.left;
root.left = null;
}
}
}
121. 买卖股票的最佳时机
难度简单1126收藏分享切换为英文关注反馈
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4] 输出: 5 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入: [7,6,4,3,1] 输出: 0 解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
典型题目,I还是很好想的,记得复习统一的思路。
非常基础的动态规划!
假如计划在第 i 天卖出股票,那么最大利润的差值一定是在[0, i-1]
之间选最低点买入;所以遍历数组,依次求每个卖出时机的的最大差值,再从中取最大值。
int maxProfit(vector& prices) {
if(prices.size()==0) return 0;
int minx=prices[0];
int ans=0;
for(int i=1;i
124. 二叉树中的最大路径和
难度困难631收藏分享切换为英文关注反馈
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例 1:
输入: [1,2,3] 1 / \ 2 3 输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7] -10 / \ 9 20 / \ 15 7 输出: 42
class Solution {
public:
//任意节点诶....
// 对于二叉树中的一个节点,该节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值,如果子节点的最大贡献值为正,则计入该节点的最大路径和,否则不计入该节点的最大路径和。
int ans=INT_MIN;
int OneSide(TreeNode* root){
if(root==NULL) return 0;
int l=max(0,OneSide(root->left));
int r=max(0,OneSide(root->right));
ans=max(ans,l+r+root->val);
return max(l,r)+root->val;
}
int maxPathSum(TreeNode* root) {
if(root==NULL) return 0;
OneSide(root);
return ans;
}
};
136. 只出现一次的数字
难度简单1415收藏分享切换为英文关注反馈
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1] 输出: 1
示例 2:
输入: [4,1,2,1,2] 输出: 4
class Solution {
public:
int singleNumber(vector& nums) {
int single = 0;
for (int num : nums) {
single ^= num;
}
return single;
}
};
//位运算就是牛逼!!!
139. 单词拆分
难度中等612收藏分享切换为英文关注反馈
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为"
applepenapple"
可以被拆分成"
apple pen apple"
。 注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
动态规划听上去非常高大上,但是其实都是源自于一个很自然的想法,就拿这道题来说,假如需要判断"onetwothreefour"这一个字符串能不能满足条件,我们很自然的想法就是:
如果"onetwothree"这一段可以拆分,再加上four如果也可以,那不就行了;
或者
如果"onetwothre"这一段可以拆分,再加上efour如果也可以,那不就行了;
这其实已经抓住了动态规划的最核心的东西了,换成式子来表达,就是
dp["onetwothreefour"] = dp["onetwothree"这一段] && 判断一下"four"
dp["onetwothreefour"] = dp["onetwothre"这一段] && 判断一下"efour"
遍历顺序稍微有点窍门,就是:要判断dp[j],最好按照 dp[j-1]&&check() -> dp[j-2]&&check -> dp[0]&&check()这个顺序,理由很简单,这样的话check的部分就相当于判断单词是否存在,仔细想想呗~
class Solution {
public:
bool wordBreak(string s, vector& wordDict) {
int n = s.size();
vector dp(n + 1, false);
unordered_map mp;
for(string str:wordDict){
mp[str]=1;
}
dp[0] = true;
//i代表长度。
for (int i = 1; i <= n; i++) {
for(int j=0;j
141. 环形链表
难度简单704收藏分享切换为英文关注反馈
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos
是 -1
,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
进阶:
你能用 O(1)(即,常量)内存解决此问题吗?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
/*
bool hasCycle(ListNode *head) {
unordered_map mp;
// int count=0;
while(head!=NULL){
if(mp.find(head)!=mp.end()) return true;
mp[head]=1;
head=head->next;
}
return false;
}
*/
//快慢指针
bool hasCycle(ListNode *head){
if(head==NULL) return false;
ListNode* first=head;
ListNode* second=head;
while(first->next&&first->next->next){
first=first->next->next;
second=second->next;
if(first==second) return true;
}
return false;
}
};