121. 买卖股票的最佳时机* - easy
还是太菜,想了很久
用双指针来记录最小值和最大利润,每进来一个数就要比较是否为最小数,并且比较此时卖出是否比之前卖出赚的更多
//14.57
//15.25
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() <= 1) return 0;
int sum = 0, small = prices[0];
for(int i = 1; i < prices.size(); i++) {
if(prices[i]-small > sum) {
sum = prices[i]-small;
}
if(small > prices[i]) {
small = prices[i];
}
}
return sum;
}
};
101. 对称二叉树*** - easy
这道题我觉得不算简单题,原因在于他的思想很新(起码对于我来说),他考察的是同时遍历左右子树的遍历过程,以前只试过遍历一遍再另一边,所以这种思想很新
同时遍历左右子树:我们可以改写平时的dfs(root)为dfs(left, right)
//15.54
//16.37
class Solution {
bool check(TreeNode *l, TreeNode *r) {
if(l == nullptr && r == nullptr) return 1;
if(l == nullptr || r == nullptr) return 0;
if(l->val != r->val) return 0;
if(check(l->left, r->right) == 0) return 0;
if(check(l->right, r->left) == 0) return 0;
return 1;
}
public:
bool isSymmetric(TreeNode* root) {
if(root == nullptr) return true;
return check(root->left, root->right);
}
};
53. 最大子序和*** - easy
方法一:动态规划
//16.49
//17.20
//动态规划算法
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.empty()) return 0;
if(nums.size() == 1) return nums[0];
vector<int> ans(nums.size(), 0);
ans[0] = nums[0];
for(int i = 1; i < nums.size(); i++) {
ans[i] = max(ans[i-1]+nums[i], nums[i]);
}
int large = ans[0];
for(int x : ans) {
if(large < x) large = x;
}
return large;
}
};
方法二:分治法
两步:
- 划分 - 最大子序列和会在左半边 / 右半边 / 任意包含左半最后一个以及右半第一个元素的交叉组合
- 处理 - 对于最大和处于两边的,对于中间重合部分从start到end用法一中的动规,返回三部分的最大值
可以参考lizhiqiang-3的图解,下面也是大佬的代码
//分治法
public int maxSubArray(int[] nums) {
return maxSubArrayDivideWithBorder(nums, 0, nums.length-1);
}
private int maxSubArrayDivideWithBorder(int[] nums, int start, int end) {
if (start == end) {
// 只有一个元素,也就是递归的结束情况
return nums[start];
}
// 计算中间值
int center = (start + end) / 2;
int leftMax = maxSubArrayDivideWithBorder(nums, start, center); // 计算左侧子序列最大值
int rightMax = maxSubArrayDivideWithBorder(nums, center + 1, end); // 计算右侧子序列最大值
// 下面计算横跨两个子序列的最大值
// 计算包含左侧子序列最后一个元素的子序列最大值
int leftCrossMax = Integer.MIN_VALUE; // 初始化一个值
int leftCrossSum = 0;
for (int i = center ; i >= start ; i --) {
leftCrossSum += nums[i];
leftCrossMax = Math.max(leftCrossSum, leftCrossMax);
}
// 计算包含右侧子序列最后一个元素的子序列最大值
int rightCrossMax = nums[center+1];
int rightCrossSum = 0;
for (int i = center + 1; i <= end ; i ++) {
rightCrossSum += nums[i];
rightCrossMax = Math.max(rightCrossSum, rightCrossMax);
}
// 计算跨中心的子序列的最大值
int crossMax = leftCrossMax + rightCrossMax;
// 比较三者,返回最大值
return Math.max(crossMax, Math.max(leftMax, rightMax));
}
作者:lizhiqiang-3
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zheng-li-yi-xia-kan-de-dong-de-da-an-by-lizhiqiang/
来源:力扣(LeetCode)
114. 二叉树展开为链表 - medium
位于root时,flatten左边后flatten右边,然后找到左子树的最右叶子节点,将root的右子树接到最右叶子节点的右边即可(思路对了,但花了30多分钟才写出来。。。)
//22.17
//23.50
class Solution {
public:
void flatten(TreeNode* root) {
if(root == nullptr) return ;
if(root->left != nullptr) flatten(root->left);
if(root->right != nullptr) flatten(root->right);
TreeNode* left = root->left;
if(left != nullptr) {
while(left->right != nullptr) {
left = left->right;
}
left->right = root->right;
root->right = nullptr;
swap(root->left, root->right);
}
}
};