移除链表元素
链接: link
思路一
遍历原链表,将值为val的节点释放掉
思路二
找值不为val的值,尾插到新的链表中
注意点:
- 如果val是在最后,那么尾插到新链表时会把后面跟的val也拿下来,要考虑。
- 如果输入的是空链表,不能直接解引用,要判断是否为空。
代码实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
//创建一个空链表
ListNode* newHead,*newTail;
newHead=newTail=NULL;
//遍历原链表
ListNode* pcur=head;
while(pcur)
{
//找值不为val的节点,尾插到新链表中
if(pcur->val!=val)
{
//链表为空
if(newHead==NULL)
{
newHead=newTail=pcur;
}
//链表不为空
else
{
newTail->next=pcur;
newTail=newTail->next;//更新一下
}
}
pcur=pcur->next;
}
if(newTail)
newTail->next=NULL;
return newHead;
}
反转链表
链接: link
思路一
创建新的链表,遍历原链表节点,将原链表中的节点拿过来头插。
思路二
创建三个指针,完成原链表的翻转
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode *pre,*curr=NULL;
while(head)
{
pre=curr;
curr=head;
head=head->next;
curr->next=pre;
}
return curr;
}
链表的中间结点
链接: link
思路一
遍历,count计节点数,直接返回(count/2)节点的next节点
思路二
快慢指针:
slow每次走一步,fast每次走两步(2slow=fast)
奇数情况
偶数情况
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
//创建快慢指针
ListNode*slow=head;
ListNode*fast=head;
while(fast&&fast->next)//确保fast->next->next至少有个NULL
{
slow=slow->next;
fast=fast->next->next;
}
//此时slow刚好指向的就是中间节点
return slow;
}
合并两个有序链表
链接: link
思路
利用原先两个链表创造一个新链表:原先两链表比较,小的插入
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//判空
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
ListNode* l1=list1;
ListNode* l2=list2;
//创造新的链表
ListNode* newHead,*newTail;
newHead=newTail=NULL;
while(l1&&l2)
{
if(l1->val<l2->val)
{
if(newHead==NULL) //l1拿下来尾插
{
newHead=newTail=l1;
}
else
{
newTail->next=l1;
newTail=newTail->next;
}
l1=l1->next;
}
else
{
if(newHead==NULL)//l2拿下来尾插
{
newHead=newTail=l2;
}
else
{
newTail->next=l2;
newTail=newTail->next;
}
l2=l2->next;
}
}
if(l2)
{
newTail->next=l2;
}
if(l1)
{
newTail->next=l1;
}
return newHead;
}
上述代码存在空链表和非空链表两种情况所以会有重复判断代码。
解决思路为让新链表不为空。
//创造新的链表
ListNode* newHead,*newTail;
// newHead=newTail=NULL;
newHead=newTail=(ListNode*)malloc(sizeof(ListNode));
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//判空
if(list1==NULL)
{
return list2;
}
if(list2==NULL)
{
return list1;
}
ListNode* l1=list1;
ListNode* l2=list2;
//创造新的链表
ListNode* newHead,*newTail;
newHead=newTail=NULL;
while(l1&&l2)
{
if(l1->val<l2->val)
{
newTail->next=l1;
newTail=newTail->next;
l1=l1->next;
}
else
{
newTail->next=l2;
newTail=newTail->next;
l2=l2->next;
}
}
if(l2)
{
newTail->next=l2;
}
if(l1)
{
newTail->next=l1;
}
//return newHead->next;//第一个是随机定的,从第二个开始
//进一步完善 ,释放掉申请的空间
ListNode* ret=newHead->next;
free(newHead);
newHead=NULL;
return ret;
}
环形链表的约瑟夫问题
链接: link
思路
创建带环链表,计数。
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @param m int整型
* @return int整型
*/
typedef struct ListNode ListNode;
//创建节点
ListNode* buyNode(int x)
{
ListNode* node=(ListNode*)malloc(sizeof(ListNode));
if(node==NULL)
{
exit(1);
}
node->val=x;
node->next=NULL;
return node;
}
//创建带环链表
ListNode* createCircle(int n)
{
//先创建第一个节点
ListNode* phead=buyNode(1);
ListNode* ptail=phead;
for(int i=2;i<=n;i++)
{
ptail->next=buyNode(i);
ptail=ptail->next;
}
//首尾相连,链表成环
ptail->next=phead;
return ptail;
}
int ysf(int n, int m ) {
// write code here
ListNode* prev=createCircle(n);
ListNode*pcur=prev->next;
int count=1;//pcur已经指向了1
//当链表中只有一个节点的情况
while(pcur->next!=pcur)
{
if(count==m)
{
//销毁pcur节点
prev->next=pcur->next;
pcur=prev->next;
count=1;
}
else
{
//此时不需要销毁节点
prev=pcur;
pcur=pcur->next;
count++;
}
}
//此时剩下的一个节点就是要返回的节点的值
return pcur->val;
}
分割链表
链接: link
思路一
在原链表上进行修改。
若pcur节点的值小于x,往后走。
若pcur节点的值大于或等于x,尾插在原链表后,删除旧节点。
思路二
创造新链表,遍历原链表
若pcur节点的值小于x,头插在新链表中
若pcur节点的值大于或等于x,尾插在新链表中。
思路三
创建新链表:小链表和大链表。
将小链表的尾节点和大链表的第一个节点首位相连。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
if(head==NULL)
{
return head;
}
//创建两个带头链表
ListNode* lessHead,*lessTail;
ListNode*greaterHead,*greaterTail;
lessHead=lessTail=(ListNode*)malloc(sizeof(ListNode));//这是哨兵
greaterHead=greaterTail=(ListNode*)malloc(sizeof(ListNode));
//遍历原链表,将原链表中的节点尾插到大小链表中
ListNode*pcur=head;
while(pcur)
{
if(pcur->val<x)
{
//尾插到小链表中
lessTail->next=pcur;
lessTail=lessTail->next;
}
else
{
//尾插到大链表中
greaterTail->next=pcur;
greaterTail=greaterTail->next;
}
pcur=pcur->next;
}
//修改大链表的尾节点的next指针指向
greaterTail->next=NULL;//若不加这一行,代码会出现死循环+next指针初始化
//小链表的尾节点和大链表的第一个有效节点首尾相连
lessTail->next=greaterHead->next;
ListNode*ret=lessHead->next;
free(lessHead);
free(greaterHead);
lessHead=greaterHead=NULL;
return ret;
}