一、移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
提示:
列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50
```c
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* cur=head;
struct ListNode* pre=NULL;
while(cur)
{
if(cur->val==val)
{
if(cur==head)
{
//cur为第一个节点,采用头删
head=cur->next;
free(cur);
cur=head;
}
else{
//cur不是第一个节点
pre->next=cur->next;
free(cur);
cur=pre->next;
}
}
else
{
pre=cur;
cur=cur->next;
}
}
return head;
}
二、链表的中间结点
给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。(测评系统对该结点序列化表述是 [3,4,5])。
注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.
示例 2:
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6]) 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。
提示:
给定链表的结点数介于 1 和 100 之间。
//给出两个指针,一个fast一个slow,fast走两步,slow走一步,当fast走到头的时候,slow刚到中间位置,则直接返回slow
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* fast=head;
struct ListNode* slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
三、反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2]
输出:[2,1]
示例 3:
输入:head = []
输出:[]
提示:
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head){
ListNode* cur=head;//指向头结点
ListNode* pre=NULL;//用来记录插入之后最后一个节点
ListNode* next=NULL;//用来记录cur的前一个节点
while(cur)
{
next=cur->next;//先将cur的下一个节点保存在next
cur->next=pre;//将节点插入到pre中
pre=cur;
cur=next;
}
return pre;
}
四、链表中倒数第k个结点
描述 输入一个链表,输出该链表中倒数第k个结点
示例1
输入: 1,{1,2,3,4,5}
返回值: {5}
//让fast先向后走K步
//再让slow与fast同时往后移动,直到fast走到链表的末尾,slow所指向的节点则为倒数第K个节点
typedef struct ListNode ListNode;
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
if(NULL==pListHead||k==0)
{
return NULL;
}
ListNode* fast=pListHead;
ListNode* slow=pListHead;
while(k--){
if(NULL==fast)
return NULL;
fast=fast->next;
}
while(fast)
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
五、合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/9499034765c4f49fbe57d710f78bdf0f.png)
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
11 和 12 均按非递减顺序排列
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if(l1==NULL)
{
return l2;
}
if(NULL==l2)
{
return l1;
}
//两个链表都不为空
ListNode* cur1=l1;
ListNode* cur2=l2;
ListNode new;
ListNode* tailNode=&new;
while(cur1&&cur2)
{
if(cur1->val<=cur2->val)
{
tailNode->next=cur1;
cur1=cur1->next;
}
else{
tailNode->next=cur2;
cur2=cur2->next;
}
tailNode=tailNode->next;
}
if(cur1)
tailNode->next=cur1;
else
tailNode->next=cur2;
return new.next;
}
六、复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。 返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。 你的代码 只 接受原链表的头节点 head 作为传入参数。示例1:
示例 3:输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。提示:
0 <= n <= 1000
-10000 <= Node.val <= 10000 Node.random 为空(null)或指向链表中的节点。
typedef struct Node Node;
Node* BuyRandomListNode(int val)
{
Node* newNode=(Node*)malloc(sizeof(Node));
if(NULL==newNode)
return NULL;
newNode->val=val;
newNode->next=NULL;
newNode->random=NULL;
return newNode;
}
struct Node* copyRandomList(struct Node* head) {
if(NULL==head)
return NULL;
Node* newNode=NULL;
//1、在原链表中每个节点后添加相等的新节点
Node* cur=head;
while(cur)
{
newNode=BuyRandomListNode(cur->val);
if(NULL==newNode)
{
return NULL;
}
newNode->next=cur->next;
cur->next=newNode;
cur=newNode->next;
}
//2.给新插入节点的随机指针域进行赋值
cur=head;
while(cur)
{
newNode=cur->next;
if(cur->random)
{
newNode->random=cur->random->next;
}
cur=newNode->next;
}
//3、将新插入的节点从原链表中拆下来
Node* newHead=head->next;
cur=head;
while(cur->next)
{
newNode=cur->next;
cur->next=newNode->next;
cur=newNode;
}
return newHead;
}
七、排序链表删除重复节点
描述
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。
例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
示例1 输入: {1,2,3,3,4,4,5}
返回值:{1,2,5}
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead) {
ListNode* start=pHead;
ListNode* end=start;
ListNode* pre=NULL;
while(start)
{
end=start->next;
//找重复节点的范围
while(end)
{
if(start->val!=end->val)
{
break;
}
end=end->next;
}
//[start,end]区间的节点删除
if(start->next==end)
{
//区间中没有重复的节点
pre=start;
start=end;
}
else{
//有重复的节点
while(start!=end)
{
//头删
if(start==pHead)
{
pHead=start->next;
free(start);
start=pHead;
}
else
{
pre->next=start->next;
free(start);
start=pre->next;
}
}
}
}
return pHead;
}
};