记一道字节跳动的算法面试题

前几天有个朋友去面试字节跳动,面试官问了他一道链表相关的算法题,不过他一时之间没做出来,就来问了我一下,感觉这道题还不错,拿来讲一讲。

题目

这其实是一道变形的链表反转题,大致描述如下

给定一个单链表的头节点 head,实现一个调整单链表的函数,使得每K个节点之间为一组进行逆序,并且从链表的尾部开始组起,头部剩余节点数量不够一组的不需要逆序。(不能使用队列或者栈作为辅助)

例如:
链表:1->2->3->4->5->6->7->8->null, K = 3。那么 6->7->8,3->4->5,1->2各位一组。调整后:1->2->5->4->3->8->7->6->null。其中 1,2不调整,因为不够一组。

解答

这道题的难点在于,是从链表的尾部开始组起的,而不是从链表的头部,如果是头部的话,那我们还是比较容易做的,因为你可以遍历链表,每遍历 k 个就拆分为一组来逆序。但是从尾部的话就不一样了,因为是单链表,不能往后遍历组起。不过这道题肯定是用递归比较好做,对递归不大懂的建议看我之前写的一篇文章为什么你学不会递归?告别递归,谈谈我的一些经验,这篇文章写了关于递归的一些套路。

先做一道类似的反转题

在做这道题之前,我们不仿先来看看如果从头部开始组起的话,应该怎么做呢?例如:链表:1->2->3->4->5->6->7->8->null, K = 3。调整后:3->2->1->6->5->4->7->8->null。其中 7,8不调整,因为不够一组。

对于这道题,如果你不知道怎么逆序一个单链表,那么可以看一下我之前写的如何优雅着反转单链表

这道题我们可以用递归来实现,假设方法reverseKNode()的功能是将单链表的每K个节点之间逆序(从头部开始组起的哦);reverse()方法的功能是将一个单链表逆序。

那么对于下面的这个单链表,其中 K = 3。


我们把前K个节点与后面的节点分割出来:


temp指向的剩余的链表,可以说是原问题的一个子问题。我们可以调用reverseKNode()方法将temp指向的链表每K个节点之间进行逆序。再调用reverse()方法把head指向的那3个节点进行逆序,结果如下:

再次声明,如果对这个递归看不大懂的,建议看下我那篇递归的文章

接着,我们只需要把这两部分给连接起来就可以了。最后的结果如下:

代码如下:

    //k个为一组逆序
    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode temp = head;
        for (int i = 1; i < k && temp != null; i++) {
            temp = temp.next;
        }
        //判断节点的数量是否能够凑成一组
        if(temp == null)
            return head;

        ListNode t2 = temp.next;
        temp.next = null;
        //把当前的组进行逆序
        ListNode newHead = reverseList(head);
        //把之后的节点进行分组逆序
        ListNode newTemp = reverseKGroup(t2, k);
        // 把两部分连接起来
        head.next = newTemp;

        return newHead;
    }

    //逆序单链表
    private static ListNode reverseList(ListNode head) {
        if(head == null || head.next == null)
            return head;
        ListNode result = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return result;
    }

回到本题

这两道题可以说是及其相似的了,只是一道从头部开始组起,这道从头部开始组起的,也是 leetcode 的第 25 题。而面试的时候,经常会进行变形,例如这道字节跳动的题,它变成从尾部开始组起,可能你一时之间就不知道该怎么弄了。当然,可能有人一下子就反应出来,把他秒杀了。

其实这道题很好做滴,你只需要先把单链表进行一次逆序,逆序之后就能转化为从头部开始组起了,然后按照我上面的解法,处理完之后,把结果再次逆序即搞定。两次逆序相当于没逆序。

例如对于链表(其中 K = 3)


我们把它从尾部开始组起,每 K 个节点为一组进行逆序。步骤如下

1、先进行逆序


逆序之后就可以把问题转化为从头部开始组起,每 K 个节点为一组进行逆序。

2、处理后的结果如下

3、接着在把结果逆序一次,结果如下

代码如下

public ListNode solve(ListNode head, int k) {
    // 调用逆序函数
    head = reverse(head);
    // 调用每 k 个为一组的逆序函数(从头部开始组起)
    head = reverseKGroup(head, k);
    // 在逆序一次
    head = reverse(head);
    return head;

}

类似于这种需要先进行逆序的还要两个链表相加,这道题字节跳动的笔试题也有出过,如下图的第二题

这道题就需要先把两个链表逆序,再节点间相加,最后在合并了。

总结

关于链表的算法题,在面试的时候听说是挺常考的,大家可以多注意注意,遇到不错的链表算法题,也欢迎扔给我勒。

如果你觉得这篇内容对你挺有启发,为了让更多的人看到这篇文章:不妨

1、点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)

2、关注我和专栏,让我们成为长期关系

3、关注公众号「苦逼的码农」,主要写算法、计算机基础之类的文章,里面已有100多篇原创文章


大部分的数据结构与算法文章被各种公众号转载相信一定能让你有所收获

我也分享了很多视频、书籍的资源,以及开发工具,欢迎各位的关注我的公众号:苦逼的码农,第一时间阅读我的文章。

原文地址:https://www.cnblogs.com/kubidemanong/p/11334017.html

时间: 2024-11-13 11:59:09

记一道字节跳动的算法面试题的相关文章

数据结构与算法面试题80道

由于这些题,实在太火了.所以,应广大网友建议要求,在此把之前已整理公布的前80题, 现在,一次性分享出来.此也算是前80题第一次集体亮相. 此些题,已有上万人,看到或见识到,若私自据为己有,必定为有知之人识破,付出代价. 所以,作者声明: 本人July对以上所有任何内容和资料享有版权,转载请注明作者本人July出处. 向你的厚道致敬.谢谢. ------------------------------------------------------------------------------

若干数据结构 && 算法面试题【四】(更新ing)

这是我的第三个面试题汇总. 想看之前的内容,请移步: http://zhweizhi.blog.51cto.com/10800691/1763237 ( 若干数据结构 && 算法面试题[一](更新完毕)) http://zhweizhi.blog.51cto.com/10800691/1775780 ( 若干数据结构 && 算法面试题[二](更新完毕)) http://zhweizhi.blog.51cto.com/10800691/1787562 ( 若干数据结构 &am

若干数据结构 && 算法面试题【三】(更新中)

这是我的第三个面试题汇总. 想看之前的内容,请移步: http://zhweizhi.blog.51cto.com/10800691/1763237 ( 若干数据结构 && 算法面试题[一](更新完毕)) http://zhweizhi.blog.51cto.com/10800691/1775780 ( 若干数据结构 && 算法面试题[二](更新完毕)) 另外,我的全部刷题代码都在这里: https://github.com/HonestFox/BrushQuestion

算法面试题

在上一篇博客中有原有提到分享一下面试题,最近也是才能新公司入职没多久,忙着熟悉环境,加上前不久出去玩了一趟(顺便写了篇游记,感兴趣的可以看一看).所以一直没时间整理博客,这段时间周末终于闲下来,就趁着周末就记录了几个面试过程中碰到的算法题. 本篇博客不打算介绍那些高逼格的算法(如winnow,bagging,ada boost等等),就讲讲最近在面试过程中遇到的算法题以及面试的时候给出的答案(出场率比较高的算法题我都列出来了,其他的就不说了).算法可以说是解决所有问题的基石.很多东西都可以转换为

九章算法面试题43 直方图内最大矩阵

九章算法官网-原文网址 http://www.jiuzhang.com/problem/43/ 题目 给出一个直方图(如图所示),求出所给直方图中所包含的最大矩阵面积.直方图可以用一个整数数组表示,如上图为[2, 1, 5, 6, 2, 3].每个直方块的宽度均为1.上图中包含的最大矩阵面积为10. 解答 如果对于每个直方块,找到从它开始往左边数第一个比它小的,和往右边数第一个比他小的,则可以确定出以该直方块为最矮一块的矩阵的最大面积.使用数据结构栈,栈中保存递增序列,从左到右依次遍历每个数让其

九章算法面试题31 子数组的最大差

九章算法官网-原文网址 http://www.jiuzhang.com/problem/31/ 题目 给定一个数组,求两个不相交的并且是连续的子数组A和B(位置连续),满足|sum(A) - sum(B)|最大(和之差的绝对值).例如[2, -1, -2, 1, -4, 2, 8],可以得到A=[-1, -2, 1, -4], B=[2, 8],最大差为16. 解答 预处理每个位置往左/右的最大/最小子数组,然后再枚举划分位置,求得所有MaxLeft[i] - MinRight[i+1]和Max

九章算法面试题37 主元素

九章算法官网-原文网址 http://www.jiuzhang.com/problem/37/ 题目 主元素(Majority Number)定义为数组中出现次数严格超过一半的数.找到这个数.要求使用O(1)的额外空间和O(n)的时间. 进阶1:如果数组中存在且只存在一个出现次数严格超过1/3的数,找到这个数.要求使用O(1)的额外空间和O(n)的时间. 进阶2:如果数组中存在且只存在一个出现次数严格超过1/k的数,找到这个数.要求使用O(k)的额外空间和O(n)的时间 解答 采用抵消法.一旦发

九章算法面试题40 不用除法求积

九章算法官网-原文网址 http://www.jiuzhang.com/problem/40/ 题目 给定一个数组A[1..n],求数组B[1..n],使得B[i] = A[1] * A[2] .. * A[i-1] * A[i+1] .. * A[n].要求不要使用除法,且在O(n)的时间内完成,使用O(1)的额外空间(不包含B数组所占空间). 解答 计算前缀乘积Prefix[i] = A[1] * A[2] .. A[i],计算后缀乘积Suffix[i] = A[i] * A[i+1] ..

九章算法面试题50 队列上实现Min函数

九章算法官网-原文网址 http://www.jiuzhang.com/problem/50/ 题目 ?在<九章算法面试题23 栈上实现Min函数>中,我们介绍了在栈上实现一个O(1)的Min方法.那么,如何在队列上实现一个Min方法? 要求,队列除了支持基本的Push(x) Pop()的方法以外,还需要支持Min方法,返回当前队列中的最小元素.每个方法的均摊复杂度为O(1) 解答 在九章面试题49<用栈实现队列>和面试题23<栈上实现Min函数>中,我们讲解到了如何用