738.单调递增的数字
题目:738. 单调递增的数字 - 力扣(LeetCode)
思路:感觉不难,就是把数字先按照位数取出来,再进行比较,不行就递减,每次检查一下是不是单调递增,暴力算法可能会比较耗时,应该是有技巧可以某些数字不检查的,尬住了,我不知道怎么取出来数字
我想到了,找到数组中最大的数字,把这个数字之后的数字都变成9,比如说6711,7最大,我就把11都变成1,7减去1,也就是6699
尝试(部分AC但是超出时间限制)
class Solution {
public int monotoneIncreasingDigits(int n) {
while(isValid(n) != true){
n--;
}
return n;
}
public boolean isValid(int n){
//取出每个数字
int length = 0;
int temp = n;
while (temp > 0) {
length++;
temp /= 10; // 移动到下一个数字
}
int[] digits = new int[length];
for (int i = length - 1; i >= 0; i--) {
digits[i] = n % 10; // 获取当前最低位的数字
n /= 10; // 移动到下一个数字
}
//判断数字是否递增,不是则返回false
for(int i = 1; i<length ; i++){
if(digits[i]<digits[i-1]) return false;
}
//返回false
return true;
}
}
第二次尝试
先找到最大的数字所在的下标,把改数字减1,再把后面的数字变成9,我的思路接近答案,但是还是不行,比如【7,1,1,9】的情况
class Solution {
public static int max = 0;
public static int minIndex = 0;
public int monotoneIncreasingDigits(int n) {
int length = 0;
int temp = n;
while (temp > 0) {
length++;
temp /= 10; // 移动到下一个数字
}
int[] digits = new int[length];
for (int i = length - 1; i >= 0; i--) {
digits[i] = n % 10; // 获取当前最低位的数字
n /= 10; // 移动到下一个数字
}
//找到
for(int i = 0; i < length; i++){
if(digits[i] > max){
max = digits[i];
minIndex = Math.min(minIndex,i);
}
}
int result = 0;
digits[minIndex] = digits[minIndex] -1;
for(int i = minIndex; i < length-1; i++){
digits[i] = 9;
}
for (int digit : digits) {
result = result * 10 + digit;
}
return result;
}
}
答案
class Solution {
public int monotoneIncreasingDigits(int n) {
String s = String.valueOf(n);
char[] chars = s.toCharArray();
int start = s.length();
for (int i = s.length() - 2; i >= 0; i--) {
if (chars[i] > chars[i + 1]) {
chars[i]--;
start = i+1;
}
}
for (int i = start; i < s.length(); i++) {
chars[i] = '9';
}
return Integer.parseInt(String.valueOf(chars));
}
}
小结
- 从后向前遍历,一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]减一,strNum[i]赋值9
- 只需要先通过【valueOf】把数字转换为字符串,再用【toCharArray】把字符串转换为字符数组就行
968.监控二叉树
思路:首先我不知道怎么判断一个节点能当作监控节点,监控节点的作用就是能够连接到周围一步范围的节点,我需要找到能够到达所有节点的最少所需监控节点,目前的一个思路就是,采用层序遍历,记录所有节点能够到达的节点数量,我只知道这个思路,得到这个数组之后,要怎么挑出监控节点就不会了
尝试(部分AC)
class Solution {
public int minCameraCover(TreeNode root) {
int result =0;
int nodeNum = 0;
List<List<Integer>> resList = new ArrayList<List<Integer>>();
Queue<TreeNode> que = new LinkedList<TreeNode>();
que.offer(root);
while(!que.isEmpty()){
List<Integer> itemList = new ArrayList<Integer>();
int len = que.size();
while(len>0){
// 记录节点个数
nodeNum += len;
TreeNode temp = que.poll();
int count =0;
if(temp.left != null){
que.offer(temp.left);
count++;
};
if(temp.right != null){
que.offer(temp.right);
count++;
};
itemList.add(count);
len--;
}
resList.add(itemList);
}
// 遍历itemlist,把元素从大到小加起来,一旦加起来之后等于节点个数,就返回当前收集到的元素个数
return result;
}
}
答案
class Solution {
static int ans;
public int minCameraCover(TreeNode root) {
ans = 0; // 初始化
if(f(root) == 0) ans ++;
return ans;
}
// 定义 f 函数有三种返回值情况
// 0:表示 x 节点没有被相机监控,只能依靠父节点放相机
// 1:表示 x 节点被相机监控,但相机不是放在自身节点上
// 2:表示 x 节点被相机监控,但相机放在自身节点上
public static int f(TreeNode x) {
if(x == null) return 1; // 空树认为被监控,但没有相机
// 左右递归到最深处
int l = f(x.left);
int r = f(x.right);
// 有任意一个子节点为空,就需要当前节点放相机,不然以后没机会
if(l == 0 || r == 0) {
ans ++; // 放相机
return 2;
}
// 贪心策略,左右子树都被监控,且没有监控到当前节点,
// 那么最有利的情况就是将相机放置在当前节点父节点上,
// 因为这样能多监控可能的子树节点和父父节点
if(l == 1 && r == 1) return 0;
// 剩下情况就是左右子树有可能为 2,即当前节点被监控
return 1;
}
}
小结
- 首先,要从下往上遍历,也就是后序遍历
- 其次,要搞清楚节点有几种状态,根据子节点的状态来判断摄像头的数量是否需要增加
- 三种状态,被监控(带相机),被监控(无相机),无监控
- 左右孩子存在一个是无监控,当前节点就要加上监控,返回状态【被监控(带相机)】;左右节点都被监控,当前节点就不加监控,返回状态【无监控】;其它情况下,返回状态【被监控(无相机)】