网站程序如何制作,大学里读网站建设,asp是网站开发吗,QQ点钓鱼网站后怎么做738 单调递增的数字#xff08;medium#xff09;
当且仅当每个相邻位数上的数字 x 和 y 满足 x y 时#xff0c;我们称这个整数是单调递增的。
给定一个整数 n #xff0c;返回 小于或等于 n 的最大数字#xff0c;且数字呈 单调递增 。
思路#xff1a;将整数转…738 单调递增的数字medium
当且仅当每个相邻位数上的数字 x 和 y 满足 x y 时我们称这个整数是单调递增的。
给定一个整数 n 返回 小于或等于 n 的最大数字且数字呈 单调递增 。
思路将整数转为字符串然后从后往前遍历按照逻辑进行处理最后再转回数字即可
题目要求小于等于N的最大单调递增的整数那么拿一个两位的数字来举例。
例如98一旦出现strNum[i - 1] strNum[i]的情况非单调递增首先想让strNum[i - 1]–然后strNum[i]给为9这样这个整数就是89即小于98的最大的单调递增整数。
这一点如果想清楚了这道题就好办了。
此时是从前向后遍历还是从后向前遍历呢 从前向后遍历的话遇到strNum[i - 1] strNum[i]的情况让strNum[i - 1]减一但此时如果strNum[i - 1]减一了可能又小于strNum[i - 2]。 这么说有点抽象举个例子数字332从前向后遍历的话那么就把变成了329此时2又小于了第一位的3了真正的结果应该是299。 那么从后向前遍历就可以重复利用上次比较得出的结果了从后向前遍历332的数值变化为332 - 329 - 299
确定了遍历顺序之后那么此时局部最优就可以推出全局找不出反例试试贪心。
C库函数to_string/stoi
代码实现
class Solution {
public:int monotoneIncreasingDigits(int N) {string strNum to_string(N);// flag用来标记赋值9从哪里开始// 设置为这个默认值为了防止第二个for循环在flag没有被赋值的情况下执行int flag strNum.size();for (int i strNum.size() - 1; i 0; i--) {if (strNum[i - 1] strNum[i] ) {flag i;strNum[i - 1]--;}}for (int i flag; i strNum.size(); i) {strNum[i] 9;}return stoi(strNum);}
};时间复杂度O(n)n 为数字长度空间复杂度O(n)需要一个字符串转化为字符串操作更方便
详细解析 思路视频 代码实现文章 968 监控二叉树hard
给定一个二叉树我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
思路理清楚状态转移关系分类讨论使用后序遍历
这道题目首先要想如何放置才能让摄像头最小的呢
从题目中示例其实可以得到启发我们发现题目示例中的摄像头都没有放在叶子节点上
这是很重要的一个线索摄像头可以覆盖上中下三层如果把摄像头放在叶子节点上就浪费的一层的覆盖。
所以把摄像头放在叶子节点的父节点位置才能充分利用摄像头的覆盖面积。
那为什么不从头结点开始看起呢为啥要从叶子节点看呢
因为头结点放不放摄像头也就省下一个摄像头 叶子节点放不放摄像头省下了的摄像头数量是指数阶别的。
所以我们要从下往上看
局部最优让叶子节点的父节点安摄像头所用摄像头最少整体最优全部摄像头数量所用最少
局部最优推出全局最优找不出反例那么就按照贪心来
此时大体思路就是从低到上先给叶子节点父节点放个摄像头然后隔两个节点放一个摄像头直至到二叉树头结点。
此时这道题目还有两个难点
二叉树的遍历如何隔两个节点放一个摄像头
确定遍历顺序
在二叉树中如何从低向上推导呢
可以使用后序遍历也就是左右中的顺序这样就可以在回溯的过程中从下到上进行推导了。
后序遍历代码如下
int traversal(TreeNode* cur) {// 空节点该节点有覆盖if (终止条件) return ;int left traversal(cur-left); // 左int right traversal(cur-right); // 右逻辑处理 // 中return ;
}注意在以上代码中我们取了左孩子的返回值右孩子的返回值即left 和 right 以后推导中间节点的状态
如何隔两个节点放一个摄像头
此时需要状态转移的公式不过本题状态转移没有择优的过程就是单纯的状态转移
来看看这个状态应该如何转移先来看看每个节点可能有几种状态
有如下三种
该节点无覆盖本节点有摄像头本节点有覆盖
我们分别有三个数字来表示
0该节点无覆盖 1本节点有摄像头 2本节点有覆盖 大家应该找不出第四个节点的状态了。
可能会想有没有第四种状态本节点无摄像头其实无摄像头就是 无覆盖 或者 有覆盖的状态所以一共还是三个状态。
因为在遍历树的过程中就会遇到空节点那么问题来了空节点究竟是哪一种状态呢 空节点表示无覆盖 表示有摄像头还是有覆盖呢
回归本质为了让摄像头数量最少我们要尽量让叶子节点的父节点安装摄像头这样才能摄像头的数量最少。
那么空节点不能是无覆盖的状态这样叶子节点就要放摄像头了空节点也不能是有摄像头的状态这样叶子节点的父节点就没有必要放摄像头了而是可以把摄像头放在叶子节点的爷爷节点上。
所以空节点的状态只能是有覆盖这样就可以在叶子节点的父节点放摄像头了
接下来就是递推关系。
那么递归的终止条件应该是遇到了空节点此时应该返回2有覆盖原因上面已经解释过了。
代码如下
// 空节点该节点有覆盖
if (cur NULL) return 2;递归的函数以及终止条件已经确定了再来看单层逻辑处理。
主要有如下四类情况
情况1左右节点都有覆盖
左孩子有覆盖右孩子有覆盖那么此时中间节点应该就是无覆盖的状态了。 代码如下
// 左右节点都有覆盖
if (left 2 right 2) return 0;情况2左右节点至少有一个无覆盖的情况
如果是以下情况则中间节点父节点应该放摄像头
left 0 right 0 左右节点无覆盖 left 1 right 0 左节点有摄像头右节点无覆盖 left 0 right 1 左节点有无覆盖右节点摄像头 left 0 right 2 左节点无覆盖右节点覆盖 left 2 right 0 左节点覆盖右节点无覆盖 这个不难理解毕竟有一个孩子没有覆盖父节点就应该放摄像头。
此时摄像头的数量要加一并且return 1代表中间节点放摄像头。
代码如下
if (left 0 || right 0) {result;return 1;
}情况3左右节点至少有一个有摄像头
如果是以下情况其实就是 左右孩子节点有一个有摄像头了那么其父节点就应该是2覆盖的状态
left 1 right 2 左节点有摄像头右节点有覆盖 left 2 right 1 左节点有覆盖右节点有摄像头 left 1 right 1 左右节点都有摄像头
代码如下
if (left 1 || right 1) return 2;从这个代码中可以看出如果left 1, right 0 怎么办其实这种条件在情况2中已经判断过了如图 情况4头结点没有覆盖
以上都处理完了递归结束之后可能头结点 还有一个无覆盖的情况如图 所以递归结束之后还要判断根节点如果没有覆盖result代码如下
int minCameraCover(TreeNode* root) {result 0;if (traversal(root) 0) { // root 无覆盖result;}return result;
}代码实现
class Solution {
private:int result;int traversal(TreeNode* cur) {// 空节点该节点有覆盖if (cur NULL) return 2;int left traversal(cur-left); // 左int right traversal(cur-right); // 右// 情况1// 左右节点都有覆盖if (left 2 right 2) return 0;// 情况2// left 0 right 0 左右节点无覆盖// left 1 right 0 左节点有摄像头右节点无覆盖// left 0 right 1 左节点有无覆盖右节点摄像头// left 0 right 2 左节点无覆盖右节点覆盖// left 2 right 0 左节点覆盖右节点无覆盖if (left 0 || right 0) {result;return 1;}// 情况3// left 1 right 2 左节点有摄像头右节点有覆盖// left 2 right 1 左节点有覆盖右节点有摄像头// left 1 right 1 左右节点都有摄像头// 其他情况前段代码均已覆盖if (left 1 || right 1) return 2;// 以上代码我没有使用else主要是为了把各个分支条件展现出来这样代码有助于读者理解// 这个 return -1 逻辑不会走到这里。return -1;}public:int minCameraCover(TreeNode* root) {result 0;// 情况4if (traversal(root) 0) { // root 无覆盖result;}return result;}
};
在以上代码的基础上再进行精简代码如下// 版本二
class Solution {
private:int result;int traversal(TreeNode* cur) {if (cur NULL) return 2;int left traversal(cur-left); // 左int right traversal(cur-right); // 右if (left 2 right 2) return 0;else if (left 0 || right 0) {result;return 1;} else return 2;}
public:int minCameraCover(TreeNode* root) {result 0;if (traversal(root) 0) { // root 无覆盖result;}return result;}
};时间复杂度: O(n)需要遍历二叉树上的每个节点空间复杂度: O(n)
详细解析 思路视频 代码实现文章