LeetCode.50 Pow(x, n) + 面试官想让你干的三件事

441 阅读5分钟

为什么面试官会考察算法

在开始今天的算法题之前,我想先聊一聊我对算法题的理解。算法可以说是让每个程序员都头疼的问题。在当今的面试过程中,算法题目几乎成为了必考内容。我们不能只刷题,还要看看面试官到底想要得到什么?我总结了以下三点。

2323.jpg

1. 思维能力和解决问题能力

首先,算法题目的设计往往能够很好地测试出一个人的逻辑思维能力和解决复杂问题的能力。一道题目通常有许多种解法,通过我们解题使用的方法,就能够考察到每个人的思维能力。如果两个人都完成了基本的任务,那就需要看哪个人的方法是否更巧妙,代码是否更简洁、更优雅,这就是思维能力的展现。思维能力对于任何一位希望成为优秀程序员的人来说都是至关重要的。

2.抽象能力的重要性

算法的学习和实践有助于培养良好的抽象思维习惯。例如,在处理数组、字符串等基本数据结构时,需要理解它们内部是如何组织存储信息的;而在操作栈、队列、链表乃至二叉树这样的高级数据结构时,则要求更高层次上的抽象能力——不仅要掌握其定义及特点,还要能灵活运用到具体场景中去。我们需要将题目与数据结构相结合,将问题抽象简单化,这方便我们理解,也更能帮助我们完成任务。

3.代码的高效性

优秀的算法不仅可以提高程序执行效率,还能有效降低资源消耗。时间复杂度和空间复杂度是衡量算法性能好坏的关键指标。我们优化算法就是在降低时间复杂度和空间复杂度。比如,快速排序相较于冒泡排序而言,在大规模数据集上有着显著的速度优势;而哈希表则能在常数时间内完成查找操作,极大地提升了数据检索速度。

编程题类型分析

面试中的编程题大致可以分为两类:

  • 程序逻辑题:通常是指那些需要编写一段代码来实现特定功能或满足某些条件的问题
  • 算法题: 考查应聘者对于数据结构的选择及使用、算法设计与优化的能力

相比之下,算法题是更为复杂的。算法题会考量效率(时间/空间复杂度)等因素;而程序逻辑题则更看重代码的质量(可读性、健壮性)。

x的n次幂(LeetCode.50题)

下面我们来计算x的n次方,在这里我使用javascript

先使用一个暴力解法

function func(x, n) {
    let result = 1;
    for (let i = 0; i < n; i++) {
        result *= x;
    }
    return result;
}

简单,很好理解!可能是新手们最先想到的方法,它也能够成功得到所需要的结果。但面试官似乎不太满意,还有吗?

我们提高一下难度,改变思维,x的n次方,有很多重复的步骤,每次都是乘x。所以我们就可以使用递归算法,时间复杂度为O(n):

牢记递归三要素

  • 递归函数以及参数
  • 递归终止条件
  • 递归单层搜索逻辑
  • 考虑栈溢出问题
function func(x, n) {
    // 退出条件
    if (n == 0) { return 1 }
    // 把问题分解成规模更小的子问题 自顶向下
    return x * func(x, n - 1);
}

面试官似乎比较满意,但还不够,我们还要惊艳他,我们要提高代码的时间复杂度。这次在递归的基础上,结合分治策略实现快速幂

function func(x, n) {
    if (n == 0) { return 1 }
    // 自顶向下 
    let t = func(x, Math.floor(n / 2));
    if (n % 2 === 0) {
        return t * t;  // 偶数 t ^ 2
    } else {
        return t * t * x; // 奇数 t ^ 2 * x
    }
}

t 就是 x^(n/2)

如果 n 是偶数 (n % 2 === 0),则 x^n=(x^(n/2))^2。因此,返回 t * t

如果 n 是奇数,则 x^n=(x^(n/2))^2*x。因此,返回 t * t * x

举个例子 2^5

// 代码运作流程(AI生成图)
func(2, 5)
|
|--- func(2, 2)
|    |
|    |--- func(2, 1)
|    |    |
|    |    |--- func(2, 0) -> 1 (t = 1)
|    |    |
|    |    `--- t = 1, return t * t * x = 2 (t = 1)
|    |
|    `--- t = 2, return t * t = 4 (t = 2)
|
`--- t = 4, return t * t * x = 32 (t = 4)

我们成功将时间复杂度O(n)优化成了O(logn)

但是别高兴得太早,这里还有一个致命的问题,n为负数时这个代码好行就行不通了。

那我们只要给代码添加一个n为负数的条件就行了,以下是完整的代码

function func(x, n) {
    if (n == 0) { return 1 }
    if (n < 0) {   		//n<0时 
        return 1 / func(x, -n)
    }
    // 自顶向下 
    let t = func(x, Math.floor(n / 2));
    if (n % 2 === 0) {
        return t * t;  // 偶数 t ^ 2
    } else {
        return t * t * x; // 奇数 t ^ 2 * x
    }
}

image.png 面试官已经决定就是你了!

当然,这道题还有许多其他解法,你可以前往力扣官方题解,或是其他大佬的题解进行更深一步的学习。

总结

在面试中,不要把面试官当考官,把面试官当老师,实在不会是可以向面试官寻求帮助的。他考验你的不完全是知识点,还会考验你的学习能力和抗压能力。面试中一定会出现不会的情况,学会向他人寻求帮助。如果在面试官的提示下完成了任务,相信他也会认可你的。