为了满足更多的小孩,避免饼干浪费,那么需要充分利用饼干尺寸喂饱孩子,全局最优就是喂饱尽可能多的小孩
思路1: 大饼干优先满足胃口大的孩子;
思路2: 用尽量小的饼干满足胃口小的孩子
做法1: 排序、child自减(相当于双指针)、贪心。先将饼干数组和小孩数组排序,然后从后往前遍历小孩数组,用大饼干优先满足胃口大的孩子,并统计满足小孩数量。
做法2: 排序、child自加(相当于双指针)、贪心。先将饼干数组和小孩数组排序,然后从前往后遍历饼干,再遍历的胃口,用尽量小的饼干满足胃口小的孩子,并统计满足小孩数量。
做法3: 排序、双指针、贪心。先将饼干数组和小孩数组排序,然后同时遍历饼干和胃口,用尽量小的饼干满足胃口小的孩子,统计满足小孩和使用过饼干的数量。
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
//排序
sort(g.begin(), g.end());
sort(s.begin(), s.end());
//cookie自减+for循环(相当于双指针)
int cookie = s.size()-1;//饼干数组下标,记录哪块饼干被使用过
int children = 0;//被满足的孩子
//先遍历孩子 再从后遍历饼干 相当于大饼干满足胃口大的孩子
for(int i=g.size()-1; i>=0; i--)
{
if(cookie>=0 && g[i] <= s[cookie])//优先用大饼干满足胃口大的孩子
{
children++;//满足的孩子
cookie--;//满足的话 这块饼干用过了
}
}
return children;
}
};
在这里,不能先遍历饼干,再遍历胃口。因为for循环的i 是固定移动的,而if里面的下标 cookie是符合条件cookie>=0 && g[i] <= s[cookie]
才移动的。如果for控制饼干, if控制胃口,会出现如下情况 :
if的cookie指向 胃口10, for的i指向饼干9,因为饼干9满足不了 胃口10,所以i 向前移动,而cookie走不到g[i] <= s[cookie] 的逻辑,所以cookie不会移动。i 持续向前移动,最后所有的饼干都匹配不上,一定是for控制胃口,if控制饼干。
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s)
{
//排序
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int child = 0;
for(int i=0; i<s.size(); i++)
{
if(child < g.size() && g[child] <= s[i]) child++;
}
return child;
}
};
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s)
{
//排序
sort(g.begin(), g.end());
sort(s.begin(), s.end());
int child = 0;
int cookie = 0;
for(;child<g.size() && cookie<s.size();)
{
if(g[child] <= s[cookie]) child++;//当前饼干可以满足当前孩子的需求,孩子数量+1
cookie++;//满足,饼干被使用过了;不满足,饼干被抛弃
}
return child;
}
};
1. 思路: 贪心算法,统计相邻数差值异号的个数,即峰值数,最大摆动序列长度=峰值数+1,注意平坡情况的考虑。
2. 要求删除元素使其达到最大摆动序列:
让峰值尽可能的保持峰值,删除单调坡度上的节点(不包括单调坡度两端的节点),该坡度就有两个局部峰值。让整个序列有最多的局部峰值,从而达到最长摆动序列,最后统计序列长度。
3. 实际操作:
prediff < 0 && curdiff > 0
或者 prediff > 0 && curdiff < 0
,统计峰值数,最大摆动序列长度=峰值数+14. 三种异常情况:
记录峰值条件:prediff < 0 && curdiff > 0
或者 prediff > 0 && curdiff < 0
上下坡中有平坡:
一共有四个2,删除左边三个2或者右边三个2都可以,统一删除左边三个2,
i指向第一个2时,prediff > 0 && curdiff = 0 ;
i指向第二个2时,prediff = 0 && curdiff = 0 ;
i指向第三个2时,prediff = 0 && curdiff = 0 ;
i指向第四个2时,prediff = 0 && curdiff < 0,要记录该峰值,删除前三个2后剩下的峰值。因此,该情况下,记录峰值条件是(preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)
单调坡中有平坡:
如果单调坡中有平坡,是不能算峰值的,只有当坡度摆动变化时,才可以计算峰值数。例如,下图要删除前两个2,有两种更新prediff情况
如果坡度变化后,即出现峰值后再更新prediff,第一个2和最后一个2都会统计为峰值
if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) result++;
preDiff = curDiff;
如果坡度变化时,即出现峰值才更新prediff,只有最后一个2统计为峰值
if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0))
{
result++;
preDiff = curDiff;
}
5. 代码:
class Solution {
public:
//贪心算法
int wiggleMaxLength(vector<int>& nums) {
if(nums.size() <= 1) return nums.size();//空数组或单元素数组
int prediff = 0;//前两个元素差值
int curdiff = 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;//更新prediff
}
}
return result;
}
};
1. 思路: 动态规划,根据当前数组计算山峰山谷数
2. 确定dp数组及其下标含义: 3. 转移方程: 4. dp数组初始化: 一个数可以接到前面的某个数后面,也可以以自身为子序列的起点,所以初始状态为:dp[0][0] = dp[0][1] = 1 5. 代码 思路: 第一层for设置起始位置,第二层for循环遍历数组寻找最大值 思路: 代码: 注意点: 思路及步骤: 代码: 思路: 代码: 思路及步骤: 如果第i天持有股票即dp[i][0], 则有: 如果第i天不持有股票即dp[i][1], 则有: dp[i][0],第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金, 第i-1天持现金-买第i天的股票),即 dp[i][1],第i天持有最多现金 = max(第i-1天持有的最多现金,第i-1天持有股票的最多现金+第i天卖出股票)。即 代码: 思路: 步骤: 代码:
如果nums[i]>nums[i-1],设dp状态为dp[i][0],表示前i个数中,第i个数nums[i]作为山峰的摆动子序列的最长长度;
如果nums[i]
前i个数,0 < j < i,
如果满足nums[j] < nums[i]
,则dp[i][0] = max(dp[i][0], dp[j][1] + 1)
,表示将nums[i]接到前面某个山谷后面,作为山峰
如果满足nums[j] > nums[i]
,则dp[i][1] = max(dp[i][1], dp[j][0] + 1)
,表示将nums[i]接到前面某个山峰后面,作为山谷class Solution {
public:
//动态规划
//确定dp数组及其下标含义
int dp[1005][2];//1.创建dp数组 第一维大小 0 <= nums[i] <= 1000
int wiggleMaxLength(vector<int>& nums)
{
memset(dp, 0, sizeof(dp));//2.将数组的每个元素初始化为0
dp[0][0] = dp[0][1] = 1;//3.dp数组初始化
//遍历dp数组
for(int i=1; i<nums.size(); i++)
{
dp[i][0] = dp[i][1] = 1;//前i个数的dp数组初始化
for(int j=0; j<i; j++)//遍历前i个数的dp数组
{
if(nums[j] < nums[i]) dp[i][0] = max(dp[i][0], dp[j][1]+1);//nums[i]接到前面某个山谷后面,作为山峰
}
for(int j=0; j<i; j++)
{
if(nums[j] > nums[i]) dp[i][1] = max(dp[i][1], dp[j][0]+1);//nums[i]接到前面某个山峰后面,作为山谷
}
}
return max(dp[nums.size()-1][0], dp[nums.size()-1][1]);
}
};
53. 最大子序和
暴力解法 双层for循环
代码: 力扣可以过用例,但是会超时class Solution {
public:
//暴力解法
int maxSubArray(vector<int>& nums) {
int result = INT32_MIN;
int sum = 0;//用来记录每一次遍历连续子数组的和
for(int i=0; i<nums.size(); i++)//决定每次连续子数组的遍历起点
{
sum = 0;//每次连续子数组求和前清零
for(int j=i; j<nums.size(); j++)
{
sum += nums[j];//求和
result = sum > result ? sum : result;//判断上次子数组和大还是当前子数组和大
}
}
return result;
}
};
贪心算法 思路 分析 代码
class Solution {
public:
int maxSubArray(vector<int>& nums)
{
int result = INT32_MIN;//最小负数
int sum = 0;//用来记录每一次遍历连续子数组的和
for(int i=0; i<nums.size(); i++)
{
sum += nums[i];
//记录最大连续和
if(sum > result) result = sum;
//连续和为负数就放弃 下一个元素开始求连续和
if(sum <= 0) sum = 0;
}
return result;
}
};
动态规划 思路 步骤 代码
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
dp[0] = nums[0]
class Solution {
public:
//动态规划
int maxSubArray(vector<int>& nums)
{
if(nums.size()==0) return 0;//剔除空序列
vector<int> dp(nums.size(), 0);//dp数组定义 nums[i]结尾的子序列和
dp[0] = nums[0];//dp数组初始化
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];//记录最大连续和dp[i]
}
return result;
}
};
122.买卖股票的最佳时机II
贪心算法 思路 代码
class Solution {
public:
//贪心算法
int maxProfit(vector<int>& prices) {
int result = 0;
for(int i=1; i<prices.size(); i++)//i从1开始,第二天才有利润
{
//累加每天的正利润,最后求的最大利润
result += max(prices[i]-prices[i-1], 0);
}
return result;
}
};
动态规划 思路 步骤 代码
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]);
dp[0][0] -= prices[0]
dp[0][1]=0
class Solution {
public:
//动态规划
int maxProfit(vector<int>& prices)
{
// dp[i][1]第i天持有的最多现金
// dp[i][0]第i天持有股票后的最多现金
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(2, 0));
dp[0][0] -= prices[0];//持股票
dp[0][1] = 0;//持现金
for(int i=1; i<n; i++)
{
// 第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金, 第i-1天持现金-买第i天的股票)
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);//第i天买了股票
// 第i天持有最多现金 = max(第i-1天持有的最多现金,第i-1天持有股票的最多现金+第i天卖出股票)
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]);//第i天卖了股票
}
return max(dp[n-1][0], dp[n-1][1]);
}
};
1005.K次取反后最大化的数组和
贪心算法 思路 步骤 代码
class Solution {
//绝对值从大到小 排序
static bool campare(int a, int b)
{
return abs(a) > abs(b);
}
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
//1. 排序
sort(nums.begin(), nums.end(), campare);
//2. 遇到负数就变号 k也要统计
for(int i=0; i<nums.size(); i++)
{
if(nums[i]<0 && k>0)
{
nums[i] = -nums[i];
k--;
}
}
//3. 此时都是正序列 且k仍大于0,数值最小的数变号
//k为偶数,偶数次反转后还是正数,不用删减,
//k为奇数,再处理一次,取数值最小的数变号
if(k%2 == 1) nums[nums.size()-1] = -nums[nums.size()-1];
//4.求和
int result = 0;
for(int n : nums) result += n;
return result;
}
};