多一些Aha Time,发现技术的美妙🍺|

啊原来是这样呀

园龄:8年3个月粉丝:3关注:9

【LeetCode】15.贪心算法系列

总目录:

LeetCode系列导航目录

 

0.理论基础

0.1.概念

贪心的本质是选择每一阶段的局部最优,从而达到全局最优。

如果找出局部最优并可以推出全局最优,就是贪心,如果局部最优都没找出来,就不是贪心,可能是单纯的模拟。

贪心算法一般分为如下四步:

(1)将问题分解为若干个子问题;

(2)找出适合的贪心策略;

(3)求解每一个子问题的最优解;

(4)将局部最优解堆叠成全局最优解。

0.2.注意

 贪心算法并没有特定的题型,是否适用贪心算法要试一试。

分析问题时要注意梳理局部最优是什么,如何由此推出全局最优。

 

1.分发饼干

1.1.问题描述

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
链接:https://leetcode.cn/problems/assign-cookies

1.2.要点

贪心策略:用尽量小的饼干应付胃口尽量小的人。

1.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int findContentChildren(vector<int>& g, vector<int>& s) {
 4         int ret=0;
 5         sort(g.begin(),g.end());
 6         sort(s.begin(),s.end());
 7 
 8         bool getFeeded=false;//是否被满足
 9         int firstCok=0;//第一个可用饼干
10         for(int& child:g){
11             getFeeded=false;
12             for(int i=firstCok;i<s.size();i++){                
13                 //不够
14                 if(s[i]<child){
15                     continue;
16                 }
17 
18                 firstCok=i+1;//更新下一个可用
19                 ret++;
20                 getFeeded=true;
21                 break;             
22             }
23 
24             //未被满足,后面的也不用看了
25             if(!getFeeded){
26                 break;
27             }
28         }
29 
30         return ret;
31     }
32 };
View Code
复制代码

 

2.摆动序列

2.1.问题描述

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
    例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
    相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
链接:https://leetcode.cn/problems/wiggle-subsequence

2.2.要点

贪心策略:算是一种增长算法,遇到不符合条件的则跳过,只取符合趋势的内容。

2.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int wiggleMaxLength(vector<int>& nums) {
 4         int dataLen=nums.size();
 5         if(dataLen<=1){
 6             return dataLen;
 7         }
 8         
 9         int ret=1;
10         int startIndex=1;
11         bool preIsPos=false;//前一个差是否大于0
12         bool curIsPos=false;
13 
14         //取第一个值
15         while(startIndex<dataLen){
16             if(nums[startIndex]!=nums[startIndex-1]){
17                 preIsPos=(nums[startIndex]-nums[startIndex-1])>0;
18                 startIndex++;
19                 ret++;
20                 break;
21             }
22 
23             startIndex++;
24         }
25 
26         //贪心查找后面的值
27         for(int i=startIndex;i<dataLen;i++){
28             if(nums[i]==nums[i-1]){
29                 continue;
30             }
31             curIsPos=(nums[i]-nums[i-1])>0;
32             if(preIsPos==curIsPos){
33                 continue;
34             }
35 
36             preIsPos=curIsPos;
37             ret++;
38         }
39 
40         return ret;
41     }
42 };
View Code
复制代码

 

3.最大子数组和

3.1.问题描述

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

链接:https://leetcode.cn/problems/maximum-subarray/

3.2.要点

贪心策略:当发现为负时,及时止损,重新开始。

3.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int maxSubArray(vector<int>& nums) {        
 4         int dataLen=nums.size();
 5         if(dataLen<=0){
 6             return 0;
 7         }
 8 
 9         int maxSum = INT_MIN;
10         int tempSum = 0;
11         for(int i=0;i<dataLen;i++){
12             tempSum+=nums[i];            
13             maxSum=max(maxSum,tempSum);  
14 
15             if(tempSum<0){
16                 tempSum=0;
17             }          
18         }
19 
20         return maxSum;
21     }
22 };
View Code
复制代码

 

4.买卖股票的最大收益

4.1.问题描述

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii

4.2.要点

贪心策略:取所有正收益即为最大收益。

4.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int maxProfit(vector<int>& prices) {
 4         int ret=0;
 5         for(int i=1;i<prices.size();i++){
 6             ret+=max(prices[i]-prices[i-1],0);
 7         }
 8 
 9         return ret;
10     }
11 };
View Code
复制代码

 

5.跳跃游戏,能否到最后

5.1.问题描述

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标。

链接:https://leetcode.cn/problems/jump-game/

5.2.要点

贪心策略:每个格子都跳一下,记录可达的最远处。注意中止条件:遍历到的位置大于最大可达时即为失败。

5.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     bool canJump(vector<int>& nums) {
 4         int lastPos=0;
 5         for(int i=0;i<nums.size();i++){
 6             if(i>lastPos){return false;}
 7             lastPos=max(lastPos,i+nums[i]);
 8         }
 9         return true;
10     }
11 };
View Code
复制代码

 

6.跳跃游戏,到最后的最小步数

6.1.问题描述

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。
每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:其中0 <= j <= nums[i] ,i + j < n。
返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。
链接:https://leetcode.cn/problems/jump-game-ii

6.2.要点

贪心策略:搜索空间。在可选范围内从第1个开始搜,记录可到达的最大值,由此生成下一轮搜索范围。

6.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int jump(vector<int>& nums) {
 4         int steps=0;
 5         int maxPos=0;//当前可达的最大位置
 6         int start=0,end=1;//start是搜索范围内的第1个,end是搜索范围外的第1个
 7         while(end<nums.size()){
 8             for(int i=start;i<end;i++){
 9                 maxPos=max(maxPos,i+nums[i]);
10             }
11 
12             start=end;//end是上一阶段范围外的第一个,也就是下一阶段的搜索起点
13             end=maxPos+1;//新的搜索结束点
14             steps++;//步数
15         }
16         return steps;
17     }
18 };
View Code
复制代码

 

7.K次取反后最大化的数组和

7.1.问题描述

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。
重复这个过程恰好 k 次。可以多次选择同一个下标 i 。
以这种方式修改数组后,返回数组 可能的最大和 。
链接:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations

7.2.要点

贪心策略:尽量将负数取反过来,优先取反绝对值较大的负数使收益最大。如果负数不够,就取反最小非负数使损失最低。

7.3.代码实例

复制代码
 1 class Solution {
 2 static bool cmp(int a, int b) {
 3     return abs(a) > abs(b);
 4 }
 5 public:
 6     int largestSumAfterKNegations(vector<int>& A, int K) {
 7         sort(A.begin(), A.end(), cmp);       // 第一步
 8         for (int i = 0; i < A.size(); i++) { // 第二步
 9             if (A[i] < 0 && K > 0) {
10                 A[i] *= -1;
11                 K--;
12             }
13         }
14         if (K % 2 == 1) A[A.size() - 1] *= -1; // 第三步
15         int result = 0;
16         for (int a : A) result += a;        // 第四步
17         return result;
18     }
19 };
View Code
复制代码

 

8.加油站问题

8.1.问题描述

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas 和 cost ,如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
链接:https://leetcode.cn/problems/gas-station

8.2.要点

贪心策略:在总量可以满足的前提下,遍历寻找累计油量为负的油站,然后尝试从下一个油站出发。

8.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
 4         //计算总油耗是否满足
 5         int sumLeft=0;
 6         for(int i=0;i<gas.size();i++){
 7             gas[i]=gas[i]-cost[i];
 8             sumLeft+=gas[i];
 9         }
10         if(sumLeft<0){
11             return -1;
12         }
13         
14         //寻找合适的起点,条件是前面累加过来的不能为负
15         int startPos=0;
16         sumLeft=0;
17         for(int i=0;i<gas.size();i++){
18             sumLeft+=gas[i];
19             if(sumLeft<0){
20                 startPos=i+1;//从下一个位置开始
21                 sumLeft=0;//重新累加
22             }
23         }
24 
25         return startPos;
26     }
27 };
View Code
复制代码

 

9.分发糖果

9.1.问题描述

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。
你需要按照以下要求,给这些孩子分发糖果:
    每个孩子至少分配到 1 个糖果。
    相邻两个孩子评分更高的孩子会获得更多的糖果。
请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。
链接:https://leetcode.cn/problems/candy

9.2.要点

双维度问题,先确定一个维度再确定另外一个维度。

贪心策略:分数较高的比旁边人多1个就好。从左到右遍历一次,从右到左再遍历一次。

9.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int candy(vector<int>& ratings) {
 4         int chCnt=ratings.size();
 5         vector<int> candyVec(chCnt,1);
 6         for(int i=0;i<chCnt;i++){
 7             if(i>0&&ratings[i]>ratings[i-1]){
 8                 candyVec[i]=max(candyVec[i],candyVec[i-1]+1);         
 9             }
10         }
11         for(int i=chCnt-1;i>=0;i--){
12             if(i<(chCnt-1)&&ratings[i]>ratings[i+1]){
13                 candyVec[i]=max(candyVec[i],candyVec[i+1]+1);  
14             }
15         }
16 
17         int canSum=0;
18         for(int& num:candyVec){
19             canSum+=num;
20         }
21         return canSum;
22     }
23 };
View Code
复制代码

 

10.卖货找零

10.1.问题描述

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
注意,一开始你手头没有任何零钱。
给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
链接:https://leetcode.cn/problems/lemonade-change

10.2.要点

贪心策略:尽量用10块1张的找零,尽量少用万能的面值5块。

10.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     bool lemonadeChange(vector<int>& bills) {
 4         int fiveCnt=0,tenCnt=0;
 5         for(int i=0;i<bills.size();i++){
 6             if(bills[i]==5){
 7                 fiveCnt++;
 8                 continue;
 9             }
10             if(bills[i]==10){
11                 if(fiveCnt<=0){
12                     return false;
13                 }
14                 fiveCnt--;
15                 tenCnt++;
16                 continue;
17             }
18             if(bills[i]==20){
19                 //这里涉及贪心策略,优先消耗10美元!
20                 if(tenCnt<=0){
21                     if(fiveCnt<3){
22                         return false;
23                     }
24                     fiveCnt-=3;
25                 }
26                 else{
27                     if(fiveCnt<=0){
28                         return false;
29                     }
30                     fiveCnt--;
31                     tenCnt--;
32                 }
33             }
34         }
35 
36         return true;
37     }
38 };
View Code
复制代码

 

11.根据身高重建队列

11.1.问题描述

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。
请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。
链接:https://leetcode.cn/problems/queue-reconstruction-by-height

11.2.要点

双维度问题,先确定一个维度再确定另外一个维度。

贪心策略:先排队高的人在前,然后让高的里面要求少的人先选。

注意:频繁的插入数据,使用链表以增加性能。

11.3.代码实例

复制代码
 1 // 版本二
 2 class Solution {
 3 public:
 4     // 身高从大到小排(身高相同k小的站前面)
 5     static bool cmp(const vector<int>& a, const vector<int>& b) {
 6         if (a[0] == b[0]) return a[1] < b[1];
 7         return a[0] > b[0];
 8     }
 9     vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
10         sort (people.begin(), people.end(), cmp);
11         list<vector<int>> que;
12         for(int i=0;i<people.size();i++){
13             std::list<vector<int>>::iterator iter=que.begin();
14             int index=people[i][1];
15             while(index--){
16                 iter++;
17             }
18             que.insert(iter,people[i]);
19         }
20 
21         return vector<vector<int>>(que.begin(),que.end());
22     }
23 };
View Code
复制代码

 

12.用最少数量的箭引爆气球

12.1.问题描述

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。
一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。
给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。
链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons

12.2.要点

双维度问题:先确定一个维度,再确定另外一个维度。

贪心策略:萎缩的右边界。

先左边界排序,然后两两比较相邻两个气球。如果有覆盖则以较小值更新右边界,如果没覆盖则加一支箭。

12.3.代码实例

复制代码
 1 class Solution {
 2 private:
 3     static bool cmp(const vector<int>& a, const vector<int>& b) {
 4         return a[0] < b[0];
 5     }
 6 public:
 7     int findMinArrowShots(vector<vector<int>>& points) {
 8         if (points.size() == 0) return 0;
 9         sort(points.begin(), points.end(), cmp);
10 
11         int result = 1; // points 不为空至少需要一支箭
12         for (int i = 1; i < points.size(); i++) {
13             if (points[i][0] > points[i - 1][1]) {  // 下一个气球左边界大于前一个气球的右边界
14                 result++; // 需要一支箭
15             }
16             else {  // 气球i和气球i-1挨着
17                 points[i][1] = min(points[i - 1][1], points[i][1]); // 使用最小右边界
18             }
19         }
20         return result;
21     }
22 };
View Code
复制代码

 

13.无重叠区间

13.1.问题描述

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。
链接:https://leetcode.cn/problems/non-overlapping-intervals

13.2.要点

双维度问题,确定一个再确定另外一个。

贪心策略:先排序左边界,然后记录右边界,右重合则删除、未重合则更新右边界。

13.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     static bool cmp(vector<int> a,vector<int> b){
 4         return a[0]<=b[0];
 5     }
 6     int eraseOverlapIntervals(vector<vector<int>>& intervals) {
 7         int ret=0;
 8         sort(intervals.begin(),intervals.end());
 9 
10         int lastRight=intervals[0][1];
11         for(int i=0;i<intervals.size();i++){
12             //下一个的左边界小于前一个的右边界
13             if(i>0&&intervals[i][0]<lastRight){
14                 ret++;
15                 lastRight=min(intervals[i][1],lastRight);
16             }
17             else{
18                 lastRight=intervals[i][1];
19             }
20         }
21 
22         return ret;
23     }
24 };
View Code
复制代码

 

14.划分字母区间

14.1.问题描述

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
链接:https://leetcode.cn/problems/partition-labels

14.2.要点

记录所有字符最后一次出现的位置。遇到一个字符可知其最后一次出现位置,但不一定是合适的切割位置,因为中间字符有可能使得结束位置更靠后。
所以遍历过程中不停更新right,直到i==right结束这一段。

贪心策略:取得尽量右,包含本字符的所有字符。

14.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     vector<int> partitionLabels(string S) {
 4         int hash[27] = {0}; // i为字符,hash[i]为字符出现的最后位置
 5         for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
 6             hash[S[i] - 'a'] = i;
 7         }
 8         vector<int> result;
 9         int left=0;
10         int right = 0;
11         for (int i = 0; i < S.size(); i++) {
12             right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界
13             
14             //到了指定的位置
15             if(i==right){
16                 result.push_back(right - left + 1);//存储数据
17                 left=right+1;
18             }           
19         }
20         return result;
21     }
22 };
View Code
复制代码

 

15.合并区间

15.1.问题描述

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
链接:https://leetcode.cn/problems/merge-intervals

15.2.要点

贪心策略:增长的右边界。

15.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     static bool cmp(vector<int> a,vector<int> b){
 4         return a[0]<b[0];
 5     }
 6     vector<vector<int>> merge(vector<vector<int>>& intervals) {
 7         sort(intervals.begin(),intervals.end());
 8         vector<vector<int>> ret;
 9         if(intervals.size()==0) return ret;
10 
11         int left=intervals[0][0];
12         int right=intervals[0][1];
13         for(int i=1;i<intervals.size();i++){
14             //未重叠
15             if(intervals[i][0]>right){
16                 ret.push_back(vector<int>{left,right});
17                 left=intervals[i][0];
18                 right=intervals[i][1];
19             }
20             else{
21                 right=max(right,intervals[i][1]);
22             }
23         }
24 
25         //兜住最后一段
26         ret.push_back(vector<int>{left,right});
27 
28         return ret;
29     }
30 };
View Code
复制代码

 

16.单调递增的数字

16.1.问题描述

当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。
给定一个整数 n ,返回 小于或等于 n 的最大数字,且数字呈 单调递增 。
链接:https://leetcode.cn/problems/monotone-increasing-digits

16.2.要点

转为字符串更好处理一些。

贪心策略:找到尽量高的需要修改的位,从它开始后面都换为9.

16.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     int monotoneIncreasingDigits(int N) {
 4         string strNum = to_string(N);
 5         // flag用来标记赋值9从哪里开始
 6         // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
 7         int flag = strNum.size();
 8         for (int i = strNum.size() - 1; i > 0; i--) {
 9             if (strNum[i - 1] > strNum[i] ) {
10                 flag = i;
11                 strNum[i - 1]--;
12             }
13         }
14         for (int i = flag; i < strNum.size(); i++) {
15             strNum[i] = '9';
16         }
17         return stoi(strNum);
18     }
19 };
View Code
复制代码

 

17.买卖股票的最佳时机——含手续费

17.1.问题描述

给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-transaction-fee

17.2.要点

这题还是不要用贪心法来求解,用dp求解会更方便些。

17.3.代码实例

 

18.监控二叉树

18.1.问题描述

给定一个二叉树,我们在树的节点上安装摄像头。

节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。

计算监控树的所有节点所需的最小摄像头数量。

链接:https://leetcode.cn/problems/binary-tree-cameras/submissions/

18.2.要点

贪心策略:查看四周环境,能不放就不放。

定义节点被监控的状态机,按规则判断当前节点是否应该添加监控。

从下向上遍历,因为头结点放不放摄像头也就省下一个摄像头, 叶子节点放不放摄像头省下了的摄像头数量是指数阶别的。因此采用后序遍历。

18.3.代码实例

复制代码
 1 class Solution {
 2 public:
 3     const int unCover=1,covered=2,hasMon=3;
 4     int ret=0;
 5     int recurve(TreeNode* root){
 6         if(root==NULL){
 7             return covered;
 8         }
 9 
10         //后序遍历
11         int left=recurve(root->left);
12         int right=recurve(root->right);
13 
14         //左右存在未覆盖,此处必须添加
15         if(left==unCover||right==unCover){
16             ret++;
17             return hasMon;
18         }
19 
20         //左右都是已覆盖状态,此处可以暂时是未覆盖状态
21         if(left==covered&&right==covered){
22             return unCover;
23         }
24 
25         //左右节点存在至少一个摄像头,根节点处于被覆盖状态
26         return covered;
27     }
28 
29     int minCameraCover(TreeNode* root) {
30         if(root==NULL){
31             return 0;
32         }
33         if(recurve(root)==unCover){
34             ret++;
35         }        
36         
37         return ret;
38     }
39 };
View Code
复制代码

 

 

xxx.问题

xxx.1.问题描述

111

xxx.2.要点

222

xxx.3.代码实例

333

本文作者:OhOfCourse

本文链接:https://www.cnblogs.com/OhOfCourse/p/17004480.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   啊原来是这样呀  阅读(27)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起