LeetCode笔记(数组双指针,同时遍历左右子树,最大子序和)

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;
    }
};

方法二:分治法
两步:

  1. 划分 - 最大子序列和会在左半边 / 右半边 / 任意包含左半最后一个以及右半第一个元素的交叉组合
  2. 处理 - 对于最大和处于两边的,对于中间重合部分从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);
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值