zoukankan      html  css  js  c++  java
  • (十二)链表(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;
    }
    
    本文为博主原创文章,未经博主允许禁止转载,需转载请注明出处,欢迎指正!
  • 相关阅读:
    Linux手动分区步骤
    Vue到底是怎样个框架?
    MongoDB
    25、正则表达式
    24、模块
    21、三元表达式、列表解析、生成器
    Linux 软件包 管理
    CentOS7.5---7.9 中文字体匹配错误 fontconfig-2.13.0
    Ubuntu14.04下Git安装与使用
    Zabbix3.4 安装配置
  • 原文地址:https://www.cnblogs.com/caoer/p/15722299.html
Copyright © 2011-2022 走看看