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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

posted @ 2020-02-05 19:38  土豆zhang  阅读(122)  评论(0编辑  收藏  举报