2019-02-14 最大乘积 - 2018拼夕夕校招

这道题目来自 2018年拼夕夕的校招,我从牛客网上刷到这个题。
https://www.nowcoder.com/practice/5f29c72b1ae14d92b9c3fa03a037ac5f

题目可以自行去看,我这里再简单提一下。

一. 题目

给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大,要求时间复杂度:O(n),空间复杂度:O(1)

示例如下。


image.png

二.分析

先简单提一下:

以前刷LeetCode是直接写方法,现在用牛客这个在线编译器还不太习惯。
首先我是用java写的,牛客这里的java代码,会要求写一个Main类,然后写main方法,其次,输入是需要写从控制台读取,输出是运算结果,所以读取数据是需要自己写的。
再就是java要导包,其实记几个重要的包就可以满足了。
千万不要以为java 可以这么写:

important java.*;

java里面这么导包是不可以的。

正式分析:

看分析可以对照代码看,我贴的代码分为了几个部分,可以对应着看。

A: 输入
最开始是想着怎么输入,用了一个nextLine读取一行,然后又用split切片,怎么也AC不过,后来发现不能这么写,于是就去参考了大佬的输入(仅仅是输入部分……哈哈哈),发现他写的是先输入n这个值,然后再输入数据,那我就觉得这个题目出的不严谨……后来看了一道腾讯的,就很清楚让你先输入什么,再输入什么。

常刷LeetCode,对于这种不太熟悉,暂且不考虑,这不是我们的重点,我们从控制台接收这个数组,存在myData 里,这里注意要是Long型的,否则可能会有溢出之类的。

B:排序
一开始想的很复杂,情况各异,主要是局限于他所强调的On的算法复杂度,但是对于算法题的话,我觉得不太可能是让你一种一种的去想,于是干脆换了个思路。

由于它要求On的复杂度,所以我就一直没有考虑排序。
Java里面Arrays.sort()方法是一个封装好的排序方法,里面是二轴快排,对于这个排序比快速排序高级一些,但是不太了解,感兴趣的可以自行研究研究。

但是最后实在想不出好方法,然后我就用了这个方法。

C:处理
可以看我对排完序的数据进行的操作,我的思路是,排好序的数组,如果要找三个数的乘积最大,只有两种情况,
case 1.一种是数组的第0位,第1位和最后一位
case 2.第二种是数组的倒数三位

然后再从这两种情况里选到底是哪个大。
最后输出就是所求。

那为什么会这样呢?
我们举个例子。

这里是有>=2个负数的情况。
原始数据: -2 -3 -1 1 0 4 3
排序后:-3 -2 -1 0 1 3 4
所求的case 1 : -3 * -2 * 4 = 24
所求的case 2 :1 * 3 * 4 = 12
那么最后的输出即是24

我们分析简单情况,假如说数组中只有正数和0,那么最大值乘积一定产生在排序后的数组的最后3位 【即case2】

此外,众所周知,负负得正,则肯定会有两个负数 再乘一个正数产生最大值的情况。
那最大值会在哪里产生,负负得正,我们就要找两个最小的负数,如上面一个例子,-3 和 -2 ,求出正数后,只需再找一个最大值即可,从哪里产生?当然是最后一位。 【即case1】

有童鞋看到这里可能就想着分case1和case2来判断了,但是这里其实就像我那样写即可,只需要比较一下哪个大就OK。

import java.io.*;
import java.util.*;
 
public class Main{
   public static void main(String[] args) throws Exception{
        long sum = 1;
       
        //A,
       //输入数据,秀儿。
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long[] myData = new long[n];
        for (int i = 0; i < n ; i++) {
            myData[i] = sc.nextLong();
        }
    
        //B,
       //排序
       Arrays.sort(myData);
 
        //C,
       //排序之后,从起始位置开始取值,有两种情况。
       //第一种:0位 * 1位 * 最后一位
       //第二种:最后一位 * 倒二 * 倒3
       //最大值只产生于这两种情况中
       long s1 = myData[0] * myData[1] * myData[n - 1];
       long s2 = myData[n - 1] * myData[n - 2] * myData[n - 3];
       sum = s1 > s2 ? s1 : s2;
 
       
       //打印最终值
       System.out.print(sum);
           
   }  
}

三. 运行结果

我们先看题目的时空限制。


看看我写的程序的时空


image.png

其实是在它的要求之内的,只不过对于On我还真是没别的思路了。
但是个人觉得我这个方法还是挺通俗易懂的,大致浏览了一下别人的算法,也有和我类似的实现,下面再说一个别的大佬的实现。

四. 其他实现

我们看一下湖南大学secndf大佬的实现。

     /**
     *  思路:三个数乘积最大,那么肯定包含其中最大的数,然后就只要比较最小的两个数乘积和第二第三大的两个数乘积。
     *  m1,m2是最小的两个数,max,h2,h1为第一/二/三大的数
     */
    public static long maxTriMultiply(long A[]){
        long m1 = Integer.MAX_VALUE, m2 = Integer.MAX_VALUE, h1 = Integer.MIN_VALUE, h2 = Integer.MIN_VALUE, max = Integer.MIN_VALUE;
 

       for(int i=0;i < A.length;++i){
            if(A[i]>max){
                h1=h2;
                h2=max;
                max = A[i];
            }else if(A[i]>h2){
                h1=h2;
                h2 = A[i];
            }else if(A[i]>h1){
                h1=A[i];
            }
            if(A[i] < m1){
                m2=m1;
                m1=A[i];
            }else if(A[i] < m2)
                m2=A[i];
        }

 
        max = max * m1 * m2 > max * h1 * h2 ? max * m1 * m2 : max * h1 * h2;
        return max;
    }

可以看到,他确定了两个最小的数,三个最大的数。
然后比较了我上面所提到的case1 和 case2 两种情况

与我不同的是,他为了实现On的算法,仅用了一遍遍历来找这些值。【自愧不如,以为要找到它们很麻烦,就没多想】

其实仔细看来也并不麻烦,举个例子,我们用简单选择排序的时候是怎么操作的?就是确定一个值,然后不断找比它小的值,找遍所有,确定最小值的序号,再进行交换,这里也是,只不过多了 第 n 小(大)的说法,

举个例子。
-1 4 2 0 1
我们来找最大值。

if(A[i]>max){
   h1=h2;
   h2=max;
   max = A[i];
 }

第一轮
A[0] > max(当前是MIN_VALUE)
h1取h2的值(当前是MIN_VALUE),
h2取max的值(当前是MIN_VALUE),
max取A[i] (当前是-1)

第二轮
A[1] > max(当前是-1)
h1取h2的值(当前是MIN_VALUE),
h2取max的值(当前是-1),
max取A[i] (当前是4)

第三轮
A[2] < max(当前是4)

第四轮,第五轮,已经无需再写了,我们的最大值已经找到了。
if也进不去了。

他这里这个变量名取的不太好,容易让人误解。
感兴趣可以分析一下这个过程,以后要是有类似的要挑选最大,第二大,最小,第二小的题,就可以直接用这个方法啦。

五. 总结

今天是2019 年情人节,上午起的很晚,刷了这道题之后就中午吃饭了,下午朋友叫我出去玩,本身要写本文的也搁置了,直到晚上才写完。

考研这几天也要下成绩了,估计考的也不好,没抱太大希望。
多刷刷算法题,涨涨知识吧。
反正复试和找工作都需要算法。

加油!
无论如何,都相信自己可以的!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,233评论 0 4
  • 前言 谢谢牛客网帮助我成功拿到心仪的offer(自然语言算法工程师),也感觉各位大佬分享的面经,所以想回馈一波。...
    batbattle阅读 3,676评论 0 3
  • 我不知道多久才能遇见你 我只知道现在的我过于普通,我的光芒太过微小,你根本看不到 我不知道会在哪里遇见你 也许会在...
    钰莹菇凉阅读 350评论 5 4
  • 两年半了吧。 好久不见,感觉自己快记不起你们的样子了。我知道,你们一定在N城过得很开心。有理想,有上进心,还有...
    来日可期末得高分阅读 393评论 0 8
  • 妇幼保健院,顾名思义,妇女和儿童比较专业的医院,大宝急性喉炎,二宝支气管肺炎,都在这里看医生,请假六天,...
    百合鸟飞阅读 169评论 0 0