121. 买卖股票的最佳时机
题目描述
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
1 <= prices.length <= 105
0 <= prices[i] <= 104
解题思路
首先定义两个变量profit和cost,分别用来记录成本以及利润,然后遍历股票的价格,cost用来记录遍历过的最小价格,作为买入价格,profit用来记录如果当天卖出,能取得的最大利润。遍历完之后profit的最大值即为答案。
代码
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int profit = 0;
int cost = INT_MAX;
for (int i = 0; i < prices.size(); i++)
{
cost = min(cost, prices[i]);
profit = max(profit, prices[i] - cost);
}
return profit;
}
};
122. 买卖股票的最佳时机 II
题目描述
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
示例 1:
输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3。
最大总利润为 4 + 3 = 7 。
示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4。
最大总利润为 4 。
示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0。
提示:
1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104
解题思路
这道题目强调的是在每一天,都可以购买或者出售股票。遍历股票的价格,如果当天比前一天贵就可以记录收益,最后记录所有正收益的总和即为答案。
代码
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
for (int i = 1; i < prices.size(); i++)
{
int profit = prices[i] - prices[i - 1];
if (profit > 0)
{
ans += profit;
}
}
return ans;
}
};
55. 跳跃游戏
题目描述
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。
示例 1:
输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
示例 2:
输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 105
解题思路
首先定义最远位置cover,然后遍历数组,如果当前位置大于能跳的最远位置,则返回false,否则更新最远位置为当前位置+当前能跳最大长度。
代码
cpp
class Solution {
public:
bool canJump(vector<int>& nums) {
int cover = 0;
for (int i = 0; i < nums.size(); i++)
{
if (i > cover)
{
return false;
}
cover = max(cover, i + nums[i]);
}
return true;
}
};
45. 跳跃游戏 II
题目描述
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。
每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:
0 <= j <= nums[i]
i + j < n
返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
提示:
1 <= nums.length <= 104
0 <= nums[i] <= 1000
题目保证可以到达 nums[n-1]
解题思路
首先定义当前右边界cur_right,和下一个右边界next_right。遍历数组,当前右边界不动,更新下一个右边界的最大值,当走到当前右边界的时候,更新当前右边界的值,同时跳跃次数加一,到达n-2个元素的时候返回跳跃次数。
代码
cpp
class Solution {
public:
int jump(vector<int>& nums) {
int ans = 0;
int cur_right = 0;
int next_right = 0;
for (int i = 0; i < nums.size() - 1; i++)
{
next_right = max(next_right, i + nums[i]);
if (i == cur_right)
{
cur_right = next_right;
ans++;
}
}
return ans;
}
};
763. 划分字母区间
题目描述
给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 "ababcc" 能够被分为 ["abab", "cc"],但类似 ["aba", "bcc"] 或 ["ab", "ab", "cc"] 的划分是非法的。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
示例 1:
输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
示例 2:
输入:s = "eccbbbbdec"
输出:[10]
提示:
1 <= s.length <= 500
s 仅由小写英文字母组成
解题思路
首先定义一个数组last用来记录每个字母出现的最后位置,然后遍历s,将具有交集的字母所在区间进行合并,取并集,记录每个区间返回最后的结果。
代码
cpp
class Solution {
public:
vector<int> partitionLabels(string s) {
int n = s.size();
vector<int> last(26, 0);
for (int i = 0; i < n; i++)
{
last[s[i] - 'a'] = i;
}
vector<int> ans;
int start = 0, end = 0;
for (int i = 0; i < n; i++)
{
end = max(end, last[s[i] - 'a']);
if(end == i)
{
ans.push_back(end - start + 1);
start = i + 1;
}
}
return ans;
}
};
455. 分发饼干
题目描述
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是满足尽可能多的孩子,并输出这个最大数值。
示例 1:
输入: g = [1,2,3], s = [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3 个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是 1,你只能让胃口值是 1 的孩子满足。
所以你应该输出 1。
示例 2:
输入: g = [1,2], s = [1,2,3]
输出: 2
解释:
你有两个孩子和三块小饼干,2 个孩子的胃口值分别是 1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出 2。
提示:
1 <= g.length <= 3 * 104
0 <= s.length <= 3 * 104
1 <= g[i], s[j] <= 231 - 1
解题思路
首先将s和g排序,然后遍历饼干大小数组s,如果当前饼干大小满足当前孩子的胃口,ans加一,否则继续循环。
代码
cpp
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(s.begin(), s.end());
sort(g.begin(), g.end());
int ans = 0;
for (int i = 0; i < s.size(); i++)
{
if (ans < g.size() && s[i] >= g[ans])
{
ans++;
}
}
return ans;
}
};
135. 分发糖果
题目描述
n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
示例 1:
输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。
示例 2:
输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。
第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
提示:
n == ratings.length
1 <= n <= 2 * 104
0 <= ratings[i] <= 2 * 104
解题思路
定义数组left和right,从左边第1个开始遍历,如果当前孩子的评分大于前一个则left[i]加一。再从倒数第二个开始遍历,如果当前孩子的评分大于后一个则right[i]加一,最后遍历一遍每个孩子的评分,取每个孩子的left和right数组值大的那个相加。
代码
cpp
class Solution {
public:
int candy(vector<int>& ratings) {
int ans = 0;
int n = ratings.size();
vector<int> left(n, 1);
vector<int> right(n, 1);
for (int i = 1; i < n; i++)
{
if (ratings[i] > ratings[i - 1])
{
left[i] = left[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; i--)
{
if (ratings[i] > ratings[i + 1])
{
right[i] = right[i + 1] + 1;
}
}
for (int i = 0; i < n; i++)
{
ans += max(left[i], right[i]);
}
return ans;
}
};
435. 无重叠区间
题目描述
给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
注意 只在一点上接触的区间是 不重叠的。例如 [1, 2] 和 [2, 3] 是不重叠的。
示例 1:
输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。
示例 2:
输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
示例 3:
输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。
提示:
1 <= intervals.length <= 105
intervals[i].length == 2
-5 * 104 <= starti < endi <= 5 * 104
解题思路
首先按照右端点大小将区间从小到大排序。定义end为第一个区间的右端点,从第一个区间开始遍历,如果当前区间的左端点大于等于end则无重复区间数量加一,更新end为当前区间右端点,最后移除区间的数量为n-无重复区间数量。
代码
cpp
class Solution {
public:
static bool cmp(vector<int>& a, vector<int>& b)
{
return a[1] < b[1];
}
int eraseOverlapIntervals(vector<vector<int>>& intervals) {
int n = intervals.size();
int ans = 1;
sort(intervals.begin(), intervals.end(), cmp);
int end = intervals[0][1];
for (int i = 1; i < n; i++)
{
if (end <= intervals[i][0])
{
end = intervals[i][1];
ans++;
}
}
return n - ans;
}
};
605. 种花问题
题目描述
假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。
给你一个整数数组 flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false 。
示例 1:
输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
示例 2:
输入:flowerbed = [1,0,0,0,1], n = 2
输出:false
提示:
1 <= flowerbed.length <= 2 * 104
flowerbed[i] 为 0 或 1
flowerbed 中不存在相邻的两朵花
0 <= n <= flowerbed.length
解题思路
首先将flowerbed前后各插入一个0,然后从第一个位置还是遍历,如果前中后位置都为0则当前位置能种花,n--,最后如果n的数量小于等于0则视为能种下n朵花
代码
cpp
class Solution {
public:
bool canPlaceFlowers(vector<int>& flowerbed, int n) {
flowerbed.insert(flowerbed.begin(), 0);
flowerbed.push_back(0);
for (int i = 1; i < flowerbed.size() - 1; i++)
{
if (flowerbed[i - 1] == 0 && flowerbed[i] == 0 && flowerbed[i + 1] == 0)
{
flowerbed[i] = 1;
n--;
}
}
return n <= 0;
}
};
452. 用最少数量的箭引爆气球
题目描述
有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。
示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。
示例 2:
输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。
示例 3:
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:
- 在x = 2处发射箭,击破气球[1,2]和[2,3]。
- 在x = 4处射出箭,击破气球[3,4]和[4,5]。
提示:
1 <= points.length <= 105
points[i].length == 2
-231 <= xstart < xend <= 231 - 1
解题思路
首先按照右端点大小将区间从小到大排序。定义pos为第一个区间的右端点,从第一个区间开始遍历,如果当前区间的左端点大于pos则需要加一只箭,pos更新为当前区间右端点
代码
cpp
class Solution {
public:
static bool cmp(vector<int>& a, vector<int>& b)
{
return a[1] < b[1];
}
int findMinArrowShots(vector<vector<int>>& points) {
if (points.empty())
{
return 0;
}
sort(points.begin(), points.end(), cmp);
int ans = 1;
int pos = points[0][1];
for (int i = 1; i < points.size(); i++)
{
if (points[i][0] > pos)
{
pos = points[i][1];
ans++;
}
}
return ans;
}
};
376. 摆动序列
题目描述
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
示例 1:
输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
示例 2:
输入:nums = [1,17,5,10,13,15,10,5,16,8]
输出:7
解释:这个序列包含几个长度为 7 摆动序列。
其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。
示例 3:
输入:nums = [1,2,3,4,5,6,7,8,9]
输出:2
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
解题思路
首先定义curdiff和prediff用来记录当前差异和前一个差异,遍历数组,curdiff等于后项减当前项,如果prediff和curdiff符号不同则长度加一,prediff更新为curdiff。
代码
cpp
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() <=1) return nums.size();
int curdiff = 0;
int prediff = 0;
int result = 1;
for(int i = 0;i<nums.size()-1;i++)
{
curdiff = nums[i+1] - nums[i];
if((prediff<=0 && curdiff>0)||(prediff>=0 && curdiff<0))
{
result++;
prediff = curdiff;
}
}
return result;
}
};
53. 最大子数组和
题目描述
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:
输入:nums = [1]
输出:1
示例 3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
解题思路
定义两个变量result和count,遍历数组,count不断加当前数组中的值,如果count小于0的话将当前位置元素跳过,count置为0,否则更新result值。
代码
cpp
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT32_MIN;
int count = 0;
for(int i = 0;i<nums.size();i++)
{
count += nums[i];
if(count>result)
{
result = count;
}
if(count<=0) count = 0;
}
return result;
}
};