文章目录
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上面的一些题目的解法,为啥要分享呢,因为菜哥正处于求职阶段,所以刷刷题,练一下基本功哈!
对啦!希望看到本篇文章的大佬们能点点赞哈!其次,要是有小伙伴有更好的解题思路,欢迎在评论区留言哈!菜哥会看每一条评论哈!(关注菜哥!你就会变得原来越(不菜哦)!加油⛽️)