738.单调递增的数字
贪心解题思路:
如果从前向后遍历的话,修改了的数值可能又会大于前面的数值。因此从后向前遍历,定义标记变量flag找到非递增的最靠前位置,将nums[i]--,i之后的数都设为9即可。
public int monotoneIncreasingDigits(int n) {
String s = String.valueOf(n);
char[] ss = s.toCharArray();
int flag = ss.length;
for (int i = 0; i <ss.length-1; i++) {
//如果这里不递增,将ss[i]-1,记录i+1的位置
//遍历结束后,flag为不递增序列开始的起始位置
if (ss[i] > ss[i + 1] || (ss[i]==ss[i+1]&&ss[i+1]>ss[i+2])) {
while (ss[i]==ss[i+1]&&ss[i+1]>ss[i+2]){
i++;
}
ss[i]--;
flag=i+1;
break;
}
}
//flag之后的都变成9
for (int i = flag; i < ss.length; i++) {
ss[i] = '9';
}
return Integer.parseInt(String.valueOf(ss));
}
714. 买卖股票的最佳时机含手续费
其实理解的还不是很透彻,尤其最后一步更新min的值
贪心解题思路:
本题不用纠结是哪一天买入买出,只要卖-买-利润>0,记录到sum中即可。
定义买入变量min的初值为price[0],遍历数组,当当前元素小于min时更新min的值。
当price[i]-min-fee<0,不做任何操作,continue。
当price[i]-min-fee>0,则将差值添加到结果集中。此时并不一定是真正卖出,只是更新了利润值。若后面有更小的min值才是真正意义是卖出。将price[i]-fee赋值给min,如果当前不是最后一次卖出的话,就把当前减去的min加上(price[i]-(min)-fee)。若后面卖出的利润大于当前price[i]-fee,则从后面卖出。
public int maxProfit(int[] prices, int fee) {
int min=prices[0];
int sum=0;
for(int i=1;i<prices.length;i++){
if(prices[i]<min){
min=prices[i];
}
if(prices[i]>min&&prices[i]<=min+fee){
continue;
}
if(prices[i]>min+fee){
sum+=prices[i]-min-fee;
min=prices[i]-fee;
}
}
return sum;
}
968.监控二叉树
这道题,看着就没思路,但是看了题解感觉还好,自己写出来代码了,嘿嘿。
首先,明确:叶子节点不能放摄像头,根节点可以有摄像头。
为什么不从根节点看起?
因为叶子节点可以有很多个,根节点只有一个。叶子节点放的摄像头指数级增长。
因此采用后序遍历,设置三个标记,0代表无覆盖,1代表有摄像头,2代表有覆盖。
首先,当遍历到空节点时,标记为2(为了让叶子结点无覆盖)
然后会有以下三种情况:
①左右孩子有一个无覆盖0:res++,此处父节点为1放置摄像头
②左右孩子都有覆盖2:此处父节点设置为无覆盖0(当左右孩子都为null标记为2,叶子结点就为0)
③左右孩子有一个为摄像头1:此处父节点为有覆盖2。
最后遍历结束时,判断返回值是否为0,若为0则代表根节点无覆盖需要添加摄像头,res++即可。
class Solution {
int res;
public int minCameraCover(TreeNode root) {
if(traversal(root)==0){
res++;
}
return res;
}
public int traversal(TreeNode root) {
// 0无覆盖 1有摄像头 2有覆盖
if(root==null){return 2;}
int left=traversal(root.left);
int right=traversal(root.right);
if(left==2&&right==2){return 0;}
if(left==0||right==0){
res++;
return 1;
}
if(left==1||right==1){
return 2;
}
return -1;
}
}