*题目编号为Leetcode中对应的题号。
某位大佬的Leetcode题解参考链接
链表
- 给一个节点需要注意:
- 如果是头节点、尾节点或者空节点等特殊情况该如何处理
-
(206反转链表) 反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (head == NULL)
return head;
ListNode* curr = head;
ListNode* next = head->next;
ListNode* pre = NULL;
while (true) {
curr->next = pre;
if (next == NULL)// 如果next为空则不移动
break;
pre = curr;
curr = next;
next = next->next;
}
return curr;
}
};
-
(92反转链表II) 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明: 1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4 输出: 1->4->3->2->5->NULL
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode* dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode* pre = dummyHead;
for(int i = 0; i < m - 1; i ++, pre = pre->next);
ListNode* tail = pre->next;
ListNode* left;
pre->next = reverse(pre->next, n - m, left);
tail->next = left;
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
private:
ListNode* reverse(ListNode* head, int index, ListNode* &left){
if(index == 0){
left = head->next;
return head;
}
ListNode* tail = head->next;
ListNode* ret = reverse(head->next, index - 1, left);
tail->next = head;
return ret;
}
};
-
(83删除排序链表中的重复元素) 给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 :
输入: 1->1->2 输出: 1->2
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* cur = head;
while(cur && cur->next){
if(cur->val == cur->next->val) cur->next = cur->next->next;
else cur = cur->next;
}
return head;
}
};
-
(86分隔链表) 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3 输出: 1->2->2->4->3->5
/// Linear Scan
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* dummyHead1 = new ListNode(-1);
ListNode* dummyHead2 = new ListNode(-1);
ListNode* prev1 = dummyHead1;
ListNode* prev2 = dummyHead2;
for(ListNode* cur = head ; cur != NULL ;){
if(cur->val < x){
prev1->next = cur;
cur = cur->next;
prev1 = prev1->next;
prev1->next = NULL;
}
else{
prev2->next = cur;
cur = cur->next;
prev2 = prev2->next;
prev2->next = NULL;
}
}
prev1->next = dummyHead2->next;
ListNode* ret = dummyHead1->next;
delete dummyHead1;
delete dummyHead2;
return ret;
}
};
-
(328奇偶链表) 给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例:
输入: 1->2->3->4->5->NULL 输出: 1->3->5->2->4->NULL 输入: 2->1->3->5->6->4->7->NULL 输出: 2->3->6->7->1->5->4->NULL
说明:
- 应当保持奇数节点和偶数节点的相对顺序。
- 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
/// Split the Linked List into two and then merge
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if(head == NULL || head->next == NULL || head->next->next == NULL)
return head;
ListNode* dummyHead1 = new ListNode(-1);
ListNode* dummyHead2 = new ListNode(-1);
ListNode* p1 = dummyHead1;
ListNode* p2 = dummyHead2;
ListNode* p = head;
for(int i = 0; p; i ++)
if(i % 2 == 0){
p1->next = p;
p = p->next;
p1 = p1->next;
p1->next = NULL;
}
else{
p2->next = p;
p = p->next;
p2 = p2->next;
p2->next = NULL;
}
p1->next = dummyHead2->next;
ListNode* ret = dummyHead1->next;
delete dummyHead1;
delete dummyHead2;
return ret;
}
};
-
(2两数相加) 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465 = 807
/// Create new LinkedList for result
/// Time Complexity: O(n)
/// Space Complexity: O(n)
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *p1 = l1, *p2 = l2;
ListNode *dummyHead = new ListNode(-1);
ListNode* cur = dummyHead;
int carried = 0;
while(p1 || p2 ){
int a = p1 ? p1->val : 0;
int b = p2 ? p2->val : 0;
cur->next = new ListNode((a + b + carried) % 10);
carried = (a + b + carried) / 10;
cur = cur->next;
p1 = p1 ? p1->next : NULL;
p2 = p2 ? p2->next : NULL;
}
cur->next = carried ? new ListNode(1) : NULL;
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
-
(445两数相加II) 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 8 -> 0 -> 7
/// Using Stack
/// Time Complexity: O(m + n + max(m, n))
/// Space Complexity: O(m + n)
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
stack<ListNode*> stack1, stack2, stack;
ListNode* node = l1;
while(node) stack1.push(node), node = node->next;
node = l2;
while(node) stack2.push(node), node = node->next;
int carry = 0;
while(!stack1.empty() || !stack2.empty() || carry){
int x = 0;
if(!stack1.empty()) x += stack1.top()->val, stack1.pop();
if(!stack2.empty()) x += stack2.top()->val, stack2.pop();
x += carry;
stack.push(new ListNode(x % 10));
carry = x / 10;
}
ListNode* ret = stack.top(), *cur = ret;
stack.pop();
while(!stack.empty())
cur->next = stack.top(), cur = cur->next, stack.pop();
return ret;
}
};
-
(203移除链表元素) 删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6 输出: 1->2->3->4->5
// 基础版
ListNode* removeElements(ListNode* head, int val) {
if (head == NULL)
return NULL;
while (head != NULL && head->val == val) {
ListNode* delNode = head;
head = delNode->next;
delete delNode;
}
if (head == NULL)
return NULL;
ListNode* curr = head;
while (curr->next != NULL) {
if (curr->next->val == val) {// 删除下一个节点
ListNode* delNode = curr->next;
curr->next = delNode->next;
delete delNode;
}
else
curr = curr->next;
}
return head;
}
// 设立虚拟头结点
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead=new ListNode(0);
dummyHead->next=head;
ListNode* curr=dummyHead;
while(curr->next != NULL){
if(curr->next->val == val){
ListNode* delNode=curr->next;
curr->next=delNode->next;
delete delNode;
}
else
curr=curr->next;
}
ListNode* ret=dummyHead->next;
delete dummyHead;
return ret;
}
-
(82删除排序链表中的重复元素II) 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。
示例:
输入: 1->2->3->3->4->4->5 输出: 1->2->5 输入: 1->1->1->2->3 输出: 2->3
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode* prev = dummyHead;
ListNode* cur = prev->next;
while(cur){
int num = 0;
ListNode* p = cur;
while(p && p->val == cur->val){
num ++;
p = p->next;
}
if(num > 1)
prev->next = p;
else
prev = cur;
cur = p;
}
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
-
(21合并两个有序链表) 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4
/// Iterative
/// Time Complexity: O(len(l1) + len(l2))
/// Space Complexity: O(1)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dummyHead = new ListNode(-1);
ListNode* p = dummyHead;
ListNode* l1p = l1;
ListNode* l2p = l2;
while(l1p != NULL && l2p != NULL){
if(l1p->val < l2p->val){
p->next = l1p;
l1p = l1p->next;
}
else{
p->next = l2p;
l2p = l2p->next;
}
p = p->next;
}
if(l1p != NULL)
p->next = l1p;
else
p->next = l2p;
ListNode* ret = dummyHead->next;
dummyHead->next = NULL;
delete dummyHead;
return ret;
}
};
-
(24两两交换链表中的节点) 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* pre = dummyHead;
// 交换pair1和pair2两个节点
while (pre->next && pre->next->next) {
ListNode* pair1 = pre->next;
ListNode* pair2 = pair1->next;
ListNode* end = pair2->next;
// 交换
pre->next = pair2;
pair2->next = pair1;
pair1->next = end;
// 前移
pre = pair1;
}
ListNode* retNode = dummyHead->next;
delete dummyHead;
return retNode;
}
-
(25K个一组翻转链表) 给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5 当 k = 2 时,应当返回: 2->1->4->3->5 当 k = 3 时,应当返回: 3->2->1->4->5
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummyHead = new ListNode(-1);
dummyHead->next = head;
ListNode* pre = dummyHead;
while(pre && pre->next){
ListNode* end = pre;
int i;
for(i = 0; i < k && end->next; i ++)
end = end->next;
if(i != k) break;
ListNode* next = end->next;
// reverse from pre->next to end
ListNode* rhead = reverse(pre->next, end);
ListNode* tail = pre->next;
pre->next = rhead;
tail->next = next;
pre = tail;
}
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
private:
ListNode* reverse(ListNode* head, ListNode* end){
if(head == end) return head;
ListNode* rhead = reverse(head->next, end);
head->next->next = head;
return rhead;
}
};
-
(148排序链表) 在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例:
输入: 4->2->1->3 输出: 1->2->3->4 输入: -1->5->3->4->0 输出: -1->0->3->4->5
/// Merge Sort Top Down
/// Time Complexity: O(nlogn)
/// Space Complexity: O(logn)
class Solution {
public:
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
ListNode* slow = head;
ListNode* fast = head->next;
while(fast && fast->next){
slow = slow->next;
fast = fast->next->next;
}
ListNode* head2 = slow->next;
slow->next = NULL;
head = sortList(head);
head2 = sortList(head2);
return merge(head, head2);
}
private:
ListNode* merge(ListNode* a, ListNode* b){
ListNode* dummyHead = new ListNode(-1);
ListNode *p1 = a, *p2 = b, *p = dummyHead;
while(p1 && p2)
if(p1->val < p2->val){
p->next = p1;
p1 = p1->next;
p = p->next;
p->next = NULL;
}
else{
p->next = p2;
p2 = p2->next;
p = p->next;
p->next = NULL;
}
if(p1) p->next = p1;
if(p2) p->next = p2;
ListNode* ret = dummyHead->next;
delete dummyHead;
return ret;
}
};
-
(237删除链表中的节点) 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
示例 :
输入: head = [4,5,1,9], node = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
// 将所有节点赋值为下一个节点的值
void deleteNode(ListNode* node) {
if(node==NULL)
return;
ListNode* next=node->next;
ListNode* nnext=next->next;
while(nnext!=NULL){
node->val=next->val;
node=next;
next=node->next;
nnext=next->next;
}
node->val=next->val;
node->next=NULL;
}
// 将当前节点赋值为下一节点,然后删除下一节点
void deleteNode(ListNode* node) {
if(node==NULL)// 删除空节点
return;
if(node->next=NULL){// 删除尾节点
delete node;
node=NULL;
return;
}
ListNode* delNode=node->next;
node->val=delNode->val;
node->next=delNode->next;
delete delNode;
}
-
(19删除链表的倒数第n个节点) 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.
// 先遍历一遍求链表长度,然后删除第size-n个节点
ListNode* removeNthFromEnd(ListNode* head, int n) {
// 计算链表的长度
int size=0;
ListNode* curr=head;
while(curr!=NULL){
curr=curr->next;
size++;
}
// 删除第size-n个节点
int count=0;
ListNode* dummyHead=new ListNode(0);// 设立虚拟头结点
curr=dummyHead;
while(count<size-n){// 要删的是curr->next节点
curr=curr->next;
count++;
}
ListNode* delNode=curr->next;
curr->next=delNode->next;
delete delNode;
ListNode* retNode = dummyHead->next;
delete dummyHead;
return retNode;
}
// 遍历一遍链表
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead=new ListNode(0);
dummyHead->next=head;
ListNode* l=dummyHead;
ListNode* r=dummyHead;
// 拉开l与r的距离
for(int i=0;i<n;i++)
r=r->next;
// 将r移到链表尾,l保持与r的距离
while(r->next!=NULL){
r=r->next;
l=l->next;
}
// 删除l->next节点
ListNode* delNode=l->next;
l->next=delNode->next;
delete delNode;
// 返回头节点
ListNode* ret=dummyHead->next;
delete dummyHead;
return ret;
}
-
(61旋转链表) 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例:
输入: 1->2->3->4->5->NULL, k = 2 输出: 4->5->1->2->3->NULL 解释: 向右旋转 1 步: 5->1->2->3->4->NULL 向右旋转 2 步: 4->5->1->2->3->NULL
/// Brute Force
/// Two Pointers
///
/// Time Complexity: O(N)
/// Space Complexity: O(1)
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(head == NULL)
return NULL;
int len = get_len(head);
k = k % len;
ListNode* end = head;
for(int i = 0 ; i < k ; i ++)
end = end->next;
ListNode* start = head;
while(end->next != NULL){
start = start->next;
end = end->next;
}
end->next = head;
head = start->next;
start->next = NULL;
return head;
}
private:
int get_len(ListNode* head){
int res = 0;
while(head){
res ++;
head = head->next;
}
return res;
}
};
-
(143重排链表) 给定一个单链表 L:L0→L1→…→L(n-1)→Ln ,将其重新排列后变为: L0→Ln→L1→Ln-1→L2→L(n-2)→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定链表 1->2->3->4, 重新排列为 1->4->2->3. 给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
class Solution {
public:
void reorderList(ListNode* head) {
if(!head || !head->next) return;
ListNode* slow = head, *fast = head;
while(fast->next && fast->next->next)
slow = slow->next, fast = fast->next, fast = fast->next;
ListNode* head1 = head, *head2 = slow->next;
slow->next = NULL;
head2 = reverse(head2);
ListNode* dummyHead = new ListNode(-1);
ListNode* cur= dummyHead, *cur1 = head1, *cur2 = head2;
for(int i = 0; cur1 || cur2; i ++)
if(i % 2 == 0) cur->next = cur1, cur = cur->next, cur1 = cur1->next;
else cur->next = cur2, cur = cur->next, cur2 = cur2->next;
head = dummyHead->next;
}
private:
ListNode* reverse(ListNode* node){
if(!node->next) return node;
ListNode* ret = reverse(node->next);
node->next->next = node;
node->next = NULL;
return ret;
}
};
-
(234回文链表) 请判断一个链表是否为回文链表。
示例:
输入: 1->2 输出: false 输入: 1->2->2->1 输出: true
/// Two Pointers to Reverse and Traverse
/// Time Complexity: O(n)
/// Space Complexity: O(1)
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head == NULL || head->next == NULL)
return true;
ListNode* slow = head;
ListNode* fast = head;
while(fast->next != NULL && fast->next->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
slow->next = reverse(slow->next);
slow = slow->next;
ListNode* cur = head;
while(slow != NULL){
if(cur->val != slow->val)
return false;
else{
slow = slow->next;
cur = cur->next;
}
}
return true;
}
private:
ListNode* reverse(ListNode* head){
if(head == NULL || head->next == NULL)
return head;
ListNode* pre = head;
ListNode* cur = head->next;
ListNode* next = cur->next;
head->next = NULL;
while(true){
cur->next = pre;
pre = cur;
cur = next;
if(cur == NULL)
break;
next = cur->next;
}
return pre;
}
};