目录
1.环形链表的约瑟夫问题
2.链表的中间节点
3.合并两个有序链表
4.反转链表
5.移除链表元素
1.环形链表的约瑟夫问题
环形链表的约瑟夫问题_牛客题霸_牛客网 (nowcoder.com)
思路:题目给出结构是环形链表,且题目已经定义好了环形链表的结构。
1.创建环形链表,对应数据为1~n。
2.定义一个变量i从1开始数,当i =m时就将该节点释放并重新连接链表。
3.直到单个节点成环时跳出循环,该节点的数据val即为幸存编号。
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int整型
* @param m int整型
* @return int整型
*/
#include <stdlib.h>
#include <stdio.h>
typedef struct ListNode ListNode;
ListNode* BuyNode(int n)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->val = n;
newnode->next = NULL;
return newnode;
}
ListNode* CreatList(int n)
{
ListNode* phead = BuyNode(1);
ListNode* ptail = phead;
for(int i = 2; i <= n; i++)
{
ListNode* newnode = BuyNode(i);
ptail->next = newnode;
ptail = ptail->next;
}
ptail->next = phead;
return ptail;
}
int ysf(int n, int m ) {
// write code here
ListNode* prev = CreatList(n);
ListNode* pcur = prev->next;
int i = 1;
while(pcur->next != pcur)
{
if(i == m)
{
prev->next = pcur->next;
free(pcur);
pcur = prev->next;
i = 1;
}
else
{
prev = pcur;
pcur = pcur->next;
i++;
}
}
return pcur->val;
}
需要注意的是当m=1是,最后一个人就是幸存者。
2.链表的中间节点
876. 链表的中间结点 - 力扣(LeetCode)
思路:快慢指针法,快指针一次走一步,慢指针一次走两步。
当链表节点为奇数个时,循环结束标志是fast->next == NULL;
当链表节点为偶数个时,循环结束标志是fast == NULL;
要注意循环条件的前后顺序,&&会进行短路求值,如果写成(fast->next && fast),当链表节点为偶数个时,此时fast == NULL,很明显NULL->next是错误的。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
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;
}
3.合并两个有序链表
21. 合并两个有序链表 - 力扣(LeetCode)
思路:创建一个新链表,给定两个指针遍历两条原链表,小的插入。当有剩余的链表时,直接将剩余的全部一起尾插到新链表中,无需一个一个尾插,因为原链表是有序的。
注意:会有一个原链表为空的情况,直接返回另一个原链表。
/**
* 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* plist = NULL;
ListNode* ptail = NULL;
while(list1 && list2)
{
if(list1->val < list2->val)
{
if(plist == NULL)
{
plist = ptail = list1;
list1 = list1->next;
}
else
{
ptail->next = list1;
ptail = ptail->next;
list1 = list1->next;
}
}
else
{
if(plist == NULL)
{
plist = ptail = list2;
list2 = list2->next;
}
else
{
ptail->next = list2;
ptail = ptail->next;
list2 = list2->next;
}
}
}
if(list1)
{
ptail->next = list1;
}
if(list2)
{
ptail->next = list2;
}
return plist;
}
4.反转链表
206. 反转链表 - 力扣(LeetCode)
思路:创建新链表,一个一个头插,要注意连接顺序。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
ListNode* plist = NULL;
ListNode* pcur = head;
while(pcur)
{
if(plist == NULL)
{
plist = head;
pcur = pcur->next;
plist->next = NULL;
}
else
{
ListNode* temp = pcur->next;
pcur->next = plist;
plist = pcur;
pcur = temp;
}
}
return plist;
}
5.移除链表元素
203. 移除链表元素 - 力扣(LeetCode)
思路:创建一个新链表,newhead指向新链表的头节点,newtail指向当前链表的尾节点;
pcur遍历原链表,遇到val跳过,遇到非val链接到新链表。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
struct ListNode* newhead = NULL;
struct ListNode* newtail = NULL;
struct ListNode* pcur = head;
while(pcur)
{
if(pcur->val != val)
{
if(newhead == NULL)
{
newhead = newtail = pcur;
}
else
{
newtail->next = pcur;
newtail = pcur;
}
}
pcur = pcur->next;
}
if(newtail)
{
newtail->next = NULL;
}
return newhead;
}