面试官问:你前面一位面试者是清华毕业的,为什么我要录取你。。

科技   2024-12-08 12:36   陕西  
说到面试,有时候你会碰到一些让人又气又好笑的问题。
比如我朋友最近面试某个公司产品岗位时,面试官突然来了这么一问:“你前面一位面试者是清华毕业的,为什么我要录取你而不是他?”当时我朋友差点没忍住,差点就怼回去:“那你咋不直接问我怎么比清华生差?”



说实话,这个问题不仅让人感觉有点挑衅,还有点让人怀疑面试官的基本职业素养。
作为程序员,我们有时候真的是不太看重这些名校标签的,做得好才是真的强。如果拿“清华毕业”就能拿到工作,那这个世界上是不是所有面试都只会选清华毕业生?但事实是,很多事情做出来才是硬道理,能动手,能解决问题才是王道。
学历,甚至名校,它只是一个起点,真正的竞争力还是在于你能做什么,能为公司带来什么。
所以,面对这种“学历比较”式的面试问题,我觉得最好的反应就是:自信!不用跟人家比什么学校,咱们凭本事说话。

算法:分割数组的最大值

来聊一个经典的算法题:分割数组的最大值

题目描述是这样的:

给定一个数组 nums 和一个整数 m,将数组分成 m 个非空的连续子数组。我们需要找到每个子数组的和的最大值,然后返回这个最大值的最小值。换句话说,我们要尽量平衡这些子数组的和,使得最大和尽可能小。

听起来是不是有点挑战性?其实这个问题关键的地方在于如何有效地在给定的约束下找到最优解。

我们先看个简单例子

假设 nums = [7, 2, 5, 10, 8],我们需要把它分成 m = 2 个子数组。目标是将这两个子数组的和最大值最小化。

直观地,我们可以分成两种可能:

  1. 子数组1:[7, 2, 5],子数组2:[10, 8],这两个子数组的和分别是 14 和 18,最大值是 18。
  2. 子数组1:[7, 2],子数组2:[5, 10, 8],这两个子数组的和分别是 9 和 23,最大值是 23。

所以第一种分割方式的最大值更小,我们的目标就是找到类似这样的最优分割。

思路

首先,我们可以通过二分法来优化问题的解法。我们知道,最大的子数组和至少是数组中最大的单个元素,而最小的子数组和是数组所有元素的和。所以,我们可以将最大值设定在这两个值之间,逐渐逼近最优解。

  1. 初始化二分范围:我们设定二分的左右边界为 max(nums)sum(nums)。也就是说,最小可能的最大子数组和是数组中的最大元素,最大可能的最大子数组和是数组元素的总和。

  2. 二分查找:我们不断地调整二分的中点 mid,检查是否能够将数组分成 m 个子数组,每个子数组的和不超过 mid。如果可以,就说明 mid 可以作为一个候选值,接着我们缩小范围来寻找更小的 mid。如果不行,那就意味着 mid 太小了,我们需要增大它。

  3. 划分子数组的判断:每次我们检查当前的 mid 值是否可行时,可以通过遍历数组来模拟子数组的划分。我们从头开始遍历数组,逐个加元素,如果当前和加上这个元素超过了 mid,那么就需要开始一个新的子数组。

代码实现

public class Solution {
    public int splitArray(int[] nums, int m) {
        // 定义二分的左右边界
        int left = 0, right = 0;
        
        for (int num : nums) {
            left = Math.max(left, num);  // 最小的可能最大值是数组中的最大元素
            right += num;  // 最大的可能最大值是数组元素的总和
        }
        
        // 二分查找
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (canSplit(nums, mid, m)) {
                right = mid;  // 如果可以分割成m个子数组,则继续缩小上界
            } else {
                left = mid + 1;  // 如果不能,则增大下界
            }
        }
        
        return left;  // 最终的最小的最大值
    }

    // 判断是否可以将数组分割成m个子数组,且每个子数组的和不超过target
    private boolean canSplit(int[] nums, int target, int m) {
        int count = 1;  // 至少一个子数组
        int currentSum = 0;
        
        for (int num : nums) {
            currentSum += num;
            if (currentSum > target) {
                count++;  // 如果当前子数组和超过了target,说明需要新建一个子数组
                currentSum = num;  // 当前元素作为新子数组的第一个元素
                if (count > m) {
                    return false;  // 如果分割成了超过m个子数组,返回false
                }
            }
        }
        
        return true;  // 如果最终分割成的子数组数量不超过m个,返回true
    }
}

代码解释

  1. 初始化边界left 是数组中的最大值,right 是数组元素的总和。
  2. 二分查找:通过二分查找逐渐缩小 leftright 的差距,找到最小的 mid,使得数组可以分割成 m 个子数组。
  3. 判断函数canSplit 函数用来判断当前的 mid 是否满足题目要求,即是否能将数组分割成不超过 m 个子数组,每个子数组的和不超过 mid

复杂度分析

  • 时间复杂度:二分查找的时间复杂度是 O(log(sum(nums) - max(nums))),每次二分查找需要遍历数组,时间复杂度是 O(n)。因此,总的时间复杂度是 O(n * log(sum(nums) - max(nums)))
  • 空间复杂度:我们只用了常数空间,所以空间复杂度是 O(1)

结语

说实话,这种题目刚开始做的时候看起来挺头大的,特别是题目里有分割这种概念,给人一种很复杂的感觉。但通过二分法这种巧妙的方式,就能把问题转化成一个可控的范围,逐渐逼近最优解。

对编程、职场感兴趣的同学,可以链接我,微信:coder301 拉你进入“程序员交流群”。
🔥东哥私藏精品 热门推荐🔥

东哥作为一名超级老码农,整理了全网最全《Java高级架构师资料合集》

资料包含了《IDEA视频教程》《最全Java面试题库》、最全项目实战源码及视频》及《毕业设计系统源码》总量高达 650GB 。全部免费领取!全面满足各个阶段程序员的学习需求。

Java面试那些事儿
回复 java ,领取Java面试题。分享AI编程,Java教程,Java面试辅导,Java编程视频,Java下载,Java技术栈,AI工具,Java开源项目,Java简历模板,Java招聘,Java实战,Java面试经验,IDEA教程。
 最新文章