赞
踩
注:按照代码随想录的刷题指南进行,自己总结补充,以加深印象
参考链接:https://leetcode-cn.com/circle/article/wGp7Y9/
题目来源:力扣(LeetCode)
本质上是通过选取每一阶段的局部最优,最终达成全局最优
没有一般套路,大体可以先模拟一下,或者取反例证明不能用贪心。可以用数学证明贪心策略的正确性(数学归纳法/反证法),但显然难度过大。
难点在于如何通过局部最优得到全局最优
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 ((curDiff > 0 && preDiff <= 0) || (preDiff >= 0 && curDiff < 0)) {
result++;
preDiff = curDiff;
}
}
return result;
}
如果 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!
局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
全局最优:选取最大“连续和”
局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。
根据人们的身高和rank重建队列,其中rank是指该人在队列中前面有rank人的身高大于等于他题目链接
这个关键点:确定一个维度(身高),再按另外一个维度(rank)排序 ,上题也是,先确定左侧的,再确定右侧的
局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性
static bool cmp(vector<int> &a , vector<int> &b){ if(a[0] > b[0] || (a[0] == b[0] && a[1] < b[1])) return true; else return false; } vector<vector<int>> reconstructQueue(vector<vector<int>>& people) { sort(people.begin(), people.end(), cmp); vector<vector<int>> ans; ans.push_back(people[0]); for(int i = 1; i < people.size(); i++){ int rank = people[i][1]; //因为现在ans的元素一定是大于等于现在值的,所以直接按rank插入 ans.insert(ans.begin() + rank, people[i]); } return ans; }
但使用vector是非常费时的,C++中vector(可以理解是一个动态数组,底层是普通数组实现的)如果插入元素大于预先普通数组大小,vector底部会有一个扩容的操作,即申请两倍于原先普通数组的大小,然后把数据拷贝到另一个更大的数组上。所以使用vector(动态数组)来insert,是费时的.
改为list结构(底层用链表实现,便于插入删除), list结构无法随机访问
vector用时5.27%, 内存57%;
list用时86%, 内存31%
然而注意到本题中数组元素的范围为 [-100, 100],因此我们可以使用计数数组(桶)或者哈希表,直接统计每个元素出现的次数,再升序遍历元素的范围,这样就省去了排序需要的时间。
1.K>0,则执行 2,否则执行 4
2.取数组 A 中的最小值,并取反(用上面说的hash找最小值)
3.K-- 执行 1
4.对数组 A 求和
通常需要排序,确定一个维度;
注意重叠的条件
for(int i = 1; i < intervals.size(); i++){
//把弓箭那道题目代码里<= 换成<
if(intervals[i][0] < intervals[i - 1][1]){
//有交集
intervals[i][1] = min(intervals[i-1][1], intervals[i][1]);
}else{
//无交集
count++;
}
}
profit += prices[i] - buy;
buy = prices[i];
如果当天价格小于之前买入花的钱,就按兵不动,
int result = 0; //返回root节点的状态 int traveral(TreeNode * root){ if(root == nullptr) { return 2; //空节点视为状态2 } //记录左右节点的状态,以判断父节点的状态 int left = traveral(root->left); int right = traveral(root->right); if(left == 2 && right == 2){ return 0; }else if(left == 0 || right == 0){ result++; return 1; }else return 2; }
1、贪心没有什么固定套路
2、注意到本题中数组元素的范围为 [-100, 100],因此我们可以使用计数数组(桶)或者哈希表,直接统计每个元素出现的次数,再升序遍历元素的范围,这样就省去了排序需要的时间。
3、很多题本质上是一样的,重点是如何把题目转化为可以解决的问题。
4、数据结构的选择在运行时间上也很重要,比如 通过身高重建队列的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。