LeetCode字节跳动专题 - 动态或贪心

买卖股票的最佳时机

给定一个数组,它的第 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。

解法

因为只能交易一次,所以要找出差值最大的那个。

AC代码

class Solution {
public:
   int maxProfit(vector<int>& prices) {
       int si=prices.size();
       if(si==0)
           return 0;
       int ans=0;
       int minn=prices[0];
       for(int i=1;i<si;i++){
           minn=min(minn,prices[i]);  
           ans=max(ans,prices[i]-minn);
       }
       return ans;
   }
};

买卖股票的最佳时机II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

解法

因为不限交易次数,那么遍历数组,只要隔天买卖能赚差价,就可以购买。

AC代码

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

最大正方形

在一个由 0 和 1 组成的二维矩阵内,找到只包含 1 的最大正方形,并返回其面积。
示例:
输入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
输出: 4

解法

判断以某个点为正方形右下角时最大的正方形时,那它的上方,左方和左上方三个点也一定是某个正方形的右下角,否则该点为右下角的正方形最大就是它自己了。 我们知道,该点为右下角的正方形的最大边长,最多比它的上方,左方和左上方为右下角的正方形的边长多 1,最好的情况是是它的上方,左方和左上方为右下角的正方形的大小都一样的,这样加上该点就可以构成一个更大的正方形。 但如果它的上方,左方和左上方为右下角的正方形的大小不一样,合起来就会缺了某个角落,这时候只能取那三个正方形中最小的正方形的边长加 1 了。

AC代码

class Solution {
public:
   int maximalSquare(vector<vector<char>>& matrix) {
       if(matrix.empty() || matrix[0].empty())  
           return 0;
       int n=matrix.size(),m=matrix[0].size();
       int ans=0;
       int dp[n][m];
       memset(dp,0,sizeof(dp));
       for(int i=0;i<n;i++)
       {
           if(matrix[i][0]=='1')
           {
               dp[i][0]=1;ans=1;
           }
       }
       for(int i=0;i<m;i++)
       {
           if(matrix[0][i]=='1')
           {
               dp[0][i]=1;ans=1;
           }
       }
       for(int i=1;i<n;i++)
       {
           for(int j=1;j<m;j++)
           {
               if(matrix[i][j]=='1')
                   dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
               ans=max(ans,dp[i][j]);
           }
       }
       return ans*ans;
   }
};

最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
进阶:
如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

解法

一个最大的子序和,我们从中间将这个序列分开,那么这个最大值有三种可能,这个最大值出现在左半边,或者出现在右半边,或者横跨中间。因此我们根据这个思想,在这个三个当中求解出最大值就可以了,同理对于左半边和右半边的最大值我们也是这么求解的。

AC代码

class Solution {
public:
   int maxsum(int l,int r,vector<int>& nums)
   {
       int ans;
       if(r==l)
           return nums[l];
       int mid=(l+r)/2;
       ans=max(maxsum(l,mid,nums),maxsum(mid+1,r,nums));
       int templ=nums[mid],t=0;
       for(int i=mid;i>=l;i--)
           templ=max(templ,t+=nums[i]);
       int tempr=nums[mid+1];t=0;
       for(int i=mid+1;i<=r;i++)
           tempr=max(tempr,t+=nums[i]);
       return max(ans,templ+tempr);
   }
   int maxSubArray(vector<int>& nums) {
       int si=nums.size();
       if(si==0)
           return 0;
       return maxsum(0,si-1,nums);
   }
};

三角形最小路径和

给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。
例如,给定三角形:
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。
说明:
如果你可以只使用 O(n) 的额外空间(n 为三角形的总行数)来解决这个问题,那么你的算法会很加分。

解法

基础dp,倒推。

AC代码

class Solution {
public:
   int minimumTotal(vector<vector<int>>& triangle) {
       int n=triangle.size();
       if(n==0)
           return 0;
       int dp[n];
       memset(dp,0,sizeof(dp));
       for(int i=0;i<n;i++)
           dp[i]=triangle[n-1][i];
       for(int i=n-2;i>=0;i--)
       {
           for(int j=0;j<=i;j++)
               dp[j]=triangle[i][j]+min(dp[j],dp[j+1]);
       }
       return dp[0];
   }
};

俄罗斯套娃信封问题

给定一些标记了宽度和高度的信封,宽度和高度以整数对形式 (w, h) 出现。当另一个信封的宽度和高度都比这个信封大的时候,这个信封就可以放进另一个信封里,如同俄罗斯套娃一样。
请计算最多能有多少个信封能组成一组“俄罗斯套娃”信封(即可以把一个信封放到另一个信封里面)。
说明: 不允许旋转信封。
示例:
输入: envelopes = [[5,4],[6,4],[6,7],[2,3]]
输出: 3
解释: 最多信封的个数为 3, 组合为: [2,3] => [5,4] => [6,7]。

解法

先按要求排好序,然后就是最长上升子序列的问题。

AC代码

class Solution {
public:
   int maxEnvelopes(vector<pair<int, int>>& envelopes) {
       int res = 0, n = envelopes.size();
       vector<int> dp(n, 1);
       sort(envelopes.begin(), envelopes.end());
       for (int i = 0; i < n; ++i) {
           for (int j = 0; j < i; ++j) {
               if (envelopes[i].first > envelopes[j].first && envelopes[i].second > envelopes[j].second) {
                   dp[i] = max(dp[i], dp[j] + 1);
               }
           }
           res = max(res, dp[i]);
       }
       return res;
   }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值