本文主要对单链表的一些OJ题进行详解,每个都有详细的图解。
文章目录
- (1) [删除链表中等于给定值 val 的所有结点](https://leetcode.cn/problems/remove-linked-list-elements/)
- (2) [反转一个单链表](https://leetcode.cn/problems/reverse-linked-list/description/)
- (3) [合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/description/)
- (4) [链表的中间节点](https://leetcode.cn/problems/middle-of-the-linked-list/description/)
- (5) [链表中倒数第k个结点](https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking)
- (6) [链表分割](https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking)
- (7) [链表的回文结构](https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking)
- (8) [相交链表](https://leetcode.cn/problems/intersection-of-two-linked-lists/description/)
- (9) [环形链表-判断有环](https://leetcode.cn/problems/linked-list-cycle/description/)
- (10) [环形链表-找入环点](https://leetcode.cn/problems/linked-list-cycle-ii/description/)
- (11) [复杂带随机指针的链表](https://leetcode.cn/problems/copy-list-with-random-pointer/description/)
(1) 删除链表中等于给定值 val 的所有结点
思路1:定义两个指针newhead和tail,还有一个cur遍历数组,不相等就尾插,相等就跳过
思路2:在思路1的基础上定义哨兵位头节点,便于尾插
//思路1:
struct ListNode* removeElements(struct ListNode* head, int val)
{
struct ListNode* cur = head;
struct ListNode* newhead = NULL;
struct ListNode* tail = NULL;
while (cur)
{
if(cur->val != val)
{
if(tail==NULL)
{
tail = newhead = cur;
}
else
{
tail->next = cur;
tail = tail->next;
}
cur = cur->next;
}
else
{
//删除
struct ListNode* next = NULL;
next = cur->next;
free(cur);
cur = next;
}
}
if(tail!=NULL)
tail->next = NULL;
return newhead;
}
//思路2:定义哨兵位头节点
struct ListNode* removeElements(struct ListNode* head, int val)
{
if(head ==NULL)
return NULL;
struct ListNode* guard,*tail;
guard = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
guard->next = NULL;
struct ListNode* cur = head;
while(cur)
{
if(cur->val != val)
{
tail->next = cur;
tail = tail->next;
cur = cur->next;
}
else
{
cur = cur->next;
}
}
tail->next = NULL;
struct ListNode* newhead = guard->next;
free(guard);
return newhead;
}
(2) 反转一个单链表
思路1:三指针,将链表直接翻转过来
思路2:双指针,创建一个新链表,然后头插
思路3:递归
思路3:递归
struct ListNode* _reverseList(struct ListNode* prev,struct ListNode* cur)
{
if(cur == NULL)
{
return prev;
}
struct ListNode* next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
return _reverseList(prev,cur);
}
struct ListNode* reverseList(struct ListNode* head)
{
// if(head == NULL)
// {
// return NULL;
// }
struct ListNode* prev = NULL;
struct ListNode* cur = head;
return _reverseList(prev,cur);
}
(3) 合并两个有序链表
思路:
(4) 链表的中间节点
思路:
(5) 链表中倒数第k个结点
思路:
(6) 链表分割
思路:
(7) 链表的回文结构
思路:调用其他函数
(8) 相交链表
思路:
(9) 环形链表-判断有环
思路:
为什么一定要走两步:
(10) 环形链表-找入环点
思路1:一个指针从相遇点走,一个指针从头走,相遇点就是入环点
思路2:将相遇点的下一个cur = meet->next位置置为NULL,以cur为头,和原来的链表找交点
(11) 复杂带随机指针的链表
这个题目超级难!!!!
思路:
1:将拷贝节点链接在原链表后面
2:设置拷贝节点的random
3:将拷贝节点解下来,形成新的链表(尾插),并且恢复原链表
每一步详细图解: