- 首先我们维护一个prev和cur指针,prev先指向NULL,cur用于遍历链表
- prev用于保存cur的前一个节点,当cur->data等于val,然后自己定义一个next指针保存cur->next,这样就可以先free/delete节点,然后让prev->next指向next,之后把next给到cur就行了
- 时间复杂度O(n) 空间复杂度0(1)
struct ListNode* removeElements(struct ListNode* head, int val)
{
//当头不为空并且第一个节点就是val时,直接走到下一个节点
while(head && head->val == val) head = head->next;
struct ListNode* prev = NULL;
struct ListNode* cur = head;
while(cur)
{
if(cur->val == val)
{
struct ListNode* next = cur->next;
prev->next = next;
free(cur);
cur = next;
}
else
{
prev = cur;
cur = cur->next;
}
}
return head;
}
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* prev = NULL;
struct ListNode* cur = head;
while(cur)
{
struct ListNode* next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
思想2:取节点进行头插
时间复杂度O(n) 空间复杂度0(1)
class Solution {
public:
ListNode* reverseList(ListNode* head)
{
ListNode* newnode = nullptr;
ListNode* cur = head;
while(cur)
{
ListNode* next = cur->next;
//取节点进行头插
cur->next = newnode;
newnode = cur;
cur = next;
}
return newnode;
}
};
class Solution {
public:
ListNode* middleNode(ListNode* head)
{
if(head == NULL) return nullptr;
ListNode* slow = head;
ListNode* fast = head;
//快慢指针
while(fast != NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k)
{
ListNode* slow = head;
ListNode* fast = head;
//向让slow走k步
while(k--)
{
//处理k大于链表有效数字情况
if(slow == NULL) return NULL;
slow = slow->next;
}
//之后slow和fast一起走->slow为空则找到倒数第k个节点
while(slow != NULL)
{
slow = slow->next;
fast = fast->next;
}
return fast;
}
};
思想:带头单链表
时间复杂度:O(n) 空间复杂度0(1)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2)
{
ListNode* pHead = new ListNode(-1);
ListNode* tail = pHead;
while(list1 && list2)
{
if(list1->val < list2->val)
{
tail->next = list1;
list1 = list1->next;
}
else
{
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
tail->next = list1 == NULL ? list2 : list1;
return pHead->next;
}
};
思想:开辟二个带哨兵位的单链表,判断原链表的每个数据,如果小于val则放到第一个链表中,反之放到另外一个链表中,然后将他们链接起来,返回哨兵位的下一个节点
class Solution {
public:
ListNode* partition(ListNode* head, int x)
{
ListNode* lessHead, *greaterHead, *lesstail, *greatertail;
lessHead = lesstail = new ListNode(-1);
greaterHead = greatertail = new ListNode(-1);
lesstail->next = greatertail->next = NULL;
ListNode* cur = head;
while(cur != NULL)
{
if(cur->val < x)
{
lesstail->next = cur;
lesstail = cur;
}
else
{
greatertail->next = cur;
greatertail = cur;
}
cur = cur->next;
}
lesstail->next = greaterHead->next;
greatertail->next = NULL;
return lessHead->next;
}
};
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false.(OJ链接)
思路:找中间节点,反转中间节点之后的节点(包括中间节点),与中间节点之前的节点逐个判断是否相等,相等即为回文,不相等即不是回文。
class Solution {
public:
//反转链表成员函数
ListNode* reverse(ListNode* head)
{
ListNode* prev = NULL;
ListNode* cur = head;
while(cur != NULL)
{
ListNode* next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}
bool isPalindrome(ListNode* head)
{
//首先找链表中间节点
ListNode* slow = head;
ListNode* fast = head;
while(fast != NULL && fast->next !=NULL)
{
slow = slow->next;
fast = fast->next->next;
}
//逆置(反转)中间节点后面的节点
slow = reverse(slow);
//判断是否为回文
while(head && slow)
{
if(head->val == slow->val)
{
slow = slow->next;
head = head->next;
}
else
{
return false;
}
}
return true;
}
};
输入两个链表,找出它们的第一个公共结点。(OJ链接)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)
{
ListNode* tailA = headA,*tailB = headB;
int lenA = 1, lenB = 1;
while(tailA->next)
{
tailA = tailA->next;
++lenA;
}
while(tailB->next)
{
tailB = tailB->next;
++lenB;
}
if(tailA != tailB)
return NULL;
//相交,求交点,长的先走差距步,在同时走找交点
ListNode* shortList = headA,*longList = headB;
if(lenA > lenB)
{
longList = headA;
shortList = headB;
}
int gap = abs( lenA-lenB);
while(gap--)
{
longList = longList->next;
}
while(shortList && longList)
{
if(shortList == longList)
return shortList;
shortList = shortList->next;
longList = longList->next;
}
return NULL;
}
};
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点,要求返回这个链表的深度拷贝。(OJ链接)
思路:在原链接每一个节点后面链接一个新开辟的节点,节点里面data与原链表节点的data相同,然后"顺藤摸瓜"把原链表的random->next给到新节点的random,最后剪断原链表和新节点之间的链接,让新开辟的节点成为新的链表,并且重新链接原来的链表。
class Solution
{
public:
Node* copyRandomList(Node* head)
{
Node* cur = head;
while(cur)
{
Node* copyNode = new Node(cur->val);
copyNode->next = cur->next;
cur->next = copyNode;
cur = cur->next->next;
}
cur = head;
while(cur)
{
if(cur->random == NULL)
{
cur->next->random = NULL;
}
else
{
cur->next->random = cur->random->next;
}
cur = cur->next->next;
}
cur = head;
Node* copyHead = NULL;
Node* copytail = NULL;
while(cur)
{
Node* copy = cur->next;
Node* next = copy->next;
//原节点重新链接
cur->next = next;
if(copyHead == NULL)
{
copyHead = copytail = copy;
}
else
{
copytail->next = copy;
copytail = copytail->next;
}
cur = next;
}
return copyHead;
}
};