✈移除链表元素
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
方法一:
遍历链表找到所有等于val的节点,再执行删除操作删除这些节点。
方法二:
双指针
创建两个指针,一个在前,一个在后。
如果前面的指针指向的元素等于val,将后面的指针连上前面指针的下一个指针,前面的指针向前走一格;
如果前面的指针指向的元素不等于val,那么两个指针都向前走一格。
再处理一些特殊情况:
struct ListNode* removeElements(struct ListNode* head, int val) {
ListNode * last = head;
ListNode* tmp = head;
if (last == NULL || (last->next == NULL && last->val == val))//如果是空链表或只有一个val的链表
{
return NULL;
}
else if (last->next == NULL)//如果只有一个节点且不等于val的链表
{
return head;
}
else
{
while (tmp != NULL)
{
if (tmp == last)
{
tmp = tmp->next;
}
if (tmp->val==val)
{
last->next = tmp->next;
tmp = tmp->next;
}
else
{
last = last->next;
tmp = tmp->next;
}
}
if (head->val == val)//如果第一个节点的元素就等于val
{
return head->next;
}
last->next = NULL;
}
return head;
}
原题链接:
移除链表元素
✈反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
双指针法:
创建两个指针,一个在前,一个在后。
每次循环,将前面的指针指向的链表指向在后面的指针,后面的指针赋值成前一个,前一个往下走一格。
struct ListNode* reverseList(struct ListNode* head) {
if (head == NULL || head->next == NULL)//如果只有一个或者没有节点
{
return head;
}
ListNode* pre = head->next;
head->next = NULL;
while (pre != NULL)
{
ListNode* tmp = pre->next;
pre->next = head;
head = pre;
pre = tmp;
}
return head;
}
原题链接:
反转链表
✈合并两个有序链表
双指针法:
创建三个指针,一个指向第一个链表,一个指向第二个链表,一个指向新链表的末尾。
如果第一个指针指向的元素比第二个指针小,那么就让新链表的末尾指向第一个指针,第一个指针再向后移一格,第三个指针向后移一格;
如果第二个指针指向的元素比第一个指针小,那么就让新链表的末尾指向第二个指针,第二个指针再向后移一格,第三个指针向后移一格。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if (list1 == NULL)//先解决其中存在空链表的情况
{
return list2;
}
else if (list2 == NULL)
{
return list1;
}
else
{
ListNode* pre = NULL;
ListNode* finnal = NULL;
if (list1->val <= list2->val)//初始化pre,确定新链表的的头节点finnal
{
finnal = list1;
pre = list1;
list1 = list1->next;
}
else
{
finnal = list2;
pre = list2;
list2 = list2->next;
}
while (list1 != NULL && list2 != NULL)//取元素到新的链表中
{
if (list1->val <= list2->val)
{
pre->next = list1;
pre = list1;
list1 = list1->next;
}
else
{
pre->next = list2;
pre = list2;
list2 = list2->next;
}
}
if (list1 == NULL)
{
pre->next = list2;
}
else
{
pre->next = list1;
}
return finnal;
}
}
原题链接:
合并两个有序链表
✈链表的中间节点
快慢指针法:
创建两个指针,一个快指针,一个慢指针,两个指针初始值为链表的起点。快指针每次走两格,慢指针每次走一格。
如果链表中有奇数个节点,当快指针的下一个节点为NULL时,慢指针走到中间节点的位置;
如果链表中有偶数个节点,当快指针为NULL时,慢指针走到中间节点的位置。
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
ListNode* fast = head;
ListNode* slow = head;
while (1)
{
if (fast == NULL || fast->next == NULL)
{
return slow;
}
fast = fast->next;
fast = fast->next;
slow = slow->next;
}
}
原题链接:
链表的中间节点
✈环形链表的约瑟夫问题
环形链表法:
创建一个n个节点的环形链表,并且第n个节点的存储的元素是n。
删去第m个的值,并且循环n-1次。
typedef struct ListNode {
int val;
struct ListNode* next;
}ListNode;
int ysf(int n, int m) {
ListNode* head = (ListNode*)malloc(sizeof(ListNode));
assert(head);
head->val = 1;
head->next = head;
ListNode* pre = head;
for (int i = 2; i <=n; i++)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
newnode->next = head;
newnode->val = i;
pre->next = newnode;
pre = newnode;
}
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < m-1; j++)
{
pre = pre->next;
}
pre->next = pre->next->next;
}
return pre->val;
}
原题链接:
环形链表的约瑟夫问题