单链表之面试常考的几道题

文章目录

1、单链表删除倒数第K个节点

1.1、题目详解

1.2、暴力解法

1.3、快慢指针法

2、链表反转

2.1、题目详解

2.2、解题方法

3、总结


1、单链表删除倒数第K个节点

1.1、题目详解


      该题目在leetcode上面有,题号是链表的19题,(题目链接)题目的描述我就用leetcode上面的来说啦!大家请看下面这张图

1.2、暴力解法


       其实解决这道题目呢,你可以来个暴力法哈!首先,你可以先遍历一遍链表,求得链表的长度啦!既然链表的长度你都知道了,那么接下来那不就是和玩没啥两样嘛!至于实现过程这里我就不写了,借鉴leetcode官方的解题答案,我们一起看看哈!

int getLength(struct ListNode* head) {
    int length = 0;
    while (head) {
        ++length;
        head = head->next;
    }
    return length;
}

struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
    struct ListNode* dummy = malloc(sizeof(struct ListNode));
    dummy->val = 0, dummy->next = head;
    int length = getLength(head);
    struct ListNode* cur = dummy;
    for (int i = 1; i < length - n + 1; ++i) {
        cur = cur->next;
    }
    cur->next = cur->next->next;
    struct ListNode* ans = dummy->next;
    free(dummy);
    return ans;
}

       我们分析一下时间复杂度和空间复杂度哈!时间复杂度主要在遍历链表的时候花费的时间比较多,所以这里是O(n),至于空间复杂度,不用想哈!那就是O(1) ,为什么是1呢,因为我们这里只用到了1个辅助空间哈!

1.3、快慢指针法


        所谓的快慢指针法,又叫做双指针法,就一一个指针在前面跑,另一个指针在后面跑,只是后面那个指针起步是比较晚的;算啦,自己懒得画图啦,盗用一下官方的图图吧!

 

具体的实现代码我这里仅仅提供函数的实现部分,若是想看全部的源码文件,请点击(源码链接)

Node *RemoveNode(Node *L, int location)
{
    Node *me = NULL, *first = NULL, *second = NULL, *pre = NULL;
    me = L;
    first = L->next;        //快指针
    second = L->next;       //慢指针
    for(int i = 0; i < location; i++)
    {
        first = first->next;
    }

    while(first)        //判断快指针是否为空
    {
        first = first->next;
        pre = second;           //记录删除节点的前驱指针
        second = second->next;
    }
    pre->next = second->next;
    free(second);
    return me;
}

       第二版代码,这版的代码是根据上一篇文章的基础上进行实现的,因为我比较喜欢能在函数体内部解决的,绝不在函数体外部下功夫,所以我这里使用的是二级指针传参,具体的用法请看下面的代码,有看不懂的地方,你可以对照着上一篇文章来看,还是看不懂的话,请在评论区留言!

//删除单链表中倒数第n个节点(利用双指针--快慢指针)
void DeleteSpecialNode(LinkList *L, int n)
{
    LinkList me, fast_ptr, slow_ptr;
    int i;
    fast_ptr = (*L)->next;
    slow_ptr = (*L)->next;
    for(i = 1; i < n; i++)
    {
        fast_ptr = fast_ptr->next;
    }
    while(fast_ptr->next != NULL)
    {
        me = slow_ptr;
        slow_ptr = slow_ptr->next;
        fast_ptr = fast_ptr->next;
    }
    me->next = slow_ptr->next;
    free(slow_ptr);
}

 

2、链表反转


2.1、题目详解

链表反转的问题,就是将链表每个节点的指向颠倒过来!就像下面图所示的这个样子!

2.2、解题方法

看懂了吧!最简单的方法当然是新建一个链表,然后采用头插法,这个就得到了原链表的逆序啦!这个过程我就不贴代码啦!自己下去动手写哈!而我要讲的方法是使用双指针的方法,来将链表就地逆置,这个过程菜哥用Ipad画了个图图给大家看!(画的图有点丑,大家见谅哈!)

其实看懂这张图,你就理解了这个是怎么实现原地反转的啦!接下来就是贴代码环节啦!

//单链表反转(原地逆置)
Status RevserseLinkList(LinkList *L)
{
    LinkList pre = NULL, cur = NULL,me = NULL;
    pre = (*L)->next;
    cur = pre->next;
    me = pre;
    while(cur != NULL)
    {
        pre->next = cur->next;
        cur->next = me;
        me = cur;
        cur = pre->next;
    }
    (*L)->next = me;
    return OK;
}

好啦,这题就讲到这里啦,其实还有很多的解法,大家可以去找找资料,学习一下哈! 

3、总结


       这道题呢,总体上的难度处于中等水准,可能第一种求解方法大家比较容易想到,第二种方法可能了解过快慢指针的小伙伴才会想到吧!最近菜哥会分享一些leetcode上面的一些题目的解法,为啥要分享呢,因为菜哥正处于求职阶段,所以刷刷题,练一下基本功哈!

        对啦!希望看到本篇文章的大佬们能点点赞哈!其次,要是有小伙伴有更好的解题思路,欢迎在评论区留言哈!菜哥会看每一条评论哈!(关注菜哥!你就会变得原来越(不菜哦)!加油⛽️) 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值