一. 在链表中穿针引线
2.1 Leetcode 206:Reverse Linked List
反转一个链表。
解法一(非递归):设立pre,cur和next三个指针完成穿针引线。示意图如下:
/**
* 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) {
ListNode* pre = NULL;
ListNode* cur = head;
while (cur != NULL){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
解法二(递归)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr || head->next == nullptr)
return head;
ListNode* newHead = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return newHead;
}
};
2.2 Leetcode 206:Reverse Linked List
反转一个链表从m到n的元素。
例如:
对于链表1->2->3->4->5->NULL,m=2,n=4,则返回1->4->3->2->5->NULL
解法(设置虚拟头结点):设置三个指针,pre,cur和move完成链表的穿针引线。其步骤如下:
1->2->3->4->5->NULL ———>1->3->2->4->5->NULL———>1->4->3->2->5->NULL
/**
* 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* dummyHead= new ListNode(0);
dummyHead->next = head;
ListNode* pre = dummyHead;
for (int i = 0; i < m - 1; i++) //为什么是m-1,因为题目中m是从1开始计的
pre = pre->next;
ListNode* cur = pre->next;
for (int i = 0; i < n - m; i++){ //为什么是n-m,因为反转n-m+1长度的子链表需要n-m次
ListNode* move = cur->next;
cur->next = move->next;
move->next = pre->next;
pre->next = move;
}
return dummyHead->next;
}
};
2.3 Leetcode 83:Remove Duplicates from Sorted List
给出一个有序链表,删除其中所有重复元素,使得每个元素只保留一次。
例如:
对于链表1->1->2->NULL,则返回1->2>NULL
对于链表1->1->2->3->3->NULL,则返回1->2->3->NULL
解法:遍历链表,判断当前结点curNode以及其下一个结点的val值是否相等,相等则让curNode->next=curNode->next->next;不相等则curNode=curNode->next。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head){
if (head == NULL)
return NULL;
ListNode* cur_node = head;
while (cur_node != NULL && cur_node->next != NULL){
if (cur_node->val == cur_node->next->val)
cur_node->next = cur_node->next->next;
else
cur_node = cur_node->next;
}
return head;
}
};
2.4 Leetcode 83:Partition List
给出一个链表以及一个数x,将链表重新整理,使得小于x的数在前;大于等于x的元素灾后。
例如:
对于链表1->4->3->2->5->2->NULL,x=3,则返回1->2->2->4->3->4->NULL
解法:设定两个虚拟头结点dummyHead1和dummyHead2,遍历整个链表,将小于该值的放于dummyHead1中,其余的放置在dummyHead2中。遍历结束后,将dummyHead2插入到dummyHead1中。
class Solution{
public:
ListNode* partition(ListNode* head, int x) {
if(head == NULL)
return NULL;
ListNode* dummyHead1 = new ListNode(0);
ListNode* dummyHead2 = new ListNode(0);
ListNode* curNode1 = dummyHead1;
ListNode* curNode2 = dummyHead2;
ListNode* curNode = head;
while(curNode != NULL){
if(curNode->val < x){
curNode1->next = curNode;
curNode1 = curNode1->next;
}
else{
curNode2->next = curNode;
curNode2 = curNode2->next;
}
curNode = curNode->next;
}
curNode2->next = NULL;
curNode1->next = dummyHead2->next;
return dummyHead1->next;
}
};
2.5 Leetcode 2:Add Two Numbers
给出两个非空链表,表示两个非负整数。其中每一个整数的各位数字以逆序存储,返回这两个整数相加所代表的链表。
例如:
342+465=807
则给出2->4->3->NULL和5->6->4->NULL,则返回7->0->8->NULL
解法:设立一个表示进位的变量carry,建立一个新链表,把输入的两个链表从头往后同时处理,每两个相加,将结果加上carry后的值作为一个新节点到新链表后面。
class Solution{
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2){
ListNode *dummyHead= new ListNode(0);
ListNode* curNode = dummyHead;
int sum = 0, carry = 0;
while(l1 || l2 || carry){
sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carry;
carry = sum / 10;
curNode->next = new ListNode(sum % 10);
curNode= curNode->next;
l1 = l1 ? l1->next : l1;
l2 = l2 ? l2->next : l2;
}
return head->next;
}
};
2.5 Leetcode 445. Add Two Numbers II
给出两个非空链表,表示两个非负整数。其中每一个整数的各位数字以顺序存储,返回这两个整数相加所代表的链表。
例如:
342+465=807
则给出3->4->2->NULL和4->6->5>NULL,则返回8->0->7->NULL
解法:由于需要从低位开始加。然后进位。因此可以采用栈来简化操作。依次将两个链表的值分别入栈stack1和stack2,然后相加入栈stack,进位操作用一个变量carried记录即可。最后根据stack生成最终的链表。
/**
* 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)
{
stack<int> s1;
stack<int> s2;
ListNode* cur_node1 = l1;
ListNode* cur_node2 = l2;
while (cur_node1){
s1.push(cur_node1->val);
cur_node1 = cur_node1->next;
}
while (cur_node2){
s2.push(cur_node2->val);
cur_node2 = cur_node2->next;
}
int sum = 0, carry = 0;
stack<int> s;
while((!s1.empty()) || (!s2.empty()) || carry){
int x = 0, y = 0;
if(!s1.empty()){
x = s1.top();
s1.pop();
}
if(!s2.empty()){
y = s2.top();
s2.pop();
}
sum = x + y + carry;
carry = sum / 10;
s.push(sum % 10);
}
ListNode* dummyHead = new ListNode(0);
ListNode* curNode = dummyHead;
while(!s.empty()){
curNode->next = new ListNode(s.top());
s.pop();
curNode = curNode->next;
}
return dummyHead->next;
}
};
2.5 Leetcode 203. Remove Linked List Elements
在链表中删除值为val的所有结点
例如:
1->2->6->3->4->5->6->NULL,val = 6,则返回1->2->3->4->5->NULL
解法:设置虚拟头结点dummyHead,遍历链表,若当前结点curNode的下一个结点的val值等于val,记为delNode,然后删除delNode.
class Solution{
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead= new ListNode(0);
dummyHead->next = head;
ListNode* curNode= dummyHead;
while (curNode->next){
if (curNode->next->val == val){
ListNode* delNode= curNode->next;
curNode->next = curNode->next;
delete delNode;
}
else
curNode = curNode->next;
}
return dummyHead->next;
}
};
};
2.5 Leetcode 82. Remove Duplicates from Sorted List II
给定一个有序链表,将其中有重复元素全部删除。
例如:
1->2->3->3->4->4->5->NULL,则返回1->2->5->NULL
1->1->1->2->3->NULL,则返回2->3->NULL
解法:设置虚拟头结点dummyHead,在设置两个结点curNode和preNode,若curNode的val值等于preNode的val值,则进行删除,并更新curNode;若不等于,则将preNode移动到curNode,并将curNode移动到curNode->next.
class Solution{
public:
ListNode* deleteDuplicates(ListNode* head){
if (head == NULL)
return NULL;
ListNode* dummyHead= new ListNode(0);
dummyHead->next = head;
ListNode* curNode = dummyHead;
ListNode* preNode = dummyHead;
int preVal = INT_MAX;
while (curNode->next){
if (curNode->next->val == preVal){
ListNode* delNode = preNode->next;
preNode->next = delNode->next;
curNode = preNode;
delete delNode;
}
else{
preNode = curNode;
curNode = curNode->next;
preVal = curNode->val;
}
}
return dummyHead->next;
}
};
2.6 Leetcode 24. Swap Nodes in Pairs
给定一个链表,对于每两个相邻的结点,交换其位置。
例如:
1->2->3->4->NULL,则返回2->1->4->3->NULL
解法:初始化node1为第一个节点,node2为第二个节点,初始化p为dummyHead,然后进行node1.next = node2.next,node2.next = node1,p.next = node2,p移动两格,直至重复完。
class Solution{
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* p = dummyHead;
while (p->next && p->next->next){
ListNode* node1 = p->next;
ListNode* node2 = node1->next;
node1->next = node2->next;
node2->next = p->next;
p->next = node2;
p = node1;
}
return dummyHead->next;
}
};
2.7 Leetcode 25. Reverse Nodes in k-Group
给定一个链表,每k个结点为一组,反转每一组的k个结点。k为正整数且小于等于链表长度。如果链表长度不是k的整数倍。剩余部分不需要进行反转。
例如:1->2->3->4->5->NULL,
若k=2,则返回2->1->4->3->5->NULL;
若k=3,则返回3->2->1->4->5->NULL;
解法
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if(head == nullptr || head->next == nullptr)
return head;
ListNode* cur = head;
for(int i = 1; i < k && cur != nullptr; i++)
cur = cur->next;
if(cur == nullptr)
return head;
ListNode* tmp = cur->next;
cur->next = nullptr;
ListNode* newTmp = reverseKGroup(tmp, k);
ListNode* newHead = reverseList(head);
head->next = newTmp;
return newHead;
}
private:
ListNode* reverseList(ListNode* head)
{
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur != nullptr)
{
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
};
2.7 Leetcode 147. Insertion Sort List
给定一个链表,实现插入排序。
解法:不太会,只给出了代码。
ListNode* insertionSortList(ListNode* head) {
if(head == NULL)
return NULL;
ListNode* cur = head;
ListNode* sList = new ListNode(INT_MIN);
while(cur){
ListNode* node = curr;
cur = cur->next;
ListNode* p = sList->next;
ListNode* n = sList;
while(p && node->val > p->val){
n = p;
p = p->next;
}
n->next = node;
node->next = p;
}
head = sList->next;
delete sList;
return head;
}
2.8 Leetcode 148. Sort List
写一个排序算法,用O(nlogn)的时间复杂度为一个链表进行排序。
解法:非标准解法(投机取巧),将链表中的元素push进一个vector中,对vector进行排序,然后将排完序的元素重新变成链表。
class Solution{
public:
ListNode* sortList(ListNode* head) {
if(head == NULL)
return NULL;
vector<int> vec;
ListNode* scan = head;
for(; scan != NULL; scan=scan->next)
vec.push_back(scan->val);
sort(vec.begin(), vec.end());
scan = head;
for(int i = 0; i < vec.size(); ++i){
scan->val = vec[i];
scan = scan->next;
}
return head;
}
};
解法二: 归并排序
public ListNode sortList(ListNode head) {
// 1、递归结束条件
if (head == null || head.next == null) {
return head;
}
// 2、找到链表中间节点并断开链表 & 递归下探
ListNode midNode = middleNode(head);
ListNode rightHead = midNode.next;
midNode.next = null;
ListNode left = sortList(head);
ListNode right = sortList(rightHead);
// 3、当前层业务操作(合并有序链表)
return mergeTwoLists(left, right);
}
// 找到链表中间节点(876. 链表的中间结点)
private ListNode middleNode(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode slow = head;
ListNode fast = head.next.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
// 合并两个有序链表(21. 合并两个有序链表)
private ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode sentry = new ListNode(-1);
ListNode curr = sentry;
while(l1 != null && l2 != null) {
if(l1.val < l2.val) {
curr.next = l1;
l1 = l1.next;
} else {
curr.next = l2;
l2 = l2.next;
}
curr = curr.next;
}
curr.next = l1 != null ? l1 : l2;
return sentry.next;
}
解法三: 快速排序
class Solution {
public ListNode sortList(ListNode head) {
//边界
if(head==null||head.next==null) return head;
//伪头结点
ListNode pre=new ListNode(0,head);
//快排
quickSort(pre,null);
//返回头结点
return pre.next;
}
//输入时伪头结点和尾节点null
void quickSort(ListNode pre,ListNode end){
//如果节点数小于1就返回
if(pre==end||pre.next==end||pre.next.next==end) return;
//选第一个节点为基准
ListNode b=pre.next;
//建立临时链表
ListNode cur=new ListNode(0);
//临时左右两指针
ListNode r=b,l=cur;
//遍历,右指针下一节点为end,说明当前是最后一个元素,结束
while(r.next!=end){
//如果当前元素小于基准,就加入临时链表,并在原链表中删除
if(r.next.val<b.val){
l.next=r.next;
l=l.next;
r.next=r.next.next;
} else{
//不小于基准,右指针后移
r=r.next;
}
}
//临时链表接在原链表前面,并把伪头结点指向临时节点头结点
l.next=pre.next;
pre.next=cur.next;
//对基准的左右两边递归,注意输入都是伪头结点和两链表的尾节点的下一节点
quickSort(pre,b);
quickSort(b,end);
}
}
2.9 Leetcode 237. Delete Node in a Linked List
给定链表中的一个结点,删除该结点。
解法:将node的val值指向下一个结点的val值,然后将下一个结点标记为delNode,然后进行删除。
class Solution{
public:
void deleteNode(ListNode* node) {
if (node == NULL)
return;
if (node->next == NULL){
delete node;
node = NULL;
return;
}
node->val = node->next->val;
ListNode* delNode = node->next;
node->next = delNode->next;
delete delNode;
}
};
2.10 Leetcode 19. Remove Nth Node From End of List
给定链表中的一个结点,删除倒数第n个结点。
例如:1->2->3->4->5->NULL,n=2,则返回1->2->3->5->NULL
解法一(常规思路):先遍历一遍计算链表长度,在遍历一遍删除倒数第n个结点。
解法一(双索引):设置两个索引指针p,q,让p指向虚拟头结点dummyHead,q指向距离p为n+1位置的结点。然后遍历一遍链表,直至q为空,那么p指向的结点就是待删除结点的前一个结点,最后在执行删除操作。
class Solution
{
public:
ListNode* removeNthFromEnd(ListNode* head, int n)
{
assert(n >= 0);
if (head == NULL)
return head;
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* p = dummyHead;
ListNode* q = dummyHead;
for (int i = 0; i < n + 1; i++){
assert(q);
q = q->next;
}
while (q){
p = p->next;
q = q->next;
}
ListNode* delNode = p->next;
p->next = delNode->next;
delete delNode;
ListNode* retHead = dummyHead->next;
delete dummyHead;
return retHead;
}
};
2.11 链表中环的入口结点
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
ListNode* meetingNode = meetNode(pHead);
if(meetingNode == nullptr)
return nullptr;
ListNode* pNode1 = meetingNode;
int nodesInLoop = 1;
while(pNode1->next != meetingNode)
{
nodesInLoop++;
pNode1 = pNode1->next;
}
pNode1 = pHead;
for(int i = 0; i < nodesInLoop; i++)
pNode1 = pNode1->next;
ListNode* pNode2 = pHead;
while(pNode1 != pNode2)
{
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
return pNode1;
}
private:
ListNode* meetNode(ListNode* pHead)
{
ListNode* pSlow = pHead->next;
if(pSlow == nullptr)
return nullptr;
ListNode* pFast = pSlow->next;
while(pSlow && pFast)
{
if(pSlow == pFast)
return pFast;
pSlow = pSlow->next;
pFast = pFast->next;
if(pFast)
pFast = pFast->next;
}
return nullptr;
}
};
2.12 合并两个排序的链表
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
if(pHead1 == nullptr)
return pHead2;
if(pHead2 == nullptr)
return pHead1;
ListNode* dummyHead = new ListNode(0);
ListNode* cur1 = pHead1;
ListNode* cur2 = pHead2;
ListNode* cur = dummyHead;
while(cur1 || cur2){
int val1 = cur1 ? cur1->val : INT_MAX;
int val2 = cur2 ? cur2->val : INT_MAX;
int val = 0;
if(val1 < val2){
val = val1;
cur1 = cur1 ? cur1->next : nullptr;
}
else{
val = val2;
cur2 = cur2 ? cur2->next : nullptr;
}
cur->next = new ListNode(val);
cur = cur->next;
}
return dummyHead->next;
}
};
另一种写法:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (list1 == nullptr)
return list2;
if (list2 == nullptr)
return list1;
ListNode* dummy_head = new ListNode(0);
ListNode* cur = dummy_head;
ListNode* cur1 = list1, *cur2 = list2;
while(cur1 && cur2) {
if(cur1->val < cur2->val) {
cur->next = cur1;
cur1 = cur1->next;
}
else {
cur->next = cur2;
cur2 = cur2->next;
}
cur = cur->next;
}
cur->next = cur1 ? cur1 : cur2;
return dummy_head->next;
}
};
2.13 复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead == nullptr)
return nullptr;
CloneNextNode(pHead);
CloneRandomNode(pHead);
return GetDumplicateList(pHead);
}
private:
void CloneNextNode(RandomListNode* pHead)
{
RandomListNode* cur = pHead;
while(cur != nullptr)
{
RandomListNode* next = cur->next;
RandomListNode* clone = new RandomListNode(cur->label);
clone->next = cur->next;
cur->next = clone;
cur = next;
}
return;
}
void CloneRandomNode(RandomListNode* pHead)
{
RandomListNode* cur = pHead;
while(cur != nullptr)
{
RandomListNode* clone = cur->next;
if(cur->random != nullptr)
clone->random = cur->random->next;
cur = clone->next;
}
return;
}
RandomListNode* GetDumplicateList(RandomListNode* pHead)
{
RandomListNode* dummyHead = new RandomListNode(0);
RandomListNode* cur1 = pHead;
RandomListNode* cur2 = dummyHead;
while(cur1 != nullptr)
{
RandomListNode* clone = cur1->next;
cur1->next = clone->next;
cur2->next = clone;
cur1 = cur1->next;
cur2 = cur2->next;
}
return dummyHead->next;
}
};
2.12 两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
if(pHead1 == nullptr || pHead2 == nullptr)
return nullptr;
int len1 = getListLen(pHead1);
int len2 = getListLen(pHead2);
ListNode* p1 = nullptr;
ListNode* p2 = nullptr;
int diff_len = 0;
if(len1 > len2){
p1 = pHead1;
diff_len = len1 - len2;
p2 = pHead2;
}
else{
p1 = pHead2;
diff_len = len2 - len1;
p2 = pHead1;
}
for(int i = 0; i < diff_len; i++)
p1 = p1->next;
while(p1 != nullptr && p2 != nullptr && p1 != p2) {
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
private:
int getListLen(ListNode* head){
int len = 0;
ListNode* cur = head;
while(cur != nullptr){
len++;
cur = cur->next;
}
return len;
}
};