(十二)链表(C++实现)

反转链表

Leetcode 206:https://leetcode-cn.com/problems/reverse-linked-list/
Nowcoder NC76:https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=188&&tqId=38547

1.问题描述

给定单链表的头节点head,反转链表。

2.输入输出

  • Input:head = [1, 2, 3, 4, 5]
  • Output:[5, 4, 3, 2, 1]

3.算法分析

  1. 迭代法:1)实现存储前一个节点;2)通过当前指针遍历链表;3)存储后一个节点;4)将当前节点的next指针改为指向前一个节点。5)最后返回新的头引用——前一个节点。
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
  1. 递归法:
  • 递归终止条件:链表只剩最后一个节点或者已经为空(最后一个节点就是反转后的头节点)
  • 处理:让当前节点的下一格节点的next指针指向当前节点,且当前节点的next指向NULL,实现链表尾部开始的局部反转
    • 时间复杂度:O(n)
    • 空间复杂度:O(n)

4.编程实现

#include <iostream>
using namespace std;

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* reverseList1(ListNode* head) {  
        // 迭代法 1->2->3->Ø变成Ø->3->2-1
        ListNode* prev = nullptr;
        ListNode* curr = head;
        
        while (curr) {
            ListNode* nxt = curr->next;
            curr->next = prev;
            prev = curr;
            curr = nxt;
        }
        
        return prev;
    }
    
    ListNode* reverseList2(ListNode* head){
        // 递归法 1->2->3->Ø变成Ø->3->2-1
        if (!head || !head->next) return head;
        ListNode *newHead = reverseList2(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newHead;
    }
};

int main() {
    Solution sol;
    ListNode* head = new ListNode(), *now = head;  
    int val;
    
    getchar();
    while (cin >> val) {
        now->next = new ListNode(val);
        now = now->next;
        if (cin.get() == ']') break;
    }
    
    
    now = sol.reverseList1(head->next);
    cout << "[";
    while (now) {
        cout << now->val;
        if (now->next) {
            cout << ",";
        } else {
            cout << "]";
        }
        now = now->next;
    }
    
    return 0;
}

k个一组翻转链表

Leetcode:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/

1.问题描述

给定一个链表,每k个节点一组进行翻转,返回翻转后的链表。(k是一个正整数,它的值小于或等于链表的长度,如果节点总数不是k的整数倍,将最后剩余的节点保持原有顺序)

2.输入输出

  • Input:head=[1, 2, 3, 4, 5],k=2
  • Output:[2,1,4,3,5]

3.算法分析

先计算以下长度,再根据需要翻转的段数进行遍历。

4.编程实现

// #include <bits/stdc++.h>
#include <iostream>
using namespace std;

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* reverseKGroup(ListNode *head, int k) {
        ListNode *dummy = new ListNode(0), *prev = dummy, *curr = head, *nextNode;
        dummy->next = head;
        
        int length = 0;
        while (head) {
            length++;
            head = head->next;
        }
        
        for (int i = 0; i < length / k; i++) {
            for (int j = 0; j < k-1; j++) {
                nextNode = curr->next;
                curr->next = nextNode->next;
                nextNode->next = prev->next;
                prev->next = nextNode;
            }
            prev = curr;
            curr = prev->next;
        }
        
        return dummy->next;
    }
};

int main(){
    Solution sol;
    ListNode *head = new ListNode(0), *fake = head;
    int val, k;
    char ch;
    
    getchar();
    while (cin >> val) {
        fake->next = new ListNode(val);
        fake = fake->next;
        if (cin.get() == ']') break;
    }
    cin >> k;
    ListNode *newNode = sol.reverseKGroup(head->next, k);
    while (newNode) {
        cout << newNode->val;
        if (newNode->next) {
            cout << ",";
        } else {
            cout << "";
        }
        newNode = newNode->next;
    }
    return 0;
}

合并两个有序链表

Leetcode:https://leetcode-cn.com/problems/merge-two-sorted-lists/

1.问题描述

将两个升序链表合并成一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

2.输入输出

  • Input:l1=[1, 2, 4],l2=[1, 3, 4]
  • Output:[1, 1, 2, 3, 4, 4]

3.算法分析

迭代法:当l1和l2都不是空链表时,判断l1和l2哪一个链表的头节点的值更小,将较小值得节点添加到结果里,当一个节点被添加到结果里之后,将对应链表的节点后移一位。

  • 时间复杂度:O(n+m)
  • 空间复杂度:O(1)

4.编程实现

#include <iostream>
using namespace std;

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:
    // 1->2->3->Ø变成Ø->3->2-1
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);
        ListNode* prev = preHead;
        
        while (l1  && l2 ) {
            if (l1->val < l2->val) {
                prev->next = l1;
                l1 = l1->next;
            } else {
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }
        
        // 合并后l1和l2最多还有一个还未被合并完,直接将链表末尾指向未合并完的链表即可。
        prev->next = l1 == nullptr? l2 : l1;
        
        return preHead->next;
    }
};

int main() {
    Solution sol;
    ListNode* l1 = new ListNode(1);  
    l1->next = new ListNode(2);  
    l1->next->next = new ListNode(4);  
    
    ListNode* l2 = new ListNode(1);  
    l2->next = new ListNode(3);  
    l2->next->next = new ListNode(4);  
    
    ListNode* newHead = sol.mergeTwoLists(l1, l2);
    while (newHead) {
        cout << newHead->val << " ";
        newHead = newHead->next;
    }
    return 0;
}

相交节点

Leetcode:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/

1.问题描述

给定两个单链表,判断它们是否相交于一点,并求这个相交节点。

2.输入输出

  • Input:A=[4, 1, 8, 4, 5],B=[5, 0, 1, 8, 4, 5]
  • Output:Intersected at '8'

3.算法分析

使用两个指针,分别指向两个链表的头节点,并以相同的速度前进,若到达链表结尾,则移动到另一条链表的头结点继续前进,两个指针会在a+b+c次前进后同时到达相交节点。

  • 时间复杂度:O(m+n)
  • 空间复杂度:O(1)

4.编程实现

#include <iostream>
using namespace std;

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 *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *you = headA, *she = headB;

        while (you != she) {
            you = you? you->next: headB;
            she = she? she->next: headA;
        }

        return you;
    }
};

int main() {
    Solution sol;
    ListNode* l1 = new ListNode(4);  
    l1->next = new ListNode(1);  
    l1->next->next = new ListNode(8);
    l1->next->next->next = new ListNode(4);
    l1->next->next->next->next = new ListNode(5);
    
    ListNode* l2 = new ListNode(5);  
    l2->next = new ListNode(0);  
    l2->next->next = l1->next->next;
    
    cout << sol.getIntersectionNode(l1, l2)->val << endl;
    return 0;
}
posted @ 2021-12-23 10:24  Caoer199  阅读(141)  评论(0编辑  收藏  举报