2021.5.24 每日一题,又开始新的一周了
有台奇怪的打印机有以下两个特殊要求:
打印机每次只能打印由 同一个字符 组成的序列。
每次可以在任意起始和结束位置打印新字符,并且会覆盖掉原来已有的字符。
给你一个字符串 s ,你的任务是计算这个打印机打印它需要的最少打印次数。
示例 1:
输入:s = "aaabbb"
输出:2
解释:首先打印 "aaa" 然后打印 "bbb"。
示例 2:
输入:s = "aba"
输出:2
解释:首先打印 "aaa" 然后在第二个位置打印 "b" 覆盖掉原来的字符 'a'。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/strange-printer
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这个动态规划没想出来,刚开始也没往这边想,想的是有什么技巧(每次都打印整个剩余长度的字符串)
定义dp[i][j]表示打印i到j最少需要多少次
如果s[i] = s[j], dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]),打印i的同时打印j,不需要额外再打印一次
如果不相同,那么两边需要分别打印,也就是将区间分成两部分[i,k][k + 1, j],然后计算各个k的最小值
那遍历顺序呢,dp[i][j]和dp[i+][j] 和dp[i][j-]有关,因此i从大到小,j从小到大
class Solution {
public int strangePrinter(String s) {
//怎么看不懂这个题啊,啥意思,大概明白了,就是每次打印字符的数量是随意的
//不过只能从开始和结尾打印,并且打印只能由同一个字符组成
//感觉这题说的也不严谨,如果打印了与开头末尾相同的字符,那么下次打印是从下一个字符开始还是覆盖以后的地方开始
//应该是覆盖到哪就从哪里开始
//动态规划,dp表示打印i到j最少需要多少次
int l = s.length();
int[][] dp = new int[l][l];
//初始化
for(int i = 0; i < l; i++){
dp[i][i] = 1;
}
char[] ss = s.toCharArray();
//如果s[i] = s[j], dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]),打印i的同时打印j
//如果不相同,那么两边需要分别打印,也就是将区间分成两部分[i,k][k + 1, j],然后计算各个k的最小值
//那遍历顺序呢,dp[i][j]和dp[i+][j] 和dp[i][j-]有关,因此i从大到小,j从小到大
for(int i = l - 2; i >= 0; i--){
for(int j = i + 1; j < l; j++){
if(ss[i] == ss[j]){
dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]);
}else{
dp[i][j] = 100; //字符串最长100
for(int k = i; k < j; k++){
dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
}
return dp[0][l - 1];
}
}
输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
层序遍历
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
//层序遍历吧
int k = 0;
Queue<TreeNode> queue = new LinkedList<>();
if(root != null)
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
while(size > 0){
TreeNode node = queue.poll();
if(node.left != null)
queue.offer(node.left);
if(node.right != null)
queue.offer(node.right);
size--;
}
k++;
}
return k;
}
}
递归,当前子树的深度,就等于左子树深度与右子树深度的较大值加1
class Solution {
public int maxDepth(TreeNode root) {
//再写个递归的
if(root == null)
return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
做了上一题,这个题有个很容易想到的思路就是判断每个子树是否是平衡二叉树,即判断每个子树的左右子树高度之差是否小于等于1,但是这样会重复遍历遍历多次单个节点,因此想更加优化的方法
就是从底部到顶部计算高度,采用后序遍历,先从底部节点开始判断是否是一颗平衡二叉树,如果是,就返回当前子树的高度,也就是左右子树高度的较大值加1,如果不是返回-1;并且加入剪枝,即如果已经判断到一个子树不是平衡二叉树了,就直接返回-1
class Solution {
public boolean isBalanced(TreeNode root) {
//是一个平衡二叉树要求当前结点的左右子树高度之差,不能大于1;同时子树也要求是平衡二叉树
return helper(root) >= 0;
}
public int helper(TreeNode root){
if(root == null)
return 0;
int left = helper(root.left);
int right = helper(root.right);
//如果左右子树有一个不是平衡二叉树,就不行
if(left == -1 || right == -1)
return -1;
//如果左右子树高度相差小于等于1,那么当前高度就是左右子树高度+1
if(Math.abs(left - right) <= 1)
return Math.max(left, right) + 1;
return -1;
}
}