今天来盘一盘 **链表 ** 这类题目
使用python刷题分类整理的笔记,请参考: https://github.com/lxztju/leetcode-algorithm/tree/v1
针对链表这种数据结构,采用指针访问元素,而且指针只可向一个方向移动, 几种主要的操作:
快慢指针,找到链表的中点
通过pre cur与last三个指针模拟题目中的流程
注意虚拟头节点(在头节点前边新建一个虚拟节点指向头节点)的使用
160 相交链表 (Easy)
206 反转链表 (Easy)
21 合并两个有序链表 (Easy)
83 删除排序链表中的重复元素 (Easy)
234 回文链表 (Easy)
19 删除链表的倒数第N个节点 (Medium)
24 两两交换链表中的节点 (Medium)
445 两数相加 II (Medium)
725 分隔链表 (Medium)
328 奇偶链表 (Medium)
/**
* 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) {
// 哈希表
//将一个链表存储到哈希表中, 遍历另一个链表查找是否存在哈希表中
unordered_set hashset;
// 将A链表存储至哈希表中
while (headA != nullptr){
hashset.insert(headA);
headA = headA->next;
}
// 遍历查找B链表
while (headB != nullptr){
if (hashset.find(headB) != hashset.end())
return headB;
headB = headB->next;
}
return nullptr;
}
};
/**
* 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) {
// 双指针
ListNode* pA = headA;
ListNode* pB = headB;
while (pA != pB){
if (pA == nullptr)
pA = headB;
else
pA = pA->next;
if (pB == nullptr)
pB = headA;
else
pB = pB->next;
}
return pA;
}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
// 直接模拟反转的过程
ListNode* pre = head;
if (head == nullptr ||head->next == nullptr) return head;
ListNode* cur = head->next;
while (cur != nullptr){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
head->next = nullptr;
return pre;
}
};
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
// 设定一个虚拟的头节点, 比较大小,移动指针.
ListNode* dummyHead = new ListNode(0);
ListNode* dummy = dummyHead;
while (l1 && l2){
if ((l1->val) >= (l2->val)){
dummyHead->next = l2;
l2 = l2->next;
}
else{
dummyHead->next = l1;
l1 = l1->next;
}
dummyHead = dummyHead->next;
}
if (l1)
dummyHead->next = l1;
else
dummyHead->next = l2;
return dummy->next;
}
};
直接模拟题目的执行过程. 所谓删除,就是使用指针跳过相对应的重复元素.
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
// 所谓删除,就是使用指针跳过相对应的重复元素.
ListNode* pre = head;
ListNode* cur = head;
while(cur){
// 利用pre指向所有的元素
// 当pre与cur的节点的值相等时, pre不动, cur后移
if( pre->val == cur->val)
cur = cur->next;
// 当二者不等时,pre指向cur, 然后pre cur均后移
else{
pre->next = cur;
pre = pre->next;
cur = cur->next;
}
}
if (pre != cur)
pre->next = nullptr;
return head;
}
};
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector nums;
while (head){
nums.push_back(head->val);
head = head->next;
}
int l = 0, r = nums.size() - 1;
while (l < r){
if (nums[l] != nums[r])
return false;
l++; r--;
}
return true;
}
};
class Solution {
public:
bool isPalindrome(ListNode* head) {
// 找到链表后半部分的头节点
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* lastHeadpre = findLastHead(dummy);
// 反转链表的后半部分
ListNode* lastHead = lastHeadpre->next;
if (lastHead == nullptr) return true;
ListNode* pre = lastHead;
ListNode* cur = lastHead->next;
while (cur){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
lastHead->next = nullptr;
lastHeadpre->next = pre;
// 找到中间节点
ListNode* newlastHeadpre = findLastHead(dummy);
ListNode* newlastHead = newlastHeadpre->next;
// 判断是否回文
while(head && newlastHead && head != newlastHead){
if (head->val != newlastHead->val)
return false;
head = head->next;
newlastHead = newlastHead->next;
}
return true;
}
ListNode* findLastHead(ListNode* head){
// 找到链表后半部分的头节点的前置节点
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next){
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
// 利用滑窗(双指针), 两个指针之间的距离为n
// 当后指针达到nullptr(链表结尾)时, 前指针刚好指向倒数第n个节点的前一个节点
// 利用虚拟头节点,解决删除头节点的问题.
if (!head) return nullptr;
ListNode* dummy = new ListNode(0);
ListNode* first = dummy;
ListNode* second = dummy;
dummy->next = head;
while (second && n >= 0){
second = second->next;
n--;
}
while (second){
first = first->next;
second = second->next;
}
first->next = first->next->next;
return dummy->next;
}
};
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* pre = dummy;
while (head && head->next){
ListNode* cur1 = head;
ListNode* cur2 = head->next;
ListNode* nex = cur2->next;
pre->next = cur2;
cur2->next = cur1;
cur1->next = nex;
pre = cur1;
head = cur1->next;
}
return dummy->next;
}
};
题解: 反转链表,然后相加
题解: 也可以遍历一遍,将结果存储到数组中,然后相加.
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
// 反转两个链表
ListNode* newl1 = reverseListNode(l1);
ListNode* newl2 = reverseListNode(l2);
// 新建结果链表
ListNode* head = new ListNode(0);
ListNode* res = head;
int carry = 0;
while (newl1 || newl2){
int l1val = newl1 ? newl1->val : 0;
int l2val = newl2 ? newl2->val : 0;
long sumval = l1val + l2val + carry;
int nodeval = sumval % 10;
carry = sumval / 10;
head->next = new ListNode(nodeval);
if (newl1) newl1 = newl1->next;
if (newl2) newl2 = newl2->next;
head = head->next;
}
if (carry) head->next = new ListNode(carry);
return reverseListNode(res->next);
}
ListNode* reverseListNode(ListNode* head){
// 反转链表
ListNode* pre = head;
if (head == nullptr) return head;
ListNode* cur = head->next;
while ( cur){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
head->next = nullptr;
return pre;
}
};
class Solution {
public:
vector splitListToParts(ListNode* root, int k) {
// 统计链表的节点数目为cnt
ListNode* head = root;
int cnt = 0;
while (head){
head = head->next;
cnt++;
}
int quotient = cnt / k;
int reminder = cnt % k;
// 那么结果vector中前reminder的元素中存入quotient+1个节点, 后边的存入quotient个节点
vector< ListNode* > res;
ListNode* cur = root;
int count = 0;
int vectorNodeSize = quotient==0 ? reminder : k; // vector中仅仅前reminder中存储节点,后边存储null;
while (count < vectorNodeSize){
// 子链表的开头
ListNode* pre = cur;
//vector中需要保存的节点数目
int num = count < reminder ? quotient + 1 : quotient;
while (num - 1){
cur = cur->next;
num--;
}
ListNode * tmp = cur->next;
cur->next = nullptr;
res.push_back(pre);
cur = tmp;
count++;
}
// 链表后边补充nullptr
for (int i = vectorNodeSize; i < k; i++)
res.push_back(nullptr);
return res;
}
};
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
//新建两个节点,分别作为奇数与偶数子链表的头节点
ListNode* oddhead = new ListNode(0);
ListNode* evenhead = new ListNode(0);
ListNode* odd = oddhead;
ListNode* even =evenhead;
bool flag = true; // 当flag为true时说明此节点为奇数节点, 否则为偶节点
while (head){
if(flag){
ListNode* oddpre = head; // 奇数链表的前置节点
odd->next = head;
flag = false;
odd = odd->next;
}
else{
even->next = head;
flag = true;
even = even->next;
}
head = head->next;
}
// 连接连个链表
odd->next = evenhead->next;
even->next = nullptr;
return oddhead->next;
}
};
微信公众号: 小哲AI
GitHub地址: https://github.com/lxztju/leetcode-algorithm
csdn博客: https://blog.csdn.net/lxztju
知乎专栏: 小哲AI
AI研习社专栏:小哲AI