|
| 1 | +今天来盘一盘 **贪心算法 ** 这类题目 |
| 2 | + |
| 3 | + |
| 4 | + |
| 5 | +使用**python**刷题分类整理的笔记,请参考: [https://github.com/lxztju/leetcode-algorithm/tree/v1](https://github.com/lxztju/leetcode-algorithm/tree/v1) |
| 6 | + |
| 7 | +## 贪心算法 |
| 8 | +贪心算法是指每步都选择最优的策略,以此达到全局的最优。**局部最优—>全局最优** |
| 9 | + |
| 10 | +贪心策略的选择必须具备**无后效性**,也就是说某个状态以前的过程不会影响以后的状态,只与当前状态有关。 |
| 11 | + |
| 12 | +* 455 分发饼干 (Easy) |
| 13 | +* 121 买卖股票的最佳时机 (Easy) |
| 14 | +* 122 买卖股票的最佳时机 II (Easy) |
| 15 | +* 605 种花问题 (Easy) |
| 16 | +* 665 非递减数列 (Easy) |
| 17 | +* 53 最大子序和 (Easy) |
| 18 | +* 435 无重叠区间 (Medium) |
| 19 | +* 452 用最少数量的箭引爆气球 (Medium) |
| 20 | +* 406 根据身高重建队列(Medium) |
| 21 | +* 763 划分字母区间 (Medium) |
| 22 | + |
| 23 | + |
| 24 | +#### 455 分发饼干 (Easy) |
| 25 | +* 二者排序之后采用双指针比较。 |
| 26 | +```c++ |
| 27 | +class Solution { |
| 28 | +public: |
| 29 | + int findContentChildren(vector<int>& g, vector<int>& s) { |
| 30 | + // 分别将二者排序 |
| 31 | + sort(g.begin(), g.end()); |
| 32 | + sort(s.begin(), s.end()); |
| 33 | + int i = 0, j = 0; |
| 34 | + int res = 0; |
| 35 | + while (i < g.size() && j < s.size()){ |
| 36 | + if (s[j] >= g[i]){ |
| 37 | + i++; |
| 38 | + res++; |
| 39 | + } |
| 40 | + j++; |
| 41 | + } |
| 42 | + return res; |
| 43 | + } |
| 44 | +}; |
| 45 | +``` |
| 46 | +
|
| 47 | +#### 121 买卖股票的最佳时机 (Easy) |
| 48 | +
|
| 49 | +```c++ |
| 50 | +class Solution { |
| 51 | +public: |
| 52 | + int maxProfit(vector<int>& prices) { |
| 53 | + // 暴力法 |
| 54 | + // 双重循环,从第i天买入可以获得的最大利润,计算最大值 |
| 55 | + int maxprofit = 0; |
| 56 | + for ( int i = 0; i < prices.size() - 1; i++){ |
| 57 | + for (int j = i + 1; j < prices.size(); j++){ |
| 58 | + int profit = prices[j] - prices[i]; |
| 59 | + maxprofit = max(profit, maxprofit); |
| 60 | + } |
| 61 | + } |
| 62 | + return maxprofit; |
| 63 | + } |
| 64 | +}; |
| 65 | +``` |
| 66 | + |
| 67 | +```c++ |
| 68 | +class Solution { |
| 69 | +public: |
| 70 | + int maxProfit(vector<int>& prices) { |
| 71 | + // 使用minprice变量保存当前天之前的最低价格, 如果在此之前采用最低价格买入,那么当前卖出的利润最大 |
| 72 | + int maxprofit = 0; |
| 73 | + int minprice = INT_MAX; |
| 74 | + for(auto price : prices){ |
| 75 | + minprice = min(minprice, price); |
| 76 | + maxprofit = max(maxprofit, price - minprice); |
| 77 | + } |
| 78 | + return maxprofit; |
| 79 | + } |
| 80 | +}; |
| 81 | +``` |
| 82 | +
|
| 83 | +#### 122 买卖股票的最佳时机 II (Easy) |
| 84 | +* 与上一题的主要区别就是,可以多次交易 |
| 85 | +* 也就是当前只要获利为正就可以交易。 |
| 86 | +
|
| 87 | +
|
| 88 | +```c++ |
| 89 | +class Solution { |
| 90 | +public: |
| 91 | + int maxProfit(vector<int>& prices) { |
| 92 | + int ans = 0; |
| 93 | + int n = prices.size(); |
| 94 | + for (int i = 1; i < n; ++i) { |
| 95 | + ans += max(0, prices[i] - prices[i - 1]); |
| 96 | + } |
| 97 | + return ans; |
| 98 | + } |
| 99 | +}; |
| 100 | +``` |
| 101 | + |
| 102 | +#### 605 种花问题 (Easy) |
| 103 | +```c++ |
| 104 | +class Solution { |
| 105 | +public: |
| 106 | + bool canPlaceFlowers(vector<int>& flowerbed, int n) { |
| 107 | + // 贪心的种植, 可以种植的位置,直接众,只要左右联测均为0,就可以种植。 |
| 108 | + // 需要考虑首尾的两个元素的特殊情况。将首尾各补上0 |
| 109 | + int res = 0; |
| 110 | + for (int i = 0; i< flowerbed.size(); i++){ |
| 111 | + int left = (i == 0) ? 0 : flowerbed[i-1]; |
| 112 | + int right = (i == flowerbed.size()-1) ? 0 : flowerbed[i+1]; |
| 113 | + if (left == 0 && right == 0 && flowerbed[i] == 0){ |
| 114 | + // cout<<res<<" " <<i<<endl; |
| 115 | + res++; |
| 116 | + flowerbed[i] = 1; |
| 117 | + } |
| 118 | + } |
| 119 | + return res >= n; |
| 120 | + } |
| 121 | +}; |
| 122 | +``` |
| 123 | +#### 665 非递减数列 (Easy) |
| 124 | +* 遇到nums[i]>nums[i+1]需要将nums[i]变小或者nums[i+1]变大 |
| 125 | +* 如果nums[i + 1] < nums[i - 1],需要将nums[i+1]变大 |
| 126 | +* 其他情况下nums[i]变小 |
| 127 | +
|
| 128 | +```c++ |
| 129 | +class Solution { |
| 130 | +public: |
| 131 | + bool checkPossibility(vector<int>& nums) { |
| 132 | + int cnt = 0; |
| 133 | + for (int i = 0; i < nums.size()-1 && cnt < 2; i++) { |
| 134 | + if (nums[i] > nums[i + 1]) { |
| 135 | + cnt++; |
| 136 | + if (i > 0 && nums[i + 1] < nums[i - 1]) { |
| 137 | + nums[i + 1] = nums[i]; |
| 138 | + } |
| 139 | + else { |
| 140 | + nums[i] = nums[i + 1]; |
| 141 | + } |
| 142 | + } |
| 143 | + } |
| 144 | + return cnt < 2; |
| 145 | + } |
| 146 | +}; |
| 147 | +``` |
| 148 | +#### 53 最大子序和 (Easy) |
| 149 | +```c++ |
| 150 | +class Solution { |
| 151 | +public: |
| 152 | + int maxSubArray(vector<int>& nums) { |
| 153 | + // 暴力法 |
| 154 | + int maxnum = nums[0]; |
| 155 | + int tmp = 0; |
| 156 | + for (int i = 0; i < nums.size(); i++){ |
| 157 | + tmp = nums[i]; |
| 158 | + maxnum = max(maxnum, tmp); |
| 159 | + for (int j = i+1; j < nums.size(); j++){ |
| 160 | + tmp += nums[j]; |
| 161 | + maxnum = max(maxnum, tmp); |
| 162 | + } |
| 163 | + } |
| 164 | + return maxnum; |
| 165 | + } |
| 166 | +}; |
| 167 | +``` |
| 168 | +
|
| 169 | +
|
| 170 | +```c++ |
| 171 | +class Solution { |
| 172 | +public: |
| 173 | + int maxSubArray(vector<int>& nums) { |
| 174 | + // 动态规划 |
| 175 | + int maxnum = nums[0]; |
| 176 | + vector<int> dp(nums.size(), 0); // dp表示到i位置的最长子序和。 |
| 177 | + dp[0] = nums[0]; |
| 178 | + for (int i = 1; i< nums.size(); i++){ |
| 179 | + dp[i] = max(nums[i], dp[i-1] + nums[i]); |
| 180 | + maxnum = max(dp[i], maxnum); |
| 181 | + } |
| 182 | + |
| 183 | + return maxnum; |
| 184 | + } |
| 185 | +}; |
| 186 | +``` |
| 187 | + |
| 188 | +#### 435 无重叠区间 (Medium) |
| 189 | +```c++ |
| 190 | +class Solution { |
| 191 | +public: |
| 192 | + // 按照区间右边界排序 |
| 193 | + static bool cmp (const vector<int>& a, const vector<int>& b) { |
| 194 | + return a[1] < b[1]; |
| 195 | + } |
| 196 | + int eraseOverlapIntervals(vector<vector<int>>& intervals) { |
| 197 | + if (intervals.size() == 0) return 0; |
| 198 | + sort(intervals.begin(), intervals.end(), cmp); |
| 199 | + |
| 200 | + int cnt = 0; |
| 201 | + for (int i = 1; i < intervals.size(); i++) { |
| 202 | + if (intervals[i][0] < intervals[i - 1][1]) { |
| 203 | + cnt++; |
| 204 | + intervals[i][1] = min(intervals[i - 1][1], intervals[i][1]); |
| 205 | + } |
| 206 | + } |
| 207 | + return cnt; |
| 208 | + } |
| 209 | +}; |
| 210 | + |
| 211 | + |
| 212 | +``` |
| 213 | +#### 452 用最少数量的箭引爆气球 (Medium) |
| 214 | +```c++ |
| 215 | +class Solution { |
| 216 | +public: |
| 217 | + // 按照区间的右端点排序 |
| 218 | + static bool cmp(const vector<int>& a, const vector<int>& b){ |
| 219 | + return a[1] < b[1]; |
| 220 | + } |
| 221 | + int findMinArrowShots(vector<vector<int>>& points) { |
| 222 | + // 与上一题的最大不重叠区间的问题实际是一样的 |
| 223 | + if(points.size() < 2) return points.size(); |
| 224 | + sort(points.begin(), points.end(), cmp); |
| 225 | + int cnt = 1; |
| 226 | + for (int i = 1; i < points.size(); i++){ |
| 227 | + if (points[i][0] > points[i-1][1]) |
| 228 | + cnt++; |
| 229 | + else |
| 230 | + points[i][1] = min(points[i][1], points[i-1][1]); |
| 231 | + } |
| 232 | + return cnt; |
| 233 | + } |
| 234 | +}; |
| 235 | +``` |
| 236 | +#### 406 根据身高重建队列(Medium) |
| 237 | +```c++ |
| 238 | +class Solution { |
| 239 | +public: |
| 240 | + static bool cmp(const vector<int> a, const vector<int> b) { |
| 241 | + if (a[0] == b[0]) return a[1] < b[1]; |
| 242 | + return a[0] > b[0]; |
| 243 | + } |
| 244 | + vector<vector<int>> reconstructQueue(vector<vector<int>>& people) { |
| 245 | + sort (people.begin(), people.end(), cmp); |
| 246 | + vector<vector<int>> que; |
| 247 | + for (int i = 0; i < people.size(); i++) { |
| 248 | + int position = people[i][1]; |
| 249 | + que.insert(que.begin() + position, people[i]); |
| 250 | + } |
| 251 | + return que; |
| 252 | + } |
| 253 | +}; |
| 254 | +``` |
| 255 | +#### 763 划分字母区间 (Medium) |
| 256 | +```c++ |
| 257 | +class Solution { |
| 258 | +public: |
| 259 | + static bool cmp(const vector<int>& a, const vector<int>& b){ |
| 260 | + return a[0] < b[0]; |
| 261 | + } |
| 262 | + vector<int> partitionLabels(string S) { |
| 263 | + // 这个题目实际上还是求最大的不重合区间的个数 |
| 264 | + // 首先遍历字符串S,求出每个字符首次与最后一次出现的次数 |
| 265 | + // 这样还是一个不重合区间的个数问题 |
| 266 | + |
| 267 | + vector<vector<int>> boards(26, vector<int>(2, -1)); |
| 268 | + for (int i = 0; i < S.size(); i++){ |
| 269 | + int index = S[i] - 'a'; |
| 270 | + if (boards[index][0] == -1){ |
| 271 | + boards[index][0] = i; |
| 272 | + boards[index][1] = i; |
| 273 | + } |
| 274 | + else |
| 275 | + boards[index][1] = i; |
| 276 | + } |
| 277 | + |
| 278 | + sort(boards.begin(), boards.end(), cmp); |
| 279 | + |
| 280 | + vector<int> res; |
| 281 | + |
| 282 | + int i = 0; |
| 283 | + while (i < 26){ |
| 284 | + if (boards[i][1] != -1) break; |
| 285 | + i++; |
| 286 | + } |
| 287 | + |
| 288 | + int min_board = boards[i][0]; |
| 289 | + int max_board = boards[i][1]; |
| 290 | + // i++; |
| 291 | + while ( i < 26){ |
| 292 | + if ( boards[i][0] > max_board){ |
| 293 | + res.push_back(max_board - min_board + 1); |
| 294 | + min_board = boards[i][0]; |
| 295 | + } |
| 296 | + |
| 297 | + max_board = max(max_board,boards[i][1]); |
| 298 | + i++; |
| 299 | + } |
| 300 | + res.push_back(max_board - min_board + 1); |
| 301 | + return res; |
| 302 | + } |
| 303 | +}; |
| 304 | +``` |
| 305 | +
|
| 306 | +
|
| 307 | +
|
| 308 | +
|
| 309 | +
|
| 310 | +## 更多分类刷题资料 |
| 311 | +
|
| 312 | +* 微信公众号: 小哲AI |
| 313 | +
|
| 314 | +  |
| 315 | +
|
| 316 | +* GitHub地址: [https://github.com/lxztju/leetcode-algorithm](https://github.com/lxztju/leetcode-algorithm) |
| 317 | +* csdn博客: [https://blog.csdn.net/lxztju](https://blog.csdn.net/lxztju) |
| 318 | +* 知乎专栏: [https://www.zhihu.com/column/c_1101089619118026752](https://www.zhihu.com/column/c_1101089619118026752) |
| 319 | +* AI研习社专栏:[https://www.yanxishe.com/column/109](https://www.yanxishe.com/column/109) |
| 320 | +
|
0 commit comments