贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下最优决策的算法。贪心算法通常用来解决最优化问题,其核心思想是通过局部最优解逐步推导出全局最优解。
在贪心算法中,我们并不总是考虑到未来可能发生的情况,而是只关注当前的最优选择。这种贪心选择性质使得贪心算法特别适合解决那些具有最优子结构性质的问题,即局部最优解能够推导出全局最优解的问题。
贪心算法的基本思路可以总结为以下几步:
需要注意的是,贪心算法并不适用于所有的问题,因为并非所有问题都具有最优子结构性质。在某些情况下,贪心算法得到的结果可能并不是全局最优解,而只是一个较好的解。因此,在应用贪心算法时,需要仔细分析问题的特性,以确定贪心算法是否适用于该问题。
下面我们会解决一些 数组相关的算法题(子数组、子序列类问题)
代码:
class Solution {
public:
int halveArray(vector<int>& nums) {
priority_queue<double> heap;
// 统计sum
double sum = 0.0;
for(auto x : nums)
{
heap.push(x);
sum += x;
}
sum /= 2.0;
// 统计最少操作次数
int count = 0;
while(sum > 0)
{
double tmp = heap.top() / 2;
heap.pop();
sum -= tmp;
++count;
heap.push(tmp);
}
return count;
}
};
代码:
class Solution {
public:
string largestNumber(vector<int>& nums) {
// 将数字转换为字符串
vector<string> strs;
for(auto x : nums) strs.push_back(to_string(x));
// 根据字符串排序
// s1s2 > s2s1 则 s1s2在前,s2s1在后
sort(strs.begin(), strs.end(), [&](const string& s1, const string& s2){
return s1 + s2 > s2 + s1;
});
// 提取结果
string ret;
for(auto s : strs)
ret += s;
// 判断特殊情况:000000...->0
if(ret[0] == '0') return "0";
return ret;
}
};
代码:
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
// 贪心
vector<int> ret;
ret.push_back(nums[0]);
for(int i = 0; i < nums.size(); ++i)
{
if(nums[i] > ret.back()) {
ret.push_back(nums[i]);
} else { // 二分查找
int left = 0, right = ret.size() - 1;
while(left < right)
{
int mid = (left + right) >> 1;
if(ret[mid] < nums[i])
left = mid + 1;
else
right = mid;
}
ret[left] = nums[i]; // 插入
}
}
return ret.size();
}
};
代码:
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int a = nums[0], b = INT_MAX;
for(auto x : nums)
{
if(x > b) return true;
else if (x > a) b = x;
else a = x;
}
return false;
}
};
代码:
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
vector<int> tmp(nums.begin(), nums.end());
tmp.push_back(INT_MIN); // 用于简化特殊处理
int ret = 0;
int i = 0, j = 1; // 即left 于 right
while (i < tmp.size() && j < tmp.size()) {
if (tmp[j - 1] < tmp[j]) {
++j;
} else {
// 更新结果 + 移动 i 指针
ret = max(ret, j - i);
i = j; // 将 i 指针移到 j 的位置继续寻找连续递增子序列
++j; // 同时移动 j 指针
}
}
return ret;
}
};
代码:
int MLS(vector<int>& arr) {
sort(arr.begin(), arr.end());
int curLen = 1, maxLen = 1;
for (int i = 1; i < arr.size(); ++i)
{
if (arr[i - 1] != arr[i]) // 不等于前一元素
{
if (arr[i - 1] + 1 == arr[i]) { // 连续
curLen++;
}
else { // 不连续
maxLen = max(maxLen, curLen);
curLen = 1;
}
}
}
return max(curLen, maxLen);
}
代码:
int findLongestNumSub() {
string s;
while (cin >> s) {
int maxLen = 0; // 最长数字串的长度
vector<string> substrings; // 存储最长数字串
int i = 0, j = 0;
while (i < s.size()) {
while (i < s.size() && !(s[i] >= '0' && s[i] <= '9')) {
++i;
}
j = i;
while (j < s.size() && s[j] >= '0' && s[j] <= '9') {
++j;
}
if (j - i > maxLen) {
maxLen = j - i;
substrings.clear();
substrings.push_back(s.substr(i, maxLen));
}
else if (j - i == maxLen) {
substrings.push_back(s.substr(i, maxLen));
}
i = j; // 移出数字串
}
for (const auto& sub : substrings) {
cout << sub;
}
cout << "," << maxLen;
cout << endl;
} // end while
return 0;
}