174竞赛
分裂二叉树的最大乘积
给你一棵二叉树,它的根为 root
。请你删除 1 条边,使二叉树分裂成两棵子树,且它们子树和的乘积尽可能大。
由于答案可能会很大,请你将结果对 10^9 + 7 取模后再返回。
示例 1:
输入:root = [1,2,3,4,5,6] 输出:110 解释:删除红色的边,得到 2 棵子树,和分别为 11 和 10 。它们的乘积是 110 (11*10)
示例 2:
输入:root = [1,null,2,3,4,null,null,5,6] 输出:90 解释:移除红色的边,得到 2 棵子树,和分别是 15 和 6 。它们的乘积为 90 (15*6)
示例 3:
输入:root = [2,3,9,10,7,8,6,5,4,11,1] 输出:1025
示例 4:
输入:root = [1,1] 输出:1
提示:
- 每棵树最多有
50000
个节点,且至少有2
个节点。 - 每个节点的值在
[1, 10000]
之间。
/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */ /** * @param {TreeNode} root * @return {number} */ var maxProduct = function(root) { const all = new Set() function getSum(root) { if (!root) return 0 const val = root.val + getSum(root.left) + getSum(root.right) all.add(val) return val } const allSum = getSum(root) let m = allSum; let max = 0; for(let v of all){ let r = v*(m-v) if(r>max){ max = r } } return max%(10**9 + 7 ); // for (let v of all) { // if (Math.abs(m - allSum / 2) > Math.abs(v - allSum / 2)) { // m = v // } // } // return (m * (allSum - m)) % (10 ** 9 + 7) } /* let maxSum = 0; var getSum = (r1, r2) =>{ } var dfs = (root)=>{ if(!root) return if(root.left) { let tr1 = root.left ; let cloneR = JSON.parse(JSON.stringify(root)); cloneR.left = null let tr2 = cloneR; let sum = getSum(tr1, tr2) if(sum>maxSum){ maxSum = sum } dfs(root.left) } if(root.right) { dfs(root.right) } } var maxProduct = function(root) { dfs(root) }; */
其实,一个深度优先求和在得出结果的回溯的过程中,会出现题目中需要的子树的和,然后求最大乘积即可。
我当时还想着多次套遍历树的节点,拿到每一部分的和,再求乘积。
数组大小减半
给你一个整数数组 arr。你可以从中选出一个整数集合,并删除这些整数在数组中的每次出现。
返回 至少 能删除数组中的一半整数的整数集合的最小大小。
示例 1:
输入:arr = [3,3,3,3,5,5,5,2,2,7]
输出:2
解释:选择 {3,7} 使得结果数组为 [5,5,5,2,2]、长度为 5(原数组长度的一半)。
大小为 2 的可行集合有 {3,5},{3,2},{5,2}。
选择 {2,7} 是不可行的,它的结果数组为 [3,3,3,3,5,5,5],新数组长度大于原数组的二分之一。
示例 2:
输入:arr = [7,7,7,7,7,7]
输出:1
解释:我们只能选择集合 {7},结果数组为空。
示例 3:
输入:arr = [1,9]
输出:1
示例 4:
输入:arr = [1000,1000,3,7]
输出:1
示例 5:
输入:arr = [1,2,3,4,5,6,7,8,9,10]
输出:5
提示:
1 <= arr.length <= 10^5
arr.length 为偶数
1 <= arr[i] <= 10^5
/** * @param {number[]} arr * @return {number} */ var minSetSize = function(arr) { let len = arr.length; let map = new Map(); arr.forEach(a=>{ if(map.has(a)){ map.set(a, map.get(a)+1) }else{ map.set(a, 1) } }) let arr1 = []; for(let [key, value] of map){ arr1.push({key, value}) } // 为什么sort 减法可以排序, 如果用对象表示,Object.values 然后 sort,拿个个数的排序,其实key没必要保留。参考下面算法。 arr1.sort((a,b)=>b.value-a.value) let res = 0; let l = len; let r=0; while(l--){ r += map.get(arr1[res]['key']); if(len / (len-r)>=2){ res++; break; } res++; } return res; };
/** * @param {number[]} arr * @return {number} */ var minSetSize = function(arr) { const len = arr.length const all = Object.values( arr.reduce((p, v) => { p[v] = (p[v] | 0) + 1 return p }, {}), ).sort((a, b) => b - a) let sum = 0 for (let i = 0; i < all.length; i++) { if ((sum += all[i]) >= len / 2) { return i + 1 } } return all.length }
为什么 sort 可以排序呢?
let arr = [4,2,3,1]; Array.prototype.sort1 = function (cb) { for (var i = 0; i < this.length; i++) { for (var j = i+1; j < this.length; j++) { let v1 = this[i], v2 = this[j]; // 从小到大 // 只需这一步就够了,cb(a, b) 对 2值进行比较,
// 如果是a-b>0, a-b>0,进行排序,从小到大排列;
// 如果是 b-a >0,进行排序,从大到小,总之回调函数的函数体起到一个比较作用。
// 之所以感觉奇怪就是,这里只有一条进行比较的语句 cb(v1, v2)>0,就可以对应 a-b 和 b-a 两种不同的排序方式 if(cb(v1, v2)>0){ let temp = this[i]; this[i] = this[j]; this[j] = temp; } //else { // 从大到小 // if(cb(v1, v2)<0){ // let temp = v1; // v1 = v2; // v2 = temp; // } //} } } return this } console.log(arr.sort1((a,b)=>b-a))
V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,数量小于10的数组使用 InsertionSort,比10大的数组则使用 QuickSort。
V8 引擎array源码 710行开始
https://zhuanlan.zhihu.com/p/55338902
可以在github上找 v8 源码
跳跃游戏 V
给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到:
i + x ,其中 i + x < arr.length 且 0 < x <= d 。
i - x ,其中 i - x >= 0 且 0 < x <= d 。
除此以外,你从下标 i 跳到下标 j 需要满足:arr[i] > arr[j] 且 arr[i] > arr[k] ,其中下标 k 是所有 i 到 j 之间的数字(更正式的,min(i, j) < k < max(i, j))。
你可以选择数组的任意下标开始跳跃。请你返回你 最多 可以访问多少个下标。
请注意,任何时刻你都不能跳到数组的外面。
示例 1:
输入:arr = [6,4,14,6,8,13,9,7,10,6,12], d = 2
输出:4
解释:你可以从下标 10 出发,然后如上图依次经过 10 --> 8 --> 6 --> 7 。
注意,如果你从下标 6 开始,你只能跳到下标 7 处。你不能跳到下标 5 处因为 13 > 9 。你也不能跳到下标 4 处,因为下标 5 在下标 4 和 6 之间且 13 > 9 。
类似的,你不能从下标 3 处跳到下标 2 或者下标 1 处。
示例 2:
输入:arr = [3,3,3,3,3], d = 3
输出:1
解释:你可以从任意下标处开始且你永远无法跳到任何其他坐标。
示例 3:
输入:arr = [7,6,5,4,3,2,1], d = 1
输出:7
解释:从下标 0 处开始,你可以按照数值从大到小,访问所有的下标。
示例 4:
输入:arr = [7,1,7,1,7,1], d = 2
输出:2
示例 5:
输入:arr = [66], d = 1
输出:1
提示:
1 <= arr.length <= 1000
1 <= arr[i] <= 10^5
1 <= d <= arr.length
/** * @param {number[]} arr * @param {number} d * @return {number} */ var maxJumps = function(arr, d) { let len = arr.length; let a = new Array(len).fill(0); // let res= 0; const get = (i)=>{ if(a[i]!==0) return a[i]; let ans = 1; // 向左 for(let j=i-1; j>=0 && arr[j]<arr[i] && i-j<=d; j--){ ans = Math.max(ans, get(j)+1); } // 向右 for(let j=i+1; j<a.length && arr[j]<arr[i] && j-i<=d; j++){ ans = Math.max(ans, get(j)+1); } return a[i] = ans; } for(let i=0; i<a.length; i++){ // res = Math.max(res, get(i)); if(a[i]!==0) continue; get(i) } // console.log('a: ',a) return Math.max.apply(null, a); }
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game-v
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。