分发饼干
- 力扣题目链接
- 大饼干满足胃口大的,小饼干满足胃口小的,物尽其用!
int findContentChildren(vector<int>& g, vector<int>& s) {
int j=s.size()-1, cnt=0;
sort(g.begin(), g.end());
sort(s.begin(), s.end());
for(int i=g.size()-1; i>=0; i--){
// 判断顺序不可弄反
if(j>=0 && s[j]>=g[i]) {j--; cnt++;}
}
return cnt;
}
摆动序列
- 力扣题目链接
- 方法1:把符合摆动数列定义的差值记录到vector中,此方式不易出错
int wiggleMaxLength(vector<int>& nums) {
vector<int> delta(nums.size()-1);
int cnt=0;
for(int i=0; i<nums.size()-1; i++){
delta[cnt]=nums[i+1]-nums[i];
if(delta[cnt]==0) continue;
if(cnt>0)
if(delta[cnt-1]>0 && delta[cnt]>0
|| delta[cnt-1]<0 && delta[cnt]<0)
continue;
cnt++;
}
return cnt+1;
}
- 方法2:双指针法优化空间
int wiggleMaxLength(vector<int>& nums) {
int cnt=0, curDiff=0, preDiff=0;
// 注意这里要减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)) {
cnt++;
preDiff=curDiff; // 注意,只在摆动变化的时候更新prediff
}
}
return cnt+1;
}
最大子序和
- 力扣题目链接
- 方法1:局部最优值不停累加,直到小于0重开,若存在更大的最优,记录下来
int maxSubArray(vector<int>& nums) {
int maxSum=INT_MIN, tmp=0;
for(int i=0; i<nums.size(); i++){
tmp+=nums[i];
// 位置不能交换,先更新后判断
if(tmp>maxSum) maxSum=tmp;
if(tmp<0) tmp=0;
}
return maxSum;
}
- 方法2:动态规划
int maxSubArray(vector<int>& nums) {
if (nums.size()==0) return 0;
vector<int> dp(nums.size(), 0); // dp[i]表示包括i之前的最大连续子序列和
dp[0]=nums[0];
int result=dp[0];
for(int i=1; i<nums.size(); i++){
// 状态转移方程的定义
dp[i]=max(dp[i-1]+nums[i], nums[i]);
if(dp[i]>result) result=dp[i];
}
return result;
}
买卖股票的最佳时机Ⅱ
- 力扣题目链接
- 以天为单位,拿走所有正利润!(未卜先知)
int maxProfit(vector<int>& prices) {
int maxVal=0;
for(int i=0; i<prices.size()-1; i++)
if(prices[i+1]-prices[i]>0)
maxVal+=(prices[i+1]-prices[i]);
return maxVal;
}
- 动态规划的方法留到动态规划再说
跳跃游戏
- 力扣题目链接
- 终点是否可达,得看每一步的最大覆盖范围
- cover动态变化作为判断条件是亮点!
bool canJump(vector<int>& nums) {
int cover=0;
if(nums.size()==1) return true;
// 注意,这里不是nums.size()-1哦
for(int i=0; i<=cover; i++){
cover=max(nums[i]+i, cover); // 贪心
if(cover>=nums.size()-1) return true;
}
return false;
}
跳跃游戏Ⅱ
- 力扣题目链接
- 跳最少的步,就得看当前步和下一步的覆盖范围
int jump(vector<int>& nums) {
if(nums.size()==1) return 0;
int cur=0, next=0; // 当前步和下一步最大覆盖范围
int ans=0;
for(int i=0; i<nums.size(); i++){
next=max(nums[i]+i, next);
if(i==cur){
cur=next;
ans++;
if(next>=nums.size()-1) break;
}
}
return ans;
}
- 这两道题目都是不需要再回头的,可以再小小优化一下:
int jump(vector<int>& nums) {
if(nums.size()==1) return 0;
int cur=0, next=0; // 当前步和下一步最大覆盖范围
int ans=0;
// 倒数第二格多一步必到,ans也会++
for(int i=0; i<nums.size()-1; i++){
next=max(nums[i]+i, next);
if(i==cur){
cur=next;
ans++;
}
}
return ans;
}
K次取反后最大化的数组和
- 按绝对值从大到小排序即可
// 按绝对值从大到小排序,必须是静态函数
static bool cmp(int a, int b){
return abs(a)>abs(b);
}
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(), nums.end(), cmp);
int sum=0, i=0;
while(k--){
if(nums[i]==0) break;
if(i<nums.size()-1){
if(nums[i]>0) k++;
else nums[i]*=-1;
i++;
}
else nums[i]*=-1;
}
// 求和
for(auto num : nums) sum+=num;
return sum;
}
参考资料
[1] 代码随想录
[2] Leetcode题解