不知道各位有没有这种感觉,贪心并不像其他算法那样有多么统一的模式规范,贪心就只有一个核心思想——贪当下。所以怎么去构成代码这件事上并没有其他算法那么机械,比如DP就是转移方程,DFS就是回溯剪枝。就感觉还是挺随意的。(仅代表个人理解,不要骂我呜呜呜)
简单
最长回文串
class Solution {
public:
void count(char key, unordered_map<char,int>& hash){
if(hash.find(key) != hash.end()) hash[key]++;
else hash.emplace(key,1);
}
int longestPalindrome(string s) {
unordered_map<char,int> hash;
int sum = 0;
for(char i:s){
count(i,hash);
}
for(auto it = hash.begin();it!=hash.end();){
if(it->second>1){
if(it->second%2){
sum = sum+it->second-1;
it->second = 1;
it++;
}
else{
sum+=it->second;
hash.erase(it++);
}
}
else it++;
}
if(hash.empty()) return sum;
return sum+1;
}
};
成绩:100 83.03
思路:
就感觉很机械啊,不知道为什么会这么快,等会儿去看看思路。
首先我们不要去想怎么去安排这样的一个回文串,而是想想一个回文串有什么特点。
那么很显然一个字符串是左右对称的:
当字符串字符数是偶数个时,字符串就根据中心线左右对称,意味着字符串中的字符都是偶数个,也就是说只要一堆字符每个都是偶数个的,那么就都能拿来构成一个回文串,某些字符多一个少一个就把偶数个拿出来即可。
当字符串字符数是奇数个时,字符串就根据中间字符对称;意味着去掉中心的字符,其余字符就和偶数个(就是上条)规则一样了。
也就是啥呢,一串给定的字符,统计每个字符的数量(我用的hash),只要有字符串是大于1个且为偶数,就可以都拿来构成回文串,然后删除hash表中的对应键值对;如果是奇数,那就拿出最大的偶数个,然后把对应键的值改成1。如果字符个数只有1,跳过即可。
最后统计完出一个sum之后,如果hash是空的,那就构成偶数个字符的回文串。如果hash非空,那就再拿出来一个作为中心字符,构成奇数个字符的回文串。
分发饼干
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(),g.end());
sort(s.begin(),s.end());
int gcur = 0;
int scur = 0;
int count = 0;
while(gcur<g.size() && scur<s.size()){
if(g[gcur]-s[scur]<=0){ //够了,换下一个小朋友
gcur++;
count++;
}
scur++;
}
return count;
}
};
成绩:57.20 47.86
思路:
一开始没看见一个小朋友最多只能给一块饼干,还以为给够就算一次,那逻辑就完全不一样了。
首先两个数组排序。贪心嘛,能贪一个是一个。胃口越小的小朋友越容易贪(bushi)
指向当前小朋友,向后遍历饼干,若不能cover,继续遍历,当能cover,计数count+1。指向下一个小朋友 。任何数组遍历到最后就跳出。
就不是很理解,还能有比这快的?最多循环再改一下吧?难道不用sort吗?去看看大佬们的代码。
数组拆分Ⅰ
class Solution {
public:
int arrayPairSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
int sum = 0;
int cur = 0;
while(cur<nums.size()){
sum += nums[cur];
cur += 2;
}
return sum;
}
};
成绩:93.78 91.76
思路:
想清楚了就很简单
你要想每组取最小求最大的和,怎么样能实现?要让这个最小的尽可能大,那就让每组的插值达到最小,说白了就是排完序,从第一个开始,隔一个取一次,这样就能最大程度避免损失。这个东西应该是有理论的,但是我说不清。