738.单调递增的数字*
代码
示例代码
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); } };
思路
-
将整数转换成字符串:首先,这个解决方案将输入的整数
N
转换成字符串strNum
。这样做的好处是可以很容易地访问和修改数字的每一位。 -
初始化标记位:接着,定义了一个整数变量
flag
作为标记位,用来记录从哪一位开始将后面的所有数字赋值为 9。初始时,flag
被设置为strNum.size()
,即字符串的长度,这是为了处理一些特殊情况,确保即使没有位需要修改,第二个循环也不会执行任何操作。 -
从后向前遍历数字:然后,使用一个 for 循环从后向前遍历字符串中的数字,即从最低位到最高位。这个过程中,如果发现当前位的数字小于它前一位的数字(即,
strNum[i - 1] > strNum[i]
),就将前一位的数字减 1(strNum[i - 1]--
),并将标记位flag
更新为当前位置i
。这个步骤是贪心算法的关键,它确保了减小的数字尽可能地小,而且只修改必要的位。 -
修改标记位之后的数字:第一个循环完成后,第二个 for 循环从标记位
flag
开始,将这一位及其后面的所有数字赋值为 9。这样做是为了保证结果是单调递增的,并且尽可能大。 -
将修改后的字符串转换回整数并返回:最后,使用
stoi(strNum)
将修改后的字符串转换回整数,并将其作为结果返回。
968.监控二叉树*
代码
示例代码
// 版本一 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; // 情况4 if (traversal(root) == 0) { // root 无覆盖 result++; } return result; } };
思路
此时,大体思路就是从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。