吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2657|回复: 10
收起左侧

[Java 转载] 【分享】一道面试题引发的思考

[复制链接]
hack_hu 发表于 2019-11-3 18:02

好的面试官能够能好的和面试者互动,而一场好的面试也能带给面试者更多的思考

面试题:有 N 个数,求能够组成最大值的 n-1 个数,不能使用除法

面试官给我出题后的 1 分钟内,我给出了第一种思路:排序

将数字按升序排序,去除最小的那个数即可。

存在问题:时间复杂度高,只考虑了正数的情况

面试官给出了第一次提示时间复杂度过高,要求降低时间复杂度。

这里其实已经把思考的范围缩小了,因为之前的排序时间度大概为 O(nlogn) (可参照快排和归并排序均摊时间复杂度),那要降低的话就是 O(n) 了,即在线性的时间复杂度(遍历几次数组)就能获得答案。

于是在经过几分钟思考后,我给出了一个错误的 动态规划 的思路。

面试官进一步提示我:这道题可以用很简单的方法解题,不用什么高深的算法。

于是我调整了一下思路继续思考问题,根据基本的几种情况进行了推导。

1、无负数情况下,取出最小值即可。

2、有负数情况下,根据负数的计数偶数个数来判断是取出,负数绝对值最小值,还是非负数绝对值最小值。

根据这个推断我们只需要一次遍历,记录负数个数,同时记录负数、非负数绝对值最小者。

于是我将思路讲给面试官,他笑了笑说,这个思路是对的,但是不能给我满分,要我再好好想一下,检查一下。

我知道,应该是有一些边界值还没有处理好,但是看了几分钟,还是没有找出问题。(人在紧张的情况下,思路会不太清晰)

于是,面试官指出了我面试中存在的问题,纯负数情况下,奇数个负数,应该排除绝对值奇数个,对于 0 这个边界值,也没有考虑到。一共应该是有 12 个分支,而我的代码只考虑了其中的 3、4 个(文章后面会画图解释)。

面试官进一步指导:在实际的代码开发中,可能并不会用太多高深的算法,但是像这道题一样的简单问题却很常见,我们需要考虑代码的健壮性,上线的代码仅考虑到 90% 的情况是错误的

问题复盘

为什么是 12 个分支?
因果图
三个初始分支 n 个数都为非负数、n 个数有正有负、n 个数都为负数,以及 n 个数中是否存在 0,负数个数的奇偶个数 推导 332 = 12 个分支(0个负数视作偶数个,去除 2 个不存在情况,还剩 10 种需要考虑的情况)

实际可能出现的答案有三种:

1、无负数、有正有负且负数个数为偶数时,去除非负数绝对值最小者。

2、n 个数都为负数且负数个数个数为偶数时,去除负数绝对值最大者。

3、负数个数为奇数时,取负数绝对值最小者。(有正有负且存在 0,负数个数为奇数个可以去除任意非 0 数)

转换为实际代码:

/*
    找出去除后集合乘积能达到最大的那个数
*/
int findMaxProductNum(int[] nums) {
        int minMinus = Integer.MIN_VALUE, maxMinus = 0, minNum = Integer.MAX_VALUE, count = 0;
        boolean hasZero = false;
         // 一次遍历,统计负数个数,并判断 0 是否存在,更新负数/非负数 最大/小 绝对值
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] < 0) {
                count++;
                maxMinus = Math.min(maxMinus, nums[i]);
                minMinus = Math.max(minMinus, nums[i]);
            } else if (nums[i] == 0) {
                hasZero = true;
                minNum = 0;
            } else {
                minNum = nums[i] < minNum ? nums[i] : minNum;
            }
        }
        if (count == 0||(count<nums.length&&(count&1)==0)) { // 无负数、有正有负且负数个数为偶数时
            return minNum;
        } else if (count==nums.length&&(count&1)==0) { // n 个数都为负数且负数个数个数为偶数时
            return maxMinus;
        } else { // 负数个数为奇数时
            return minMinus;
        }
    }

这道题的目的是什么

考察一个求职者代码的健壮性,即能不能考虑全面,将问题的每个分支处理好。(可以先分解出输入的边界值,根据不同组合的分支推导结果。)

总结

1、 面试过程中,不要急于解题,要 和面试官确认好问题的边界。如果未明确,代码的健壮性就很有可能出现问题。

2、出错不要怕,好的面试官会引导你解题,注意提出问题后面试官给出的提示,这都是解题的方向。

3、几轮的面试是很累的,前一天做好休息,面试过程中 不要太紧张,会影响发挥,喝喝水调整下呼吸,放松下自己。

免费评分

参与人数 4吾爱币 +3 热心值 +4 收起 理由
woaiqing77521 + 1 热心回复!
qing-bei + 1 + 1 用心讨论,共获提升!
lijt16 + 1 + 1 我很赞同!
zxy19970406 + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| hack_hu 发表于 2019-11-3 20:24
看过帖子的老铁们也可以分享下自己的看法
2271325928 发表于 2019-11-3 20:38
这个题看着很简单 ,很多人都会说是排序之类, 其实吧 最优以及最简单就是  时间复杂度为n, 对于负数 正数之类的判断,  几次for 就ok 。
 楼主| hack_hu 发表于 2019-11-3 20:58
2271325928 发表于 2019-11-3 20:38
这个题看着很简单 ,很多人都会说是排序之类, 其实吧 最优以及最简单就是  时间复杂度为n, 对于负数 正数 ...

关键不在于考察算法的理解,而是代码设计的健壮性,是否对每种情况都有考虑
2271325928 发表于 2019-11-3 21:01
hack_hu 发表于 2019-11-3 20:58
关键不在于考察算法的理解,而是代码设计的健壮性,是否对每种情况都有考虑

也是,当初也遇到这种类似的面试题
 楼主| hack_hu 发表于 2019-11-3 21:43
2271325928 发表于 2019-11-3 21:01
也是,当初也遇到这种类似的面试题

有经验以后会好很多,更多的是平时代码经验的积累。
夜渐短 发表于 2019-11-4 17:02
小白学到了
cukuyo 发表于 2019-11-8 09:56
这题记得在哪个公众号看过,还有楼主你图挂了
woaiqing77521 发表于 2019-11-8 10:52
关键不在于考察算法的理解,而是代码设计的健壮性,是否对每种情况都有考虑,说的有道理啊,实践是最好的锻炼细节把握能力。
 楼主| hack_hu 发表于 2019-11-8 13:18
cukuyo 发表于 2019-11-8 09:56
这题记得在哪个公众号看过,还有楼主你图挂了

这个题肯定有在其他面试题中出现过,不过这是我的亲身经历,图是引入的外部图片,你刷新看一下能不能看到
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 18:10

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表