LeetCode747 至少是其他数字两倍的最大数(树形选择排序 | 锦标赛树)

本文探讨了LeetCode 747题目的两种解题思路:线性扫描和锦标赛树。线性扫描简单直观,而锦标赛树虽空间复杂度较高,但能减少比较次数,适用于寻找唯一最大值及次大值的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:leetcode747

题目大意

在这里插入图片描述

解题思路

问题中有说一定存在最大值,意思是这个最大值是唯一的。确定了问题主要是寻找最大值次大值就可以愉快地解决了,主要思路有如下两种:

线性扫描

直接 for 一遍即可,如果只是考虑比较的次数,最差会达到 2 ∗ n − 2 2*n-2 2n2

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

锦标赛树

这个树是树形选择排序的前置技能,也是堆排序的弱化版,因为空间复杂度较高,但优点是能够减少比较次数。对于本题,仅仅只要寻找最大值和次大值,构造的树没必要为一个严谨的满二叉树,利用数组像堆那样构造即可,父节点维护子节点的最大值。找次大值时只需要沿着最大值的根到叶子的路径中,每个节点的兄弟节点,取最大的一个即为次大值。这个算法如果没有最大值是唯一的约束则不成立,因为那样路径就不能保证唯一。

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

考虑比较的次数,这个算法最差会达到 n + ⌈ l o g n ⌉ − 2 n+\lceil logn \rceil-2 n+logn2。如何计算呢?我们容易计算,构造这个树并找到最大值的复杂度为 n − 1 n-1 n1,之后根据最大值的路径去寻找次大值的次数为 h − 1 h-1 h1,h为树的高度,减一是因为根已经是最大值了,故不用考虑

代码

class Solution {
public:
    int dominantIndex(vector<int>& nums) {
        if(nums.size()==1) return 0;
        int tree[nums.size()<<1], n=nums.size();
        for (int i=n; i<2*n; i++) tree[i]=i-n;
        for (int i=2*n-2; i>=2; i-=2) tree[i>>1]=nums[tree[i]]>nums[tree[i|1]]?tree[i]:tree[i|1];
        int first_max_id = tree[1], second_max_id, start=2;
        if (nums[tree[1]] == nums[tree[2]]) second_max_id=tree[3];
        else start=3, second_max_id=tree[2];
        for (int i=2*start; i<=2*n-2; i*=2) {
            if (nums[tree[i]]==nums[tree[i>>1]]) second_max_id=nums[tree[i|1]]>nums[second_max_id]?tree[i|1]:second_max_id;
            else second_max_id = nums[tree[i]]>nums[second_max_id]?tree[i++]:second_max_id;
        }
        return nums[first_max_id]>=nums[second_max_id]*2?first_max_id:-1; 
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小胡同的诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值