【蓝桥Java每日一练】——7.至少是其他数字两倍的最大数

简介: 今天带来的每日一题,是昨天的每日一题——至少是其他数字两倍的最大数。

🐤1.至少是其他数字两倍的最大数


给你一个整数数组 nums ,其中总是存在 唯一的 一个最大整数 。


请你找出数组中的最大元素并检查它是否 至少是数组中每个其他数字的两倍 。如果是,则返回 最大元素的下标 ,否则返回 -1 。


题目链接:至少是其他数字两倍的最大数https://leetcode-cn.com/problems/largest-number-at-least-twice-of-others/solution/zhi-shao-shi-qi-ta-shu-zi-liang-bei-de-z-985m/


           题目分析:题目的要求非常简单,找出一个数组的最大值的下标即可,只不过这个最大值有一个限制条件,它至少是数组中每个其他数字的两倍。大家起码都是大学生了,这意思肯定能看懂吧,无非就是要求最大值最少都都得是次大值的两倍,所以我们遍历一遍数组,利用两个变量maxIndex1和maxIndex2去找到数组中的最大值下标和次大值下标就好啦。


遍历过程:


      当我们循环判断nums[i]时,会有三种情况:


      1.此时nums[i]>nums[maxIndex1],nums[maxIndex1]也就是最大值,那么说明找到了个更大的,我们把maxIndex1更新成i


      2.此时nums[maxIndex1]>nums[i]>nums[maxIndex2],找到了个次大值,我们把maxIndex2更新为i


      3.此时nums[i]<nums[maxIndex2],小于次大值,这个数对我们无意义,不处理


      最后我们去判断nums[maxIndex1]>=2*nums[maxIndex2],如果满足我们就输出maxIndex1,否则输出-1


🐣1.易错情况1


          上述的逻辑其实是有地方有错误的,不知道大家能否发现,因为根据上述的代码我们会写出如下的代码:          


错误版本代码1:
class Solution {
    public int dominantIndex(int[] nums) {
        if(nums.length==1) return 0;
        //1维护的是最大值下标,2维护的是次大值下标
        int maxIndex1=0;
        int maxIndex2=0;
        for(int i=1;i<nums.length;i++){
            if(nums[i]>nums[maxIndex1]){
                 maxIndex2=maxIndex1;                              
            }else if(nums[i]>nums[maxIndex2]){
                 maxIndex2=i;
            }
        }
        if(nums[maxIndex1]>=2*nums[maxIndex2]){
            return maxIndex1;
        }else{
            return -1;
        }
    }
}

       这样一写就发现连题目给的第二个用例就过不了:        


image.png


为什么呢?明明4不是3的两倍,为什么还输出下标3呢?其实如果我们去眼睛debug一下,很容易就会发现一个问题——在情况1中,我们把maxIndex1更新为i,但是没有把maxIndex2更新为maxIndex1。虽然maxIndex1它遇到了比他更大的,但它应该为次大,所以需要把maxIndex1赋值给maxIndex2。      


🐣2.易错情况2


         如果照上面改正一定就没问题了吧,没错本来我也是这么想的,完善的代码如下:


错误版本2
class Solution {
    public int dominantIndex(int[] nums) {
        if(nums.length==1) return 0;
        //1维护的是最大值下标,2维护的是次大值下标
        int maxIndex1=0;
        int maxIndex2=0;
        for(int i=1;i<nums.length;i++){
            if(nums[i]>nums[maxIndex1]){
                 maxIndex2=maxIndex1;
                 maxIndex1=i;                              
            }else if(nums[i]>nums[maxIndex2]){
                 maxIndex2=i;
            }
        }
        if(nums[maxIndex1]>=2*nums[maxIndex2]){
            return maxIndex1;
        }else{
            return -1;
        }
    }
}

提交以后获得血红的提示:


image.png


其实当我一看到这个用例时,我就知道问题出在了哪!我的maxIndex1和maxIndex2起始下标都是0,可是如果num[0]是一个数组的最大元素,那么maxIndex2就不会更新,导致答案出错。我觉得这个还是比较难想到的,究其原因还是因为我的maxIndex1和maxIndex2不合理。但是我们也加一行代码给它强制改正,当nums[maxIndex2]遇到nums[1]比自己小的时候,把maxIndex2更新为1。


🐣3.正确答案版本


结合以上的经验,我们终于写出来AC的代码了:


class Solution {
    public int dominantIndex(int[] nums) {
        if(nums.length==1) return 0;
        //1维护的是最大值下标,2维护的是次大值下标
        int maxIndex1=0;
        int maxIndex2=0;
        for(int i=1;i<nums.length;i++){
            if(i==1&&nums[i]<nums[maxIndex2]){
                maxIndex2=i;
            }
            if(nums[i]>nums[maxIndex1]){
                 maxIndex2=maxIndex1;
                 maxIndex1=i;                              
            }else if(nums[i]>nums[maxIndex2]){
                 maxIndex2=i;
            }
        }
        if(nums[maxIndex1]>=2*nums[maxIndex2]){
            return maxIndex1;
        }else{
            return -1;
        }
    }
}


🐣4.官方答案版本  


class Solution {
    public int dominantIndex(int[] nums) {
        int m1 = -1, m2 = -1;
        int index = -1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > m1) {
                m2 = m1;
                m1 = nums[i];
                index = i;
            } else if (nums[i] > m2) {
                m2 = nums[i];
            }
        }
        return m1 >= m2 * 2 ? index : -1;
    }
}


🐣5.自写版本与官方版本对比总结


        自己写的和官方对比起来,肯定是相形见绌。官方版本的优点在于,它用了m1和m2去记录最大值和次大值,只用index去记录最大值下标,且index初始值为-1。迭代最大值m1时才更改index的值。最后的return语句更少一句话搞定,而我反而还写了个ifelse语句。我们为什么要注意去总结?学习算法是循序渐进的路程,虽然我们做出来了,但应该去循环是否有更好的方法、更好的写法以及更好的代码书写规范,这都是我们需要去学习的,只有和更好的人对比才能让自己进步。      


相关文章
|
4月前
|
Java
0-1背包问题(Java详解)(动态规划)至少与恰好
0-1背包问题(Java详解)(动态规划)至少与恰好
48 1
|
4月前
|
Java
CSDN每日一练(Java)--小艺的英文名
CSDN每日一练(Java)--小艺的英文名
|
4月前
|
安全 Java C++
2023-3-25 java选择题每日一练
2023-3-25 java选择题每日一练
39 1
|
4月前
|
Rust 索引
Rust 编程小技巧摘选(6)
Rust 编程小技巧摘选(6)
70 1
Rust 编程小技巧摘选(6)
|
4月前
|
C++ Python Rust
Rust 重载运算符|复数结构的“加减乘除”四则运算
Rust 重载运算符|复数结构的“加减乘除”四则运算
86 0
Rust 重载运算符|复数结构的“加减乘除”四则运算
|
4月前
|
Linux
Linux 终端命令之文件浏览(1) cat
Linux 终端命令之文件浏览(1) cat
46 0
Linux 终端命令之文件浏览(1) cat
|
4月前
|
Go Python Rust
Rust 编程小技巧摘选(7)
Rust 编程小技巧摘选(7)
83 0
Rust 编程小技巧摘选(7)
|
4月前
|
Linux Windows Ubuntu
Windows 使用 Linux 子系统,轻轻松松安装多个linux
Windows 使用 Linux 子系统,轻轻松松安装多个linux
343 0
Windows 使用 Linux 子系统,轻轻松松安装多个linux
|
6天前
|
存储 缓存 安全
【Java面试题汇总】多线程、JUC、锁篇(2023版)
线程和进程的区别、CAS的ABA问题、AQS、哪些地方使用了CAS、怎么保证线程安全、线程同步方式、synchronized的用法及原理、Lock、volatile、线程的六个状态、ThreadLocal、线程通信方式、创建方式、两种创建线程池的方法、线程池设置合适的线程数、线程安全的集合?ConcurrentHashMap、JUC
【Java面试题汇总】多线程、JUC、锁篇(2023版)
|
17天前
|
监控 Java 调度
【Java学习】多线程&JUC万字超详解
本文详细介绍了多线程的概念和三种实现方式,还有一些常见的成员方法,CPU的调动方式,多线程的生命周期,还有线程安全问题,锁和死锁的概念,以及等待唤醒机制,阻塞队列,多线程的六种状态,线程池等
79 6
【Java学习】多线程&JUC万字超详解