代码随想录算法训练营第37天 | 738.单调递增的数字 968.监控二叉树

单调递增的数字

Alt
这道题思路挺巧妙的。举个例子,332这个数,会出现strNum[i - 1] > str[i]这种非单调递增的情况,这时需要将strNum[i - 1]--,然后给strNum[i]赋值9,这样既保证了两位数字之间的递增关系,同时也使得数字减小的最少。

  • 最后的问题就是处理的方向,如果从前向后遍历,其实并不能维持单调递增的性质(举例模拟一下可知),没法利用之前的比较结果。所以需要从后向前遍历。
  • 另外就是该给哪些位赋9,一旦某一位需要被赋值为9,那这一位后面都应该被赋值9,因为要保证这个数要小于等于原来的数。
class Solution{
public:
	int monotoneIncreasingDigits(int n){
		string strNum = to_string(n);
		int flag = strNum.size();  // 确定从哪一位开始被赋值为9,赋初始值,避免循环出错
		for(int i = strNum.size() - 1; i > 0; i--){
			if(strNum[i - 1] > strNum[i]){
				// 出现了非单调递增的情况
				strNum[i - 1]--;
				flag = i; // 第i位应该赋值为9
			}
		}
		for(int i = flag; i < strNum.size(); i++){
			strNum[i] = '9';
		}
		return stoi(strNum);
	}
};

监控二叉树

Alt
一个摄像头可以覆盖上中下三层,如果摄像头放在叶子节点上就损失了一层覆盖,所以将摄像头放在叶子节点的父节点位置,才能充分利用摄像头的覆盖面积。
所以我们要从树的底层开始向上遍历,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少。整体最优:所用的全部摄像头数目最少。
具体到实现上:

  1. 二叉树的遍历
  2. 每隔两个节点放一个摄像头

这里从底层开始,需要后序遍历。那么如何每隔两个节点放一个摄像头,这里利用状态转移的方法。每一个节点都有一个对应的状态,是 “0-无覆盖;1-有摄像头;2-有覆盖” 三种之一。
那么空节点的状态应该是什么呢?如果赋值为0,那么叶子节点就需要放摄像头,这不符我们的要求;如果赋值为1,那么下一个摄像头应该放在叶子节点的爷爷节点,这也不对。所以只能给空节点赋值为2,叶子节点的父节点是需要摄像头的,合理!
另外还有一个最终的头结点问题,如果覆盖了或者有摄像头还好,但如果没覆盖,就需要一个摄像头。

class Solution{
public:
	int result = 0;
	int traversal(TreeNode* cur){
		if(cur == nullptr)  return 2;
		int left = traversal(cur->left);
		int right = traversal(cur->right);
		if(left == 0 || right == 0){  // 如果左右节点中有没覆盖的,所以当前的节点应该安摄像头
			result++;
			return 1;		
		}
		if(left == 1 || right == 1){  // 如果左右节点中有摄像头,那么当前的节点应该有覆盖
			return 2;
		}
		if(left == 2 && right == 2){
			return 0;
		}
		return -1;
	}
	int minCameraCover(TreeNode* root){
		if(traversal(root) == 0){
			result++;  // 如果头节点没有被覆盖,摄像头的数目应该+1
		}
		return result;
	}
};
  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值