leetcode c++(3)( 多题买股票动态规划、二叉树搜索中栈的应用、迭代、递归、二分法、push_back()、insert())

1.二叉树的层次遍历Ⅱ

在这里插入图片描述

①广度优先,每次都在out最后插入(push_back()),然后最后将out反转reverse

vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>>out;
        queue<TreeNode*>q;
	    q.push(root);
	    while (!q.empty())
	    {
            vector<int>inside;
		    int S = q.size();
    		for (int i = 0; i < S; i++)//把本层的弄出来
	    	{
		    	TreeNode* Node = q.front();
			    q.pop();              
    			if (Node != NULL)
	    		{
                    inside.push_back(Node->val);
			    	q.push(Node->left);
				    q.push(Node->right);
    			}
	    	}
            if(inside.size()>0)
		        out.push_back(inside);
	    }
        reverse(out.begin(),out.end());
        return out;
    }

②广度优先,每次都在out最前插入(out.insert(out.begin(),xxx))(本来以为会比方法一快很多,但实际确是比方法一慢很多)

vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>>out;
        queue<TreeNode*>q;
	    q.push(root);
	    while (!q.empty())
	    {
            vector<int>inside;
		    int S = q.size();
    		for (int i = 0; i < S; i++)//把本层的弄出来
	    	{
		    	TreeNode* Node = q.front();
			    q.pop();              
    			if (Node != NULL)
	    		{
                    inside.push_back(Node->val);
			    	q.push(Node->left);
				    q.push(Node->right);
    			}
	    	}
            if(inside.size()>0)
		        out.insert(out.begin(),inside);
	    }
        return out;
    }

上面两个是方法二,最下面的是方法一
在这里插入图片描述

2.将有序数组转换为二叉搜索树(构造不唯一的平衡二叉树)

因为是有序的数组,排序刚好是二叉树的中序遍历的结果,所以想到用二分法

在这里插入图片描述

二分法

struct TreeNode {
	int val;
	TreeNode *left, *right;
	TreeNode(int x) :val(x), left(nullptr), right(nullptr) {};
};
TreeNode* dfs(vector<int>& nums,int LE,int RI)
{
	if (LE >= RI)
		return NULL;
	int mid = LE + (RI - LE) / 2;
	TreeNode *root = new TreeNode(nums[mid]);
	root->left = dfs(nums, LE, mid);
	root->right = dfs(nums, mid+1, RI);//必须要+1不然最后两个的时候会出错没办法取完了
	return root;//在内层的时候是返回一颗一颗子树(从最底层的子树开始倒回去返),在最外层是返回最终答案
}
TreeNode* sortedArrayToBST(vector<int>& nums)
{
	if (nums.size() == 0)
		return NULL;
	if (nums.size() == 1)
		return new TreeNode(nums[0]);
	int RI = nums.size(),LE=0;
	return dfs(nums, LE, RI);
}

3.平衡二叉树(判断平衡二叉树)

用两个递归,一个递归是算结点深度,一个递归是判断结点左右子树是否平衡即深度差<=1

在这里插入图片描述

int depth(TreeNode *Node)
{
	if (Node == NULL)
		return 0;
	else
		return max(depth(Node->left),depth(Node->right)) + 1;//深度计算,和104题是一样的
}

bool isBalanced(TreeNode* root) 
{
	if (root == NULL)
		return true;
	int gap = abs(depth(root->left) - depth(root->right));//左右子树深度差
	return gap <= 1 && isBalanced(root->left) && isBalanced(root->right);//左右子树深度差平衡,并且子树的子树...也平衡
}

4.二叉树的最小深度(叶子节点的最小高度)

在这里插入图片描述

①递归(深度)

如果根空,返回0
如果左右有一个空或者都空 ,返回LE+RI+1,因为空的话是0
如果都不空,返回LE和RI的最小值+1

int minDepth(TreeNode* root) 
{
	if (root == NULL)//根空
		return 0;
	int LE = minDepth(root->left);
	int RI = minDepth(root->right);
	if (root->left == NULL || root->right == NULL)//左右有一个空或者都空
		return LE+RI+1;
	return min(LE, RI)+1;//左右都不空
}

int main()
{
	TreeNode *tree = new TreeNode(3);
	tree->left = new TreeNode(9);
	tree->right = new TreeNode(20);
	tree->right->left = new TreeNode(15);
	tree->right->right = new TreeNode(7);
	cout << minDepth(tree);
	return 0;
}

②迭代(广度)(遇到左右子树都为空的结点,返回它的高度)

int minDepth(TreeNode* root) 
{
	if (root == NULL)
		return 0;
	queue<TreeNode*>q;
	q.push(root);
	int ans = 1;
	while (!q.empty())
	{
		int Size = q.size();
		for (int i = 0; i < Size; i++)
		{
			TreeNode *cur = q.front();
			q.pop();
			if (cur->left == NULL && cur->right == NULL)
				return ans;
			if (cur->left != NULL)//只插不空的子树
				q.push(cur->left);
			if (cur->right != NULL)
				q.push(cur->right);
		}
		ans++;
	}
	return 0;
}

或者

int minDepth(TreeNode* root) 
{
	if (root == NULL)
		return 0;
	queue<TreeNode*>q;
	q.push(root);
	int ans = 1;
	while (!q.empty())
	{
		int Size = q.size();
		for (int i = 0; i < Size; i++)
		{
			TreeNode *cur = q.front();
			q.pop();			
			if (cur != NULL)
			{
                if (cur->left == NULL && cur->right == NULL)
				    return ans;	
				q.push(cur->left);//子树空不空都插
				q.push(cur->right);
			}
		}
		ans++;
	}
	return 0;
}

5.路径总和

在这里插入图片描述

①递归:

这两个是一个意思

bool hasPathSum(TreeNode* root, int sum) {
	if (root == NULL)
		return false;
	if (hasPathSum(root->left, sum - root->val))
		return true;
	if (hasPathSum(root->right, sum - root->val))
		return true;
	if (root->left == NULL && root->right == NULL && sum == root->val)
		return true;
	return false;
}
bool hasPathSum(TreeNode* root, int sum) {
	if (root == NULL)
		return false;
	if (root->left == NULL && root->right == NULL && sum == root->val)
		return true;
	return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val);
}

②栈:

//使用两个栈,一个栈保存节点一个栈保存遍历过的节点的总和
    bool hasPathSum(TreeNode* root, int sum) {
        if(!root) return false;//空
        stack<TreeNode*> path;//点
        stack<int> sub;//和
        path.push(root);
        sub.push(root->val);
        while(!path.empty()){
            TreeNode* pnode = path.top();
            path.pop();
            int pval = sub.top();
            sub.pop();
            if(!pnode->left && !pnode->right && pval==sum) return true;
           
            if(pnode->left){
                path.push(pnode->left);
                sub.push(pval+pnode->left->val);
            }
            if(pnode->right){
                path.push(pnode->right);
                sub.push(pval+pnode->right->val);                          
            }
        }
        return false;
    }

6.杨辉三角Ⅰ

在这里插入图片描述

方法一:就是逐层添进去

vector<vector<int>> generate(int numRows)
{
	vector<vector<int>>out;
    if(numRows==0)
    {
        out={};
        return out;
    }
	vector<int>inside;
	inside.push_back(1);
	out.push_back(inside);
	for (int i = 2; i <= numRows; i++)
	{
		vector<int>inside;
		inside.push_back(1);
		for (int j = 2; j <= i - 1; j++)
		{
			inside.push_back(out[i - 2][j - 2] + out[i - 2][j - 1]);
		}
		inside.push_back(1);
		out.push_back(inside);
	}
	return out;
}

方法二:

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> out;
        for(int i=0;i<numRows;i++)
        	out.push_back(vector<int>(i+1,1));//看这里,vector可以不起名字的,size是i+1位,每位初始值是1
       	for(int i=0;i<numRows;i++)
       		for (int j = 1; j < i; j++)
       		 out[i][j]=out[i-1][j-1]+out[i-1][j];
       	return out;
    }
};

7.杨辉三角Ⅱ

在这里插入图片描述

空间利用只有O(N),这个方法挺巧妙的

vector<int> getRow(int rowIndex) {
	vector<int>ans(rowIndex+1, 1);//rowIndex+1位,初值为1
	for (int i = 2; i <= rowIndex; i++)
	{
		for (int j = i - 1; j > 0; j--)
		{
			ans[j] += ans[j - 1];//看看图就懂了,从上层往下层推,每层内部从右往左推
		}
	}
	return ans;
}

8.买股票的最佳时机Ⅰ

在这里插入图片描述

int maxProfit(vector<int>& prices) {
	int max_gap = 0;
	int minprice = INT_MAX;
	for (int i = 0; i < prices.size(); i++)
	{
		max_gap = max(max_gap, prices[i] - minprice);
		minprice = min(minprice, prices[i]);
	}
	return max_gap;
}

9.买股票的最佳时机Ⅱ

在这里插入图片描述

①贪心算法:

逢低买入,逢高卖出,前一天低于后一天价格就符合(画个折线图就懂了)

int maxProfit(vector<int>& prices) {
	int ans=0;
	for (int i = 1; i < prices.size(); i++)
	{
		if (prices[i] > prices[i - 1])
			ans += prices[i] - prices[i - 1];
	}
	return ans;
}

②动态规划:

dp[ i ] [ 0 ]:状态表示在 第i位的时候 不持有,dp的值 是该状态下 最大持有的钱
dp[ i ] [ 1 ]:状态表示在 第i位的时候 持有,dp的值 是该状态下 最大持有的钱

int maxProfit(vector<int>& prices) {
	int dp[prices.size()][2];//0不买或者现在卖(不持有),1买(持有)
	dp[0][0] = 0;
	dp[0][1] = -prices[0];
	for (int i = 1; i < prices.size(); i++)
	{
		dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);//左边是不持有的时候继续保持,右边持有的时候是卖出去
		dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);//左边是持有的时候继续保持,右边是不持有的时候买进
	}
	return dp[prices.size()-1][0];
}

ps:visual studio的编译器不是GCC,所以int dp[prices.size()][2];定义这个的时候是会报错的,只有GCC才支持不是常量定义数组长度。

10.买卖股票时机含冷冻期

在这里插入图片描述

动态规划

和上面122题的区别在于循环里的 dp [ i-2 ] [ 0 ]上一次卖出隔一天

int maxProfit(vector<int>& prices) {
	if (prices.size() == 0)
		return 0;
	int dp[prices.size()][2];//0不买或者现在卖(不持有),1买(持有)
	dp[0][0] = 0;
	dp[0][1] = -prices[0];
    if(prices.size()>1)//i等于1的时候dp[1][1]是-price[0]和-prices[1]看哪个的负值比较大
    {
        dp[1][0] = max(dp[0][0], dp[0][1] + prices[1]);
	    dp[1][1] = max(-prices[0], -prices[1]);
    }
	for (int i = 2; i < prices.size(); i++)/因为有冻结期,所以i要大于2
	{
		dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);//左边是不持有的时候继续保持,右边持有的时候是卖出去
		dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i]);//左边是持有的时候继续保持,右边是不持有的时候买进
	}
	return dp[prices.size()-1][0];
}

11.买卖股票的最佳时机含手续费

在这里插入图片描述

动态规划

和上上面122题的区别在于循环里卖出的时候要减去手续费fee

int maxProfit(vector<int>& prices, int fee) {
	if (prices.size() == 0)
		return 0;
	int dp[prices.size()][2];//0不买或者现在卖(不持有),1买(持有)
	dp[0][0] = 0;
	dp[0][1] = -prices[0];
	for (int i = 1; i < prices.size(); i++)
	{
		dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
		dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
	}
	return dp[prices.size() - 1][0];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值