例题一
解法(贪⼼):
贪⼼策略:
我们的任何选择,应该让这个数尽可能快的变成 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[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 个空⾥⾯摆放;每次摆放的时候,隔⼀个格⼦摆放⼀个数;优先处理出现次数最多的那个数。
例题六
解法(贪⼼):
贪⼼策略:
与上⾯的⼀道题解法⼀致~