一、leetcode题目
1.从先序遍历还原二叉树
题目描述
我们从二叉树的根节点 root
开始进行深度优先搜索。
在遍历中的每个节点处,我们输出 D
条短划线(其中 D
是该节点的深度),然后输出该节点的值。(如果节点的深度为 D
,则其直接子节点的深度为 D + 1
。根节点的深度为 0
)。
如果节点只有一个子节点,那么保证该子节点为左子节点。
给出遍历输出 S
,还原树并返回其根节点 root
。
(1)测试用例
输入:
- “1-2- -3- -4-5- -6- -7”
- “1-2- -3- - -4-5- -6- - -7”
- “1-401- -349- - -90- -88”
输出:
- [1,2,5,3,4,6,7]
- [1,2,5,3,null,6,null,4,null,7]
- [1,401,null,349,88,90]
解释:
提示
- 原始树中的节点数介于 1 和 1000 之间。
- 每个节点的值介于 1 1 1 和 1 0 9 10 ^ 9 109 之间。
(2)思路
第一时间想到的是不用技巧,纯模拟,不过模拟算法也写的够呛。
(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 {
String s;
public TreeNode recoverFromPreorder(String traversal) {
// 因为递归函数的写法限制,对于第一个值需要特殊处理(第一个值前面没有‘-’符号)
if(traversal == "") reutnr null;
int i = 0;
while(i < traversal.length() && isNumber(traversal.charAt(i))) i++;
TreeNode root = new TreeNode(Integer.parseInt(traversal.substring(0, i)));
s = traversal.substring(i, traversal.length());
root.left = dfs(1);
root.right = dfs(1);
return root;
}
// 递归函数,在题目中,需要对深度有要求,所以必须要把深度作为参数传递进去。
public TreeNode dfs(int depth){
if(s == "") return null;
int i = 0;
while(i < s.length() && isSymbol(s.charAt(i))) i++;
if(i != depth) return null;
int j = i + 1;
while(j < s.length() && isNumber(s.charAt(j))) j++;
TreeNode node = new TreeNode(Integer.parseInt(s.substring(i, j)));
s = s.substring(j, s.length());
node.left = dfs(depth + 1);
node.right = dfs(depth + 1);
return node;
}
// 判断是否为符号。
private boolean isSymbol(char c){
return c == '-';
}
// 判断是否为数字
private boolean isNumber(char c){
if('0' <= c && c <= '9') return true;
return false;
}
}
2.乘积为正数的最长子数组长度
题目描述
给你一个整数数组 nums
,请你求出乘积为正数的最长子数组的长度。
一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。
请你返回乘积为正数的最长子数组长度。
(1)测试用例
输入:
nums = [1,-2,-3,4]
nums = [0,1,-2,-3,-4]
nums = [-1,-2,-3,0,1]
输出:
4
3
2
解释:
数组本身乘积就是正数,值为 24 。
最长乘积为正数的子数组为 [1,-2,-3] ,乘积为 6 。注意,我们不能把 0 也包括到子数组中,因为这样乘积为 0 ,不是正数。
乘积为正数的最长子数组是 [-1,-2] 或者 [-2,-3] 。
解释:
- 1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
- − 1 0 9 < = n u m s [ i ] < = 1 0 9 -10^9 <= nums[i] <= 10^9 −109<=nums[i]<=109
(2)思路
最初的思路为使用区间dp,每个阶段都有两个状态:1. 乘积为正数最大值,乘积为负数的最大值。(答案没错,但超出空间限制,使用了三维数组)。最后看的题解,论证了并不需要遍历每个子数组。
(3)算法实现
最初算法实现
class Solution {
public int getMaxLen(int[] nums) {
int len = nums.length;
int ans = 0;
int[][][] dp = new int[len+1][len+1][2];
for(int i = 1; i <= len; i++){
for(int j = 1; j <= i; j++){
if(nums[i-1] > 0){
dp[j][i][0] = dp[j][i-1][0] + 1;
dp[j][i][1] = dp[j][i-1][1] == 0 ? 0 : dp[j][i-1][1] + 1;
}else if(nums[i-1] < 0){
if(dp[j][i-1][1] != 0){
dp[j][i][0] = dp[j][i-1][1] + 1;
}else{
dp[j][i][0] = 0;
dp[j][i][1] = dp[j][i-1][0] + 1;
}
}else{
dp[j][i][0] = 0;
dp[j][i][1] = 0;
}
ans = Math.max(ans, dp[j][i][0]);
}
}
return ans;
}
}
上面代码第100个测试用例空间超出限制了。
最后的算法实现
class Solution {
public int getMaxLen(int[] nums) {
int len = nums.length;
int[] dp = new int[2];
if(nums[0] > 0) dp[0] = 1;
else if(nums[0] < 0) dp[1] = 1;
int ans = dp[0];
for(int i = 1; i < len; i++){
if(nums[i] > 0){
dp[0] = dp[0] + 1;
dp[1] = dp[1] == 0 ? 0 : dp[1] + 1;
}else if(nums[i] < 0){
int tmp1 = dp[0], tmp2 = dp[1];
dp[0] = tmp2 == 0 ? 0 : tmp2 + 1;
dp[1] = tmp1 + 1;
}else{
dp[0] = 0;
dp[1] = 0;
}
ans = Math.max(ans, dp[0]);
}
return ans;
}
}
二、蓝桥题目
今天看了一道蓝桥的题目,脑子里面有一些思路。我也不想看题解,想自己硬肯,感觉能写出来,但感觉今天时间不够了,明天在贴上来吧。