671. 二叉树中第二小的节点
给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么该节点的值等于两个子节点中较小的一个。
更正式地说,root.val = min(root.left.val, root.right.val) 总成立。
给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。
示例 1:
输入:root = [2,2,5,null,null,5,7]
输出:5
解释:最小的值是 2 ,第二小的值是 5 。
示例 2:
输入:root = [2,2,2]
输出:-1
解释:最小的值是 2, 但是不存在第二小的值。
提示:
树中节点数目在范围 [1, 25] 内
1 <= Node.val <= 231 - 1
对于树中每个节点 root.val == min(root.left.val, root.right.val)
解题思路:根节点永远是最小的那个
- 利用递归遍历二叉树,遇到叶子节点则结束递归
- 当前节点值若大于根节点值,并且小于当前第二小值,则更新第二小的值
- 由于第二小的值初始化为-1,所以第二步多一步判断,即(第二小值 == -1)
- 返回第二小值
代码如下:
int min, min1 = -1;
public int findSecondMinimumValue(TreeNode root) {
if (root == null) {
return -1;
}
min = root.val;
recursion(root);
return min1;
}
public void recursion(TreeNode root) {
if (root != null) {
if (root.val > min && (root.val <= min1 || min1 < 0)) {
min1 = root.val;
}
recursion(root.left);
recursion(root.right);
}
}
1695. 删除子数组的最大得分
给你一个正整数数组 nums ,请你从中删除一个含有 若干不同元素 的子数组。删除子数组的 得分 就是子数组各元素之 和 。
返回 只删除一个 子数组可获得的 最大得分 。
如果数组 b 是数组 a 的一个连续子序列,即如果它等于 a[l],a[l+1],...,a[r] ,那么它就是 a 的一个子数组。
示例 1:
输入:nums = [4,2,4,5,6]
输出:17
解释:最优子数组是 [2,4,5,6]
示例 2:
输入:nums = [5,2,1,2,5,2,1,2,5]
输出:8
解释:最优子数组是 [5,2,1] 或 [1,2,5]
提示:
1 <= nums.length <= 100000
1 <= nums[i] <= 10000
解题思路:滑动窗口不断右移,保证窗口内的元素唯一,同时更新最大得分
- 初始化滑动窗口左边界为数组下标0,右边界为数组下标1,最大得分为左边第一个元素值,同时定义一个临时最大值,初始为左边第一个元素值,用于和最大得分比较,大于最大得分则更新最大得分
- 由于已知元素值最大不超过10000,因此可以利用一个大小10001的数组来存储元素是否存在于滑动窗口内,提升效率
- 右边界从1开始不断右移,利用boolean数组判断右边元素是否已经存在于窗口内,若不存在,则将boolean数组对应下标(右边元素值)置为true表示该元素已存在,并更新临时最大值为临时最大值;若存在,则左边界需要不断左移至存在元素的位置,每次左移都要更新临时最大值=临时最大值-左移的值
- 每次右移一位,都需要用临时最大值和当前最大得分来比较,得出最大值,并更新最大得分
- 当右边界移至数组尾部时,结束移动,返回最大得分即可
代码如下:
public int maximumUniqueSubarray(int[] nums) {
int max = nums[0];
int max1 = max;
int left = 0, right = 1;
boolean[] booleans = new boolean[10001];
booleans[max] = true;
while (right < nums.length) {
int rightNum = nums[right];
if (!booleans[rightNum]) {
max1 += rightNum;
booleans[rightNum] = true;
} else {
booleans[rightNum] = false;
while (booleans[nums[left]]) {
max1 -= nums[left];
booleans[nums[left]] = false;
left++;
}
booleans[rightNum] = true;
++left;
}
max = Math.max(max, max1);
++right;
}
return max;
}
面试题 10.11. 峰与谷
在一个整数数组中,“峰”是大于或等于相邻整数的元素,相应地,“谷”是小于或等于相邻整数的元素。例如,在数组{5, 8, 4, 2, 3, 4, 6}中,{8, 6}是峰, {5, 2}是谷。现在给定一个整数数组,将该数组按峰与谷的交替顺序排序。
示例:
输入: [5, 3, 1, 2, 3]
输出: [5, 1, 3, 2, 3]
提示:
nums.length <= 10000
解题思路:
- 利用boolean来标志当前需要峰->谷还是谷->峰,初始化为true表示峰->谷
- 从第二个元素开始遍历数组,每次与前一个元素作比较
- 若前一个元素小于当前元素,且标志为峰->谷,则需要对这两个元素进行交换
- 每次循环都要对标志取反,表示峰谷顺序变换
- 遍历完后,即完成了峰谷交替
代码如下:
public void wiggleSort(int[] nums) {
boolean flag = true;
for (int i=1; i<nums.length; i++) {
if (nums[i-1] < nums[i] == flag) {
int temp = nums[i-1];
nums[i-1] = nums[i];
nums[i] = temp;
}
flag = !flag;
}
}