同理,可得
up[i-1] ----下降摆动序列
down[i-1] ---四不像
3:nums[i]==nums[i-1]
四不像
得到状态转移方程:
代码如下:
class Solution {
public:
int wiggleMaxLength(vector& nums) {
int len=nums.size();
if(len==1){
return 1;
}
vector up;
vector down;
up.resize(len);
down.resize(len);
//遍历
up[0]=1;
down[0]=1;
for(int i=1;inums[i-1]){//现在比之前大
up[i]=max(down[i-1]+1,up[i-1]);
down[i]=down[i-1];
}
else if(nums[i]
进阶dp:
只维护一个变量
class Solution {
public:
int wiggleMaxLength(vector& nums) {
int n = nums.size();
if (n < 2) {
return n;
}
int up = 1, down = 1;
for (int i = 1; i < n; i++) {
if (nums[i] > nums[i - 1]) {
up = max(up, down + 1);
} else if (nums[i] < nums[i - 1]) {
down = max(up + 1, down);
}
}
return max(up, down);
}
};
贪心:
class Solution {
public:
int wiggleMaxLength(vector& nums) {
int n = nums.size();
if (n < 2) {
return n;
}
int prevdiff = nums[1] - nums[0];
int ret = prevdiff != 0 ? 2 : 1;
for (int i = 2; i < n; i++) {
int diff = nums[i] - nums[i - 1];
if ((diff > 0 && prevdiff <= 0) || (diff < 0 && prevdiff >= 0)) {
ret++;
prevdiff = diff;
}
}
return ret;
}
};
三、P53最大子数和
第一眼前缀和,然后遍历求和,代码如下:
class Solution {
public:
int maxSubArray(vector& nums) {
int len=nums.size();
if(len==1){
return nums[0];
}
vector res;
res.resize(len);
for(int i=0;inowsum){
nowsum=temp;
}
if(res[i]
一看排名太靠后了,原来还是动态规划。,。。。
想了想,自己看不出来,总结了一下,主要的原因是选取的问题
注意dp的无后效性
举例:
有后效性
简单来说就是不考虑后面的了,考虑以其结尾的。
设有dp数组,dp[i]表示截至i长时以i结尾的最大值
考虑一下:
dp[i]=max(dp[i-1]+nums[i],nums[i]);
代码如下:
class Solution {
public:
int maxSubArray(vector& nums) {
int len=nums.size();
if(len==1){
return nums[0];
}
vector dp;
dp.resize(len);
//初值
dp[0]=nums[0];
for(int i=1;isum){
sum=dp[i];
}
}
return sum;
}
};
四、P122买股票的最佳时机2
一眼dp
class Solution {
public:
int maxProfit(vector& prices) {
int len=prices.size();
//任何时候最多持有1股
//2种情况-第x天持有或者没有持有股票
//持有是否卖,没有是否买
//dp[i][j] == 利润
//i表示第几天
//j表示是否持有股票
//7,1,5,3,6,4
//dp[1][0]=0;
//dp[1][1]=-7;
//dp[2][0]=0;
//dp[2][1]=-1;
//dp[3][0]=4
//dp[3][1]=0;
//dp[4][0]=4; //卖出股票了
//dp[4][1]=-3;
//dp[i][0]=p[i]-dp[i-1][1];
//dp[i][1]=if(dp[i][0]==dp[i-1][0]) -->max(dp[i-1][1],p[i]);
// else dp[i][1]=0;
if(len==1){
return 0;
}
int dp[len][2];
dp[0][0]=0;
dp[0][1]=prices[0];
for(int i=1;i
五、P55跳跃游戏
一眼dp
class Solution {
public:
bool canJump(vector& nums) {
int len=nums.size();
vector res;
res.resize(len);
res[0]=1;
//赋值
for(int i=0;i=len){
break;
}
res[i+j]=1;
}
}
else{
return false;
}
}
return true;
}
};
发现超时了。。。这个时间复杂的一个是o(n),可能是测试数据的问题,要更小一点,不能遍历所以的节点了,换一个思路。
前面的不断更新,实质上是不断更新到最远的距离,更新最远距离就行。
class Solution {
public:
bool canJump(vector& nums) {
int len=nums.size();
vector res;
res.resize(len);
int maxlen=0;//从0开始
for(int i=0;i=len-1){
return true;
}
}
return false;
}
};
六、P45跳跃游戏2
上一题一开始的思路
class Solution {
public:
int jump(vector& nums) {
//多了一个次数
//时间复杂度降低了
//dp[i]=min(dp[i],dp[i-j]+1)
int len=nums.size();
vector dp(len,INT_MAX);
//dp.resize(len);
dp[0]=0;
for(int i=0;i=len){
break;
}
dp[i+j]=min(dp[i+j],dp[i]+1);
}
}
return dp[len-1];
}
};
七、P1005K 次取反后最大化的数组和
简单的模拟
class Solution {
public:
int largestSumAfterKNegations(vector& nums, int k) {
sort(nums.begin(),nums.end());
int len=nums.size();
//检测负数的个数
int sumneg=0;
for(int i=0;i=0){
break;
}
sumneg++;
}
int sum=0;
if(sumneg>=k){
//int ct=0;
for(int i=0;i=sumneg){
break;
}
nums[i]=-nums[i];
}
sort(nums.begin(),nums.end());
if(temp%2==1){
nums[0]=-nums[0];
}
for(int i=0;i k 优先翻转大的
//2: sumneg == k 翻转
//3: sumneg < k 额外翻转的次数是 temp=k-sumneg temp==1 --翻转最小的
//temp==2 不翻转
}
};
八、P134加油站
找了半天,想dp,最后发现暴力就行,这里贴上官方代码
class Solution {
public:
int canCompleteCircuit(vector& gas, vector& cost) {
int n = gas.size();
int i = 0;
while (i < n) {
int sumOfGas = 0, sumOfCost = 0;
int cnt = 0;
while (cnt < n) {
int j = (i + cnt) % n;
sumOfGas += gas[j];
sumOfCost += cost[j];
if (sumOfCost > sumOfGas) {
break;
}
cnt++;
}
if (cnt == n) {
return i;
} else {
i = i + cnt + 1;
}
}
return -1;
}
};
做一个笔记,这里官方的代码很巧妙的避免了圈的问题,通过余数,值得学习
九、135. 分发糖果
看题意,感觉从左向右边遍历一下和从右边向左遍历一下,就行,但发现时间很长,代码如下
class Solution {
public:
int candy(vector& ratings) {
int len=ratings.size();
if(len==1){
return 1;
}
//if r[i]> r[i-1] s[i]>s[i-1]
//if r[i]> r[i+1] s[i]>s[i+1]
// if r[i]=r[i+1]
//2次遍历
//
vector dp(len,1);
for(int i=1;iratings[i-1]){
dp[i]=dp[i-1]+1;
}
}
for(int i=len-2;i>=0;i--){
if(ratings[i]>ratings[i+1]&&dp[i]<=dp[i+1]){
dp[i]=dp[i+1]+1;
}
}
//右边到左边更新
int sum=0;
for(int i=0;i
看了看题解,发现主要是贪心,思路是看图发现它是递增递减
重点是将其所在递减序列所有的加1,那么难度主要就是如何找到递减序列
下面是官方题解:
class Solution {
public:
int candy(vector& ratings) {
int n = ratings.size();
int ret = 1;
int inc = 1, dec = 0, pre = 1;
for (int i = 1; i < n; i++) {
if (ratings[i] >= ratings[i - 1]) {
dec = 0;
pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1;
ret += pre;
inc = pre;
} else {
dec++;
if (dec == inc) {
dec++;
}
ret += dec;
pre = 1;
}
}
return ret;
}
};
看看就行。
十、P860柠檬水找零
简单的模拟
class Solution {
public:
bool lemonadeChange(vector& bills) {
int len=bills.size();
int st5=0;
int st10=0;//优先给10r的
for(int i=0;i0){
st5--;
st10--;
}
else{
st5=st5-3;
}
}
if(st5<0||st10<0){
return false;
}
}
return true;
}
};
十一、406. 根据身高重建队列
一开始没有思路,看了题解,总结来说就是高的看不到矮的,不受矮的影响,矮的会看高的,要受其影响,因此先按照高度排序,先给高的排好位置,再逐步排矮的,代码如下:
class Solution {
public:
static bool cmp(vector p1,vector p2){
if(p1[0]>p2[0]){
return true;
}
else if((p1[0]==p2[0])&&(p1[1]> reconstructQueue(vector>& people) {
sort(people.begin(),people.end(),cmp);
int len=people.size();
vector path;
vector> res;
//res.resize(len,vector(2));
for(int i=0;i=res.size()){
res.push_back(people[i]);
}
else{
res.insert(people[i][1]+res.begin(), people[i]);
}
}
return res;
}
};
十二、452. 用最少数量的箭引爆气球
找规律
class Solution {
public:
int findMinArrowShots(vector>& points) {
if (points.empty()) {
return 0;
}
sort(points.begin(), points.end(), [](const vector& u, const vector& v) {
return u[1] < v[1];
});
int pos = points[0][1];
int ans = 1;
for (const vector& balloon: points) {
if (balloon[0] > pos) {
pos = balloon[1];
++ans;
}
}
return ans;
}
};
十三、435. 无重叠区间
class Solution {
public:
static bool cmp(vector p1,vector p2){
return p1[0]>p2[0];
}
int eraseOverlapIntervals(vector>& intervals) {
sort(intervals.begin(),intervals.end());
int len=intervals.size();
if(len==1){
return 0;
}
int l=intervals[0][1];
int ans=0;
for(int i=1;i=l){//不重叠
l=intervals[i][1];
}
l=min(l,intervals[i][1]);
}
return ans;
}
};
十四、763. 划分字母区间
难点是思路,把字母最后出现的位置看成区间
class Solution {
public:
vector partitionLabels(string s) {
//转换为区间
//记录每一个字母最后出现的位置
//则开始-结束的位置的所有元素的末尾位置都再结束位置之前
int a[26];
memset(a,-1,sizeof(a));
int len=s.size();
for(int i=0;i res;
for(int i=0;iend){
end=a[(int)(s[j]-'a')];
}
}
//cout<
十五、剑指 Offer II 074. 合并区间
思路同上
class Solution {
public:
static bool cmp(vector s1,vector s2){
return s1[0]>s2[0];
}
vector> merge(vector>& intervals) {
sort(intervals.begin(),intervals.end());
int maxr=intervals[0][1];
int maxl=intervals[0][0];
vector > res;
int len=intervals.size();
for(int i=1;imaxr){
//更新
res.push_back({maxl,maxr});
maxr=intervals[i][1];
maxl=intervals[i][0];
continue;
}
if(intervals[i][1]>maxr){
maxr=intervals[i][1];
}
}
res.push_back({maxl,maxr});
return res;
}
};
十六、738. 单调递增的数字
看不懂,看题解理解一下:
先找一个递增序列的结尾,然后将前一位减1,进位,同时递推的满足前面都是递增序列,最后将尾数全设为9
public:
int monotoneIncreasingDigits(int n) {
string strN = to_string(n);
int i = 1;
while (i < strN.length() && strN[i - 1] <= strN[i]) {
i += 1;//递增的
}
if (i < strN.length()) {
while (i > 0 && strN[i - 1] > strN[i]) {
strN[i - 1] -= 1;
i -= 1;
}
for (i += 1; i < strN.length(); ++i) {
strN[i] = '9';
}
}
return stoi(strN);
}
};