206. 反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == NULL)
return head;
ListNode *Dummy = new ListNode(0);
Dummy->next = head;
while(head->next != NULL)
{
ListNode *node = head->next;
head->next = node->next;
node->next = Dummy->next;
Dummy->next = node;
}
return Dummy->next;
}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre=NULL;
ListNode* cur=head;
while(cur != NULL)
{
ListNode* next=cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
92. 反转链表 II
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
采用头插法将后面的元素插到前面来,时间复杂度O(n)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
ListNode *dummy = new ListNode(0), *cur;
dummy -> next = head;
ListNode * pre = dummy;
for (int i = 0; i < m - 1; i++) {
pre = pre -> next;
}
cur = pre -> next;
for (int i = 0; i < n - m; i++) {
ListNode* temp = cur -> next;
cur -> next = temp -> next;
temp -> next = pre -> next;
pre -> next = temp;
}
return dummy -> next;
}
};
86. 分隔链表
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode* dummy1 = new ListNode(0);
ListNode* low = dummy1;
ListNode* dummy2 = new ListNode(0);
ListNode* high = dummy2;
while(head != NULL)
{
ListNode* temp = new ListNode(head->val);
if(temp->val < x)
{
low->next = temp;
low = temp;
}
else
{
high->next = temp;
high = temp;
}
head = head->next;
}
low->next = dummy2->next;
return dummy1->next;
}
};
2. 两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *dummy = new ListNode(-1), *cur = dummy;
int carry = 0;
while (l1 || l2) {
int val1 = l1 ? l1->val : 0;
int val2 = l2 ? l2->val : 0;
int sum = val1 + val2 + carry;
carry = sum / 10;
cur->next = new ListNode(sum % 10);
cur = cur->next;
if (l1) l1 = l1->next;
if (l2) l2 = l2->next;
}
if (carry) cur->next = new ListNode(1);
return dummy->next;
}
};
445. 两数相加 II
给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:
如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
示例:
输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* reverse(ListNode* L)
{
ListNode* dummy = new ListNode(0);
dummy->next = L;
ListNode* temp = L;
while(temp != NULL && temp->next!=NULL)
{
ListNode* node = temp->next;
temp->next = node->next;
node->next = dummy->next;
dummy->next = node;
}
return dummy->next;
}
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* L1 = reverse(l1);
ListNode* L2 = reverse(l2);
ListNode* dummy = new ListNode(0);
int carry = 0, sum = 0;
while(L1 || L2)
{
int val1 = L1 ? L1->val : 0;
int val2 = L2 ? L2->val : 0;
sum = carry + val1 + val2;
carry = sum / 10;
ListNode* temp = new ListNode(sum%10);
temp->next = dummy->next;
dummy->next = temp;
if(L1) L1 = L1->next;
if(L2) L2 = L2->next;
}
if(carry > 0)
{
ListNode* temp = new ListNode(1);
temp->next = dummy->next;
dummy->next = temp;
}
return dummy->next;
}
};
82. 删除排序链表中的重复元素 II
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
while(cur->next != NULL)
{
ListNode* temp = cur->next;
if(temp->next == NULL || temp->val != temp->next->val)
cur = temp;
else
{
while(temp->next != NULL && temp->val == temp->next->val)
temp = temp->next;
cur->next = temp->next;
}
}
return dummy->next;
}
};
24. 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy;
ListNode* first = cur->next;
while(first != NULL)
{
ListNode* second = first->next;
if(second == NULL)
break;
first->next = second->next;
second->next = first;
cur->next = second;
cur = first;
first = first->next;
}
return dummy->next;
}
};
25. K 个一组翻转链表
给你一个链表,每 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* dummy = new ListNode(0);
ListNode* cur = dummy;
stack<ListNode*> s;
while(head)
{
s.push(head);
head = head->next;
if(s.size() == k)
{
while(!s.empty())
{
ListNode* temp = s.top();
s.pop();
cur->next = temp;
cur = temp;
}
}
}
cur->next = NULL;
while(!s.empty())
{
ListNode* temp = s.top();
s.pop();
temp->next = cur->next;
cur->next = temp;
}
return dummy->next;
}
};
147. 对链表进行插入排序
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
ListNode* dummy = new ListNode(0);
dummy->next = head;
ListNode* cur = dummy->next;
while(cur != NULL)
{
ListNode* node = cur->next;
if(node == NULL)
break;
if(cur->val <= node->val)
cur = node;
else
{
cur->next = node->next;
ListNode* temp = dummy;
while(temp->next->val < node->val )
temp = temp->next;
node->next = temp->next;
temp->next = node;
}
}
return dummy->next;
}
};
148. 排序链表
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
第一种方法:快速排序
class Solution {
public:
void swap(ListNode* s, ListNode* t)
{
int temp = s->val;
s->val = t->val;
t->val = temp;
}
ListNode* partition(ListNode* head, ListNode* tail)
{
int pivot = head->val;
ListNode* cur = head;
ListNode* temp = cur->next;
while(temp != tail)
{
if(temp->val < pivot)
{
cur = cur->next;
swap(temp, cur);
}
temp = temp->next;
}
swap(cur, head);
return cur;
}
void quicksort(ListNode* head, ListNode* tail)
{
if(head == tail || head->next == NULL)
return;
ListNode* mid = partition(head, tail);
quicksort(head, mid);
quicksort(mid->next, tail);
}
ListNode* sortList(ListNode* head) {
quicksort(head, NULL);
return head;
}
};
第二种方法:归并排序
归并排序大致思想是: 1.将链表划分左右两部分--> 2.对左右链表进行排序 --> 3.将左右两个有序链表进行合并
class Solution {
public:
ListNode* merge(ListNode* L, ListNode* R)
{
ListNode* dummy = new ListNode(0);
ListNode* cur = dummy;
while(L != NULL && R != NULL)
{
if(L->val < R->val)
{
cur->next = L;
cur = cur->next;
L = L->next;
}
else
{
cur->next = R;
cur = cur->next;
R = R->next;
}
}
if(L != NULL)
cur->next = L;
if(R != NULL)
cur->next = R;
return dummy->next;
}
ListNode* mergesort(ListNode* head)
{
if(head->next == NULL)
return head;
ListNode* first = head;
ListNode* second = head;
ListNode* pre = NULL;
while(second != NULL && second->next != NULL)
{
pre = first;
first = first->next;
second = second->next->next;
}
pre->next = NULL;
ListNode* L = mergesort(head);
ListNode* R = mergesort(first);
return merge(L, R);
}
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL)
return head;
return mergesort(head);
}
};
61. 旋转链表
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 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
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if(head == NULL || k == 0)
return head;
ListNode *cur = head;
int count = 1;
while(cur->next)
{
count++;
cur = cur->next;
}
cur->next = head;//变成环
k = k % count;
int n = count-k;
for(int i = 0; i < n;i++)
cur = cur->next;
ListNode *newNode = cur->next;
cur->next = NULL;//断开环
return newNode;
}
};
143. 重排链表
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
(1)首先链表使用快慢指针,找到链表的中点
(2)然后将链表的后半部分逆置
(3)最后将后半部分依次插入前半部分
class Solution {
public:
void reorderList(ListNode* head) {
if(head == NULL || head->next == NULL)
return;
ListNode* first = head;
ListNode* second = head;
while(second != NULL && second->next != NULL)
{
first = first->next;
second = second->next->next;
}
ListNode* back = first->next;
while(back != NULL)
{
ListNode* temp = back->next;
if(temp == NULL)
break;
back->next = temp->next;
temp->next = first->next;
first->next = temp;
}
ListNode* s = head;
ListNode* t = first;
while(t->next != NULL)
{
ListNode* node = t->next;
t->next = node->next;
node->next = s->next;
s->next = node;
s = node->next;
}
}
};
234. 回文链表
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
(1)使用快慢指针找到链表的中点
(2)将后半部分链表逆置
(3)比较前半部分和后半部分
class Solution {
public:
bool isPalindrome(ListNode* head) {
if(head == NULL)
return true;
ListNode *fast = head, *slow = head;
while(fast->next != NULL && fast->next->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
ListNode* cur = slow->next;
while(cur != NULL)
{
ListNode* temp = cur->next;
if(temp == NULL)
break;
cur->next = temp->next;
temp->next = slow->next;
slow->next = temp;
}
slow = slow->next;
while(slow != NULL)
{
if(slow->val != head->val)
return false;
head = head->next;
slow = slow->next;
}
return true;
}
};