移除链表元素
例题203(简单)移除链表元素
注意要点:
- 链表题目涉及增减元素,可以设置虚拟头节点,辅助把链表的所有元素的逻辑操作同化;
- 删除元素,相当于next变成next->next。
下面贴出代码:
CPP版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
while (cur->next)
{
if (cur->next->val == val)
{
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
}
else {cur = cur->next;}
}
head = dummy->next;
delete dummy;
return head;
}
};
C版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
if (!head) {return head;}
struct ListNode* dummyhead = malloc(sizeof(struct ListNode));
dummyhead->next = head;
struct ListNode* tail = dummyhead;
while (tail->next)
{
if (tail->next->val == val)
{
struct ListNode* temp = tail->next;
tail->next = tail->next->next;
free(temp);
}
else {tail = tail->next;}
}
return dummyhead->next;
}
设计链表
例题707(中等)设计链表
注意要点:
- 类中创建时,可以设置private变量:虚拟头结点以及当前链表长度辅助计算;
- 增添和删减元素时,涉及index都需要和链表长度先行比较;
- get的操作需要从头结点开始,也就是虚拟头结点的next节点;其余操作均从虚拟头结点开始。
下面贴出代码:
CPP版本
class MyLinkedList {
public:
struct LinkedNode
{
int val;
LinkedNode* next;
LinkedNode(int val): val(val), next(nullptr){}
};
MyLinkedList() {
dummy = new LinkedNode(0);
size = 0;
}
int get(int index) {
if (index >= size || index < 0) {return -1;}
LinkedNode* cur = dummy->next;
while (index--) {cur = cur->next;}
return cur->val;
}
void addAtHead(int val) {
LinkedNode* newhead = new LinkedNode(0);
newhead->val = val;
LinkedNode* tmp = dummy->next;
dummy->next = newhead;
newhead->next = tmp;
size++;
}
void addAtTail(int val) {
LinkedNode* cur = dummy;
while (cur->next) {cur = cur->next;}
LinkedNode* newtail = new LinkedNode(0);
cur->next = newtail;
newtail->val = val;
newtail->next = nullptr;
size++;
}
void addAtIndex(int index, int val) {
if (index > size) {return;}
if (index < 0) {index = 0;}
LinkedNode* cur = dummy;
while (index--) {cur = cur->next;}
LinkedNode* newnode = new LinkedNode(val);
newnode->next = cur->next;
cur->next = newnode;
size++;
}
void deleteAtIndex(int index) {
if (index < 0 || index >= size) {return;}
LinkedNode* cur = dummy;
while (index--) {cur = cur->next;}
LinkedNode* tmp = cur->next;
cur->next = cur->next->next;
delete(tmp);
tmp = nullptr;
size--;
}
private:
LinkedNode* dummy;
int size;
};
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList* obj = new MyLinkedList();
* int param_1 = obj->get(index);
* obj->addAtHead(val);
* obj->addAtTail(val);
* obj->addAtIndex(index,val);
* obj->deleteAtIndex(index);
*/
C版本
struct ListNode* ListNodeCreate(int val)
{
struct ListNode* node = (struct ListNode* )malloc(sizeof(struct ListNode));
node->val = val;
node->next = NULL;
return node;
}
typedef struct {
struct ListNode* head;
int size;
} MyLinkedList;
MyLinkedList* myLinkedListCreate() {
MyLinkedList* obj = (MyLinkedList* )malloc(sizeof(MyLinkedList));
obj->head = ListNodeCreate(0);
obj->size = 0;
return obj;
}
int myLinkedListGet(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) {return -1;}
struct ListNode* cur = obj->head->next;
while (index--) {cur = cur->next;}
return cur->val;
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
struct ListNode* head = obj->head;
struct ListNode* newhead = ListNodeCreate(val);
newhead->next = head->next;
head->next = newhead;
obj->size++;
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
struct ListNode* cur = obj->head;
while (cur->next) {cur = cur->next;}
struct ListNode* newtail = (struct ListNode* )malloc(sizeof(struct ListNode));
newtail->val = val;
cur->next = newtail;
newtail->next = NULL;
obj->size++;
}
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if (index > obj->size) {return;}
index = fmax(0, index);
struct ListNode* cur = obj->head;
while (index--) {cur = cur->next;}
struct ListNode* newnode = ListNodeCreate(val);
newnode->next = cur->next;
cur->next = newnode;
obj->size++;
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) {return;}
struct ListNode* cur = obj->head;
while (index--) {cur = cur->next;}
struct ListNode* tmp = cur->next;
cur->next = cur->next->next;
free(tmp);
obj->size--;
}
void myLinkedListFree(MyLinkedList* obj) {
struct ListNode* cur = obj->head;
struct ListNode* tmp = NULL;
while (cur)
{
tmp = cur;
cur = cur->next;
free(tmp);
}
free(obj);
}
/**
1. Your MyLinkedList struct will be instantiated and called as such:
2. MyLinkedList* obj = myLinkedListCreate();
3. int param_1 = myLinkedListGet(obj, index);
4. myLinkedListAddAtHead(obj, val);
5. myLinkedListAddAtTail(obj, val);
6. myLinkedListAddAtIndex(obj, index, val);
7. myLinkedListDeleteAtIndex(obj, index);
8. myLinkedListFree(obj);
*/
翻转链表
例题206(简单)翻转链表
注意要点:
- 本题可以不用虚拟头结点,养成加上的习惯避免不时之需;
- 翻转的思路是找到当前节点的前一个节点,并修改当前节点的next指针,然后向后移动一位;所以需要保存pre以及cur->next辅助计算。
下面贴出代码:
CPP版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = nullptr;
while (cur)
{
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
C版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* dummy = (struct ListNode* )malloc(sizeof(struct ListNode));
dummy->next = head;
struct ListNode* cur = dummy->next;
struct ListNode* pre = NULL;
while (cur)
{
struct ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
两两交换链表中的节点
例题24(中等)两两交换链表中的节点
注意要点:
- 设置虚拟头结点,避免头结点的不同处理;
- 交换一共涉及四个节点,分别为待交换的两个节点,以及前一和后一节点;所以需要两个tmp来记录帮助交换(一个也可以,但都是next很容易搞晕)。
下面贴出代码:
CPP版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
while (cur->next && cur->next->next)
{
ListNode* tmp1 = cur->next;
ListNode* tmp2 = cur->next->next->next;
cur->next = tmp1->next;
tmp1->next->next = tmp1;
tmp1->next = tmp2;
cur = tmp1;
}
return dummy->next;
}
};
C版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* swapPairs(struct ListNode* head){
struct ListNode* dummyhead = (struct ListNode* )malloc(sizeof(struct ListNode));
dummyhead->next = head;
struct ListNode* cur = dummyhead;
while (cur->next && cur->next->next)
{
struct ListNode* tmp = cur->next;
struct ListNode* tmp1 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = tmp;
cur->next->next->next = tmp1;
cur = cur->next->next;
}
return dummyhead->next;
}
删除链表的倒数第N个节点
例题19(中等)删除链表的倒数第N个节点
注意要点:
- 避免删除的是头结点,所以设置虚拟头节点辅助计算;
- 通过快慢指针,快指针移动(n+1)次,再与慢指针一起移动直至链表尾部,慢指针所在位置即为倒数(n+1)所在;
- 移动n+1次,就可以直接通过next来删除倒数第n个,避免还要记录pre节点。
下面贴出代码:
CPP版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* slow = dummy;
ListNode* fast = dummy;
while (n--) {fast = fast->next;}
fast = fast->next;
while (fast)
{
slow = slow->next;
fast = fast->next;
}
ListNode* tmp = slow->next;
slow->next = slow->next->next;
delete(tmp);
tmp = nullptr;
return dummy->next;
}
};
C版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* dummyhead = malloc(sizeof(struct ListNode));
dummyhead->next = head;
struct ListNode* slow = dummyhead;
struct ListNode* fast = dummyhead;
while (n--) {fast = fast->next;}
fast = fast->next;
while (fast)
{
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
return dummyhead->next;
}
链表相交
例题160(简单)链表相交
注意要点:
- 通过遍历长度,并使得两链表的当前指针对齐,进而可以同时移动指针判断是否相交;
- 对齐方法:计算链表长度差,并在长链表指针移动长度差个次数,来对齐两个指针;
- 相交是地址相等,不能简单判断值相等。
下面贴出代码:
CPP版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int totalA = 0, totalB = 0;
ListNode* curA = headA;
ListNode* curB = headB;
//统计两个链表的长度
while (curA) {curA = curA->next; totalA++;}
while (curB) {curB = curB->next; totalB++;}
//移动到距离结尾相同距离处
curA = headA, curB = headB;
int sub = totalA - totalB;
if (sub > 0)
{
while (sub--) {curA = curA->next;}
}
else {while (sub++) {curB = curB->next;}}
//判断地址是否相同,而不是val是否相同
while (curA)
{
if (curA == curB) {return curA;}
else
{
curA = curA->next;
curB = curB->next;
}
}
return NULL;
}
};
C版本
/**
1. Definition for singly-linked list.
2. struct ListNode {
3. int val;
4. struct ListNode *next;
5. };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* p1 = malloc(sizeof(struct ListNode));
struct ListNode* p2 = malloc(sizeof(struct ListNode));
p1->next = headA;
p2->next = headB;
int l1 = 0, l2 = 0;
while (p1->next)
{
p1 = p1->next;
l1++;
}
while (p2->next)
{
p2 = p2->next;
l2++;
}
p1 = headA;
p2 = headB;
int delta = l1 - l2;
// printf("delta = %d\n", delta);
// printf("p1 = %d\n", p1);
if (delta >= 0)
{
while(delta--) {p1 = p1->next;}
}
else
{
while(delta++) {p2 = p2->next;}
}
// printf("p1 = %d\n", p1);
while (p1)
{
if (p1 == p2)
{
return p1;
}
p1 = p1->next;
p2 = p2->next;
}
return NULL;
}
环形链表
例题142(中等)环形链表II
注意要点:
- 是否成环的判断:快慢指针,快指针走两步,慢指针走一步,如果能相遇,则证明成环;记录下当前节点;
- 寻找成环点:快指针从当前节点出发,慢指针从头结点出发,移动相同步数,相遇点即为成环点。
这道题涉及到的数学推导可以自行退导一下,不乐意推导就直接记结论就可以做题了。
下面贴出代码:
CPP版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast) //有环
{
//从相遇节点,slow回到head,再次移动同样步数,再次相遇就是成环点
slow = head;
while (slow != fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
}
return NULL;
}
};
C版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
while (slow != head)
{
slow = slow->next;
head = head->next;
}
return head;
}
}
return NULL;
}
总结
再次白嫖代码随想录,这个总结的思维导图真的好!!!!