您的位置:首页 > 职场人生

一道看似简单的面试算法题所隐藏的潜在意图

2015-11-11 17:45 387 查看
大家面试历程中有没有经历过类似情况,面试官给出一道算法题,看似不难,你三下五除二搞定了,时间和空间效率都是最优,你乐呵呵以为offer,已经到手,结果左等右等,望穿秋水,面试的结果却是无疾而终,你反复确认,觉得题做得没错啊,为什么会失败呢。我就有过类似的情况,后来反复思考,才明白,其实我没明白简单的表面其实隐藏着潜在的考察点。

举个栗子,一道常用的面试算法题是:给你一个链表,让你将链表反转,例如链表原来是1->2->3, 经过算法后变成3->2->1.常用的做法是,先用三个指针指向链表的前三个节点,将第一第二个节点的链接反转后,把第二个指针赋予第一个指针,第三个指针赋予第二个指针,然后继续对前两个节点做反转。这种做法,时间复杂度是O(n), 空间复杂度是O(1). 表面上看起来很完美,但如果你仅仅这么做的话,结果很可能是没戏的。据我了解,微软面试时出过这道题。

我曾经在这道题上摔过交,一直想不通为何,直到有一天才突然意识到潜在的问题。想想看如果面试官要求你在解题时只能用两个指针,你会怎么做。这道表面看起来简单的题,隐藏着算法设计中常用的divide and conque 的技术手段,其思想内核是面对一个大问题,如果大问题可以分解成一些容易解决的小问题,把解决了的小问题合并起来就能得到大问题的解,快速排序就是这一思想的典型特例。

回到这一问题,我们如何用分而治之的技术去更好的解决它呢。对于链表:

node1->node2->….->nodeN; 如果假定,以node2开始的子链表都已经被反转过了,那么要反转整个链表,其实只要把node1指向node2的指针反转一下就可以了,这么做比原来用三个指针顺着来的办法简单多了,而且这种做法,就正好只用了两个指针,以下是根据这种算法编写的伪码:

class ListNode  {
int v;
ListNode next;
}
ListNode reversedListHead = null;

ListNode reverseList(ListNode head)  {
if (head == null || head.next == null)  {
reversedListHead = head;
return head;
}

ListNode subList = reverseList(head.next);
subList.next = head;
head.next = null;
return head;
}


reversedListHead 就是反转后,链表的头。相比较一下,第二种做法,是不是比第一种要简单多了,如果使用第一种的话,我们还得判断链表的长度要不要大于3, 如果链表是空或只有一个节点,还得要有相应的处理,而第二中做法就无需做那么多琐碎的判断,同时空间和时间复杂度也并没有增加。

由此可见,面试时,如果感觉题目比较简单的话,我们还是要多一个心眼,不要轻易被表面的简单所迷惑,面试官常会挖一些坑让你跳,只有你跳过了,那offer才会跳到你手里。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: