606. 根据二叉树创建字符串
2022.3.19 每日一题
题目描述
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 “()” 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
示例 1:
输入: 二叉树: [1,2,3,4]
1
/ \
2 3
/
4
输出: "1(2(4))(3)"
解释: 原本将是“1(2(4)())(3())”,
在你省略所有不必要的空括号对之后,
它将是“1(2(4))(3)”。
示例 2:
输入: 二叉树: [1,2,3,null,4]
1
/ \
2 3
\
4
输出: "1(2()(4))(3)"
解释: 和第一个示例相似,
除了我们不能省略第一个对括号来中断输入和输出之间的一对一映射关系。
思路
注意到左边括号不能删除,防止歧义
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
StringBuffer res = new StringBuffer();
public String tree2str(TreeNode root) {
//意思是左边括号不能删,因为可能会影响判断,右边括号可以删
preOrder(root);
return res.toString();
}
public void preOrder(TreeNode root){
if(root == null)
return;
res.append(root.val);
//如果没有子节点了直接返回
if(root.left == null && root.right == null)
return;
res.append("(");
preOrder(root.left);
res.append(")");
//如果右节点为空,直接返回
if(root.right == null)
return;
res.append("(");
preOrder(root.right);
res.append(")");
}
}
迭代
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public String tree2str(TreeNode root) {
//写个迭代
StringBuffer res = new StringBuffer();
Deque<TreeNode> stack = new LinkedList<>();
Set<TreeNode> set = new HashSet<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
//如果添加过这个节点,说明第二次遍历了,那么加结束符
if(set.contains(node)){
res.append(")");
//如果是第一次遍历
}else{
stack.push(node);
res.append("(");
res.append(node.val);
if(node.right != null)
stack.push(node.right);
if(node.left != null)
stack.push(node.left);
//如果left为空,但是right不为空,那么加括号
else if(node.right != null)
res.append("()");
set.add(node);
}
}
return res.substring(1, res.length() - 1).toString();
}
}
2039. 网络空闲的时刻
2022.3.20 每日一题
题目描述
给你一个有 n 个服务器的计算机网络,服务器编号为 0 到 n - 1 。同时给你一个二维整数数组 edges ,其中 edges[i] = [ui, vi] 表示服务器 ui 和 vi 之间有一条信息线路,在 一秒 内它们之间可以传输 任意 数目的信息。再给你一个长度为 n 且下标从 0 开始的整数数组 patience 。
题目保证所有服务器都是 相通 的,也就是说一个信息从任意服务器出发,都可以通过这些信息线路直接或间接地到达任何其他服务器。
编号为 0 的服务器是 主 服务器,其他服务器为 数据 服务器。每个数据服务器都要向主服务器发送信息,并等待回复。信息在服务器之间按 最优 线路传输,也就是说每个信息都会以 最少时间 到达主服务器。主服务器会处理 所有 新到达的信息并 立即 按照每条信息来时的路线 反方向 发送回复信息。
在 0 秒的开始,所有数据服务器都会发送各自需要处理的信息。从第 1 秒开始,每 一秒最 开始 时,每个数据服务器都会检查它是否收到了主服务器的回复信息(包括新发出信息的回复信息):
- 如果还没收到任何回复信息,那么该服务器会周期性 重发 信息。数据服务器 i 每 patience[i] 秒都会重发一条信息,也就是说,数据服务器 i 在上一次发送信息给主服务器后的 patience[i] 秒 后 会重发一条信息给主服务器。
- 否则,该数据服务器 不会重发 信息。
当没有任何信息在线路上传输或者到达某服务器时,该计算机网络变为 空闲 状态。
请返回计算机网络变为 空闲 状态的 最早秒数 。
示例 1:
示例 2:
提示:
思路
先存图,然后计算每个服务器与主服务器的距离,然后根据这些距离计算时间
class Solution {
public int networkBecomesIdle(int[][] edges, int[] patience) {
//因为两个服务器之间一秒内可以传输任意数目的信息,
//所以说关键还是找到任意服务器与主服务器之间的距离,然后根据重发的信息就可以确定每个服务器所需要的时间
//然后找到最长时间就可以了
//所以可以直接从主服务器开始扩散,然后记录每个服务器与主服务器之间的距离
Map<Integer, Set<Integer>> map = new HashMap<>();
for(int[] e : edges){
int a = e[0];
int b = e[1];
Set<Integer> set1 = map.getOrDefault(a, new HashSet<>());
Set<Integer> set2 = map.getOrDefault(b, new HashSet<>());
set1.add(b);
set2.add(a);
map.put(a, set1);
map.put(b, set2);
}
//然后广度优先所有,记录每个位置与0的距离
int n = patience.length;
int[] distance = new int[n];
Arrays.fill(distance, -1);
distance[0] = 0;
Queue<Integer> queue = new LinkedList<>();
queue.offer(0);
int dis = 0;
while(!queue.isEmpty()){
int size = queue.size();
dis++;
while(size -- > 0){
int top = queue.poll();
Set<Integer> set = map.get(top);
for(int p : set){
//如果没有到达过,说明是第一次,那么更新距离
if(distance[p] == -1){
distance[p] = dis;
queue.offer(p);
}
}
}
}
//记录了每个点的距离以后,计算每个点传输需要的时间
//首先,传输来回,需要 2*d 的时间
//而在这个时间内,每个p又重新发送一次,也就是要发送 (2*d - 1) / p次,最后一次发送是在(2*d - 1) / p * p这个时间
//所以最终时间就是这个时间加上2*d时间
int max = 0;
for(int i = 1; i < n; i++){
int d = distance[i];
//System.out.println(d);
int t = 2 * d;
//发送了多少次
int time = (2 * d - 1) / patience[i];
int last = time * patience[i]; //最后一次发送的时间
int f = last + t;
max = Math.max(f, max);
}
return max + 1;
}
}
653. 两数之和 IV - 输入 BST
2022.3.21 每日一题
题目描述
给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
示例 1:
示例 2:
提示:
思路
纯纯两数之和
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
Set<Integer> set = new HashSet<>();
public boolean findTarget(TreeNode root, int k) {
//就是两数之和呗
if(root == null)
return false;
if(set.contains(k - root.val))
return true;
set.add(root.val);
return findTarget(root.left, k) || findTarget(root.right, k);
}
}
利用二叉搜索树的性质,左中右从小到大,右中左从大到小
双指针搞定
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean findTarget(TreeNode root, int k) {
//利用bst的性质,也就是中序遍历是递增的,所以一个从左中右递增,一个右中左递减
Stack<TreeNode> ls = new Stack<>();
Stack<TreeNode> rs = new Stack<>();
TreeNode lnode = root;
TreeNode rnode = root;
ls.push(lnode);
rs.push(rnode);
//先一直向左,把最小值找出来
while(lnode.left != null){
ls.push(lnode.left);
lnode = lnode.left;
}
while(rnode.right != null){
rs.push(rnode.right);
rnode = rnode.right;
}
while(lnode != rnode){
if(lnode.val + rnode.val == k)
return true;
if(lnode.val + rnode.val < k){
lnode = findLeft(ls);
}else{
rnode = findRight(rs);
}
}
return false;
}
public TreeNode findLeft(Stack<TreeNode> s){
TreeNode temp = s.pop();
TreeNode node = temp.right;
while(node != null){
s.push(node);
node = node.left;
}
return temp;
}
public TreeNode findRight(Stack<TreeNode> s){
TreeNode temp = s.pop();
TreeNode node = temp.left;
while(node != null){
s.push(node);
node = node.right;
}
return temp;
}
}