1.删数问题代码实现:
#include <iostream>
#include <string>
using namespace std;
string deleteDigits(string num, int k) {
int n = num.size();
// 循环删除k个数字
for (int i = 0; i < k; ++i) {
int j = 0;
// 从左到右遍历,找到第一个比下一位大的数字并删除它
while (j < num.size() - 1 && num[j] <= num[j + 1]) {
++j;
}
num.erase(j, 1);
}
// 去除前导0
int start = 0;
while (start < num.size() - 1 && num[start] == '0') {
++start;
}
return num.substr(start);
}
int main() {
string num;
int k;
cin >> num;
cin >> k;
cout << deleteDigits(num, k) << endl;
return 0;
}
反证法证明:
假设存在一个最优解,它不包含贪心选择。这意味着在最优解中,存在一个位置i
,使得a[i] > a[i+1]
,但我们没有删除a[i]
,而是选择了删除另一个数字a[j]
,其中j > i
。
根据贪心策略,我们应该删除a[i]
,因为它比它后面的数字大,删除它会得到一个更小的数。但是根据假设,我们没有这样做。
现在,让我们交换删除操作:我们将a[j]
放回原位,并删除a[i]
。由于a[i] > a[i+1]
,删除a[i]
后,新的数字序列在位置i
的数字将会变小或者保持不变。同时,由于我们没有改变其他位置的数字,新数字序列仍然是一个有效的解,并且它满足删除了k
个数字的条件。
由于新数字序列在位置i
的数字变小了,而其他位置的数字没有变化,我们可以得出结论,新数字序列比原来的最优解更小。这与原假设的最优解相矛盾。
因此,我们的假设不成立,最优解必须包含贪心选择。这证明了删数问题的算法满足贪心选择性质。
对贪心算法的体会和思考:
1.贪心算法的核心在于通过一系列局部最优的选择来构造全局最优解。然而,并不是所有问题都能通过局部最优得到全局最优。
2.贪心算法通常实现简单,运行效率高,因为它不需要考虑所有可能的解决方案,只需做出当前最好的选择。
3.贪心算法的一个特点是它一旦做出选择,就不会回溯,即不会改变之前的决策。
4.贪心算法并不适用于所有问题。例如,对于需要考虑所有可能组合的问题(如旅行商问题),贪心算法往往不能得到最优解。
5.贪心算法与动态规划是两种常见的算法策略。动态规划通过考虑所有可能的子问题来找到最优解,而贪心算法只考虑当前的最优选择。在某些问题上,两者可以相互转换。
6.在实际应用中,有时即使贪心算法不能保证最优解,但若其解足够接近最优解,且计算效率高,那么贪心算法仍然是一个很好的选择。
7.设计一个有效的贪心算法通常需要深入理解问题的本质,以及如何定义“局部最优”。选择合适的贪心策略是算法成功的关键。
8.在一些复杂问题中,贪心算法可以与其他算法结合使用。例如,在动态规划算法中,贪心策略可以用来优化某些步骤,或者作为初始解来加速算法的收敛。