贪心算法学习五

例题一

解法(贪⼼):
贪⼼策略:
我们的任何选择,应该让这个数尽可能快的变成 1
对于偶数:只能执⾏除 2 操作,没有什么分析的;
对于奇数:
i. n== 1 的时候,不⽤执⾏任何操作;
ii. n == 3 的时候,变成 1 的最优操作数是 2
iii. (n / 2) % 2 == 0 的时候,那么它的⼆进制表⽰是 ......01 ,最优的⽅式应该选择 -1 ,这样就可以把末尾的 1 ⼲掉,接下来执⾏除法操作,能够更快的变成 1 ;
iv. (n / 2) % 2 == 1 的时候,那么它的⼆进制表⽰是 ......11 ,此时最优的策略应该是 +1 ,这样可以把⼀堆连续的 1 转换成 0 ,更快的变成 1

例题二

解法⼀(动态规划):
将数组按照左端点排序之后,问题就转化成了最⻓上升⼦序列模型,那接下来我们就可以⽤解决最⻓上升⼦序列的经验,来解决这个问题。
1. 状态表⽰:
dp[i] 表⽰:以 i 位置的箱子为结尾的堆起来的箱子序列中,最高的箱子序列的高度;
2. 状态转移⽅程:
dp[i] = max(dp[i] , dp[j] + box[i] ) 其中 0 <= j < i && box[i][0] > box[j][0] && box[i][1] > box[j][1]&& box[i][2] > box[j][2] ;
3. 初始化:
初始化为 每个箱子原来的高度  
4. 填表顺序:
从左往右;
5. 返回值:
整个 dp 表中的最⼤值。

例题三

解法⼀(动态规划):
将数组按照左端点排序之后,问题就转化成了最⻓上升⼦序列模型,那接下来我们就可以⽤解决最⻓上升⼦序列的经验,来解决这个问题(虽然会超时,但是还是要好好写代码)。
1. 状态表⽰:
dp[i] 表⽰:以 i 位置的信封为结尾的所有套娃序列中,最⻓的套娃序列的⻓度;
2. 状态转移⽅程:
dp[i] = max(dp[j] + 1) 其中 0 <= j < i && e[i][0] > e[j][0] && e[i][1] > e[j][1] ;
3. 初始化:
全部初始化为 1
4. 填表顺序:
从左往右;
5. 返回值:
整个 dp 表中的最⼤值。
解法⼆(重写排序 + 贪⼼ + ⼆分):
当我们把整个信封按照「下⾯的规则」排序之后:
i. 左端点不同的时候:按照「左端点从⼩到⼤」排序;
ii. 左端点相同的时候:按照「右端点从⼤到⼩」排序;
我们发现,问题就变成了仅考虑信封的「右端点」,完完全全的变成的「最⻓上升⼦序列」的模型。那么我们就可以⽤「贪⼼ + ⼆分」优化我们的算法。

例题四

解法⼀(动态规划):
1. 状态表⽰:
dp[0][i]:表示取到第 i 个数的时候%3余数为0的最大值;
dp[1][i]:表示取到第 i 个数的时候%3余数为1的最大值;
dp[2][i]:表示取到第 i 个数的时候%3余数为2的最大值。
2. 状态转移⽅程:
1.当nums[i-1] % 3 == 0时
dp[0][i] = max(dp[0][i - 1], dp[0][i - 1] + nums[i - 1]);
dp[1][i] = max(dp[1][i - 1], dp[1][i - 1] + nums[i - 1]);
dp[2][i] = max(dp[2][i - 1], dp[2][i - 1] + nums[i - 1]);

2.当nums[i - 1] % 3 == 1时

dp[0][i] = max(dp[0][i - 1], dp[2][i - 1] + nums[i - 1]);
dp[1][i] = max(dp[1][i - 1], dp[0][i - 1] + nums[i - 1]);
dp[2][i] = max(dp[2][i - 1], dp[1][i - 1] + nums[i - 1]);

3.当nums[i - 1] % 3 == 2时

dp[0][i] = max(dp[0][i - 1], dp[1][i - 1] + nums[i - 1]);
dp[1][i] = max(dp[1][i - 1], dp[2][i - 1] + nums[i - 1]);
dp[2][i] = max(dp[2][i - 1], dp[0][i - 1] + nums[i - 1]);

3. 初始化:
dp[0][0] = 0, dp[1][0] = INT_MIN, dp[2][0] = INT_MIN;
4. 填表顺序:
从左往右;
5. 返回值:
dp[ 0 ][ n ]
解法二(正难则反 + 贪⼼ + 分类讨论):
正难则反:
我们可以先把所有的数累加在⼀起,然后根据累加和的结果,贪⼼的删除⼀些数。
分类讨论:
设累加和为 sum ,⽤ x 标记 %3 == 1 的数,⽤ y 标记 % 3 == 2 的数。那么根据 sum 的余数,可以分为下⾯三种情况:
a. sum % 3 == 0 ,此时所有元素的和就是满⾜要求的,那么我们⼀个也不⽤删除;
b. sum % 3 == 1 ,此时数组中要么存在⼀个 x ,要么存在两个 y 。因为我们要的是最⼤值,所以应该选择 x 中最⼩的那么数,记为 x1 ,或者是 y 中最⼩以及次⼩的两个数,记为y1,y2 。 那么,我们应该选择两种情况下的最⼤值: max(sum - x1, sum - y1 - y2)
c. sum % 3 == 2 ,此时数组中要么存在⼀个 y ,要么存在两个 x 。因为我们要的是最⼤值,所以应该选择 y 中最⼩的那么数,记为 y1 ,或者是 x 中最⼩以及次⼩的两个数,记为 x1, x2
那么,我们应该选择两种情况下的最⼤值: max(sum - y1, sum - x1 - x2)

例题五

解法(贪⼼):
贪⼼策略:
每次处理⼀批相同的数字,往 n 个空⾥⾯摆放;每次摆放的时候,隔⼀个格⼦摆放⼀个数;优先处理出现次数最多的那个数。

例题六

解法(贪⼼):
贪⼼策略:
与上⾯的⼀道题解法⼀致~

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要满血复活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值