zoukankan      html  css  js  c++  java
  • 链表练习题集

     

    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) {
            ListNode *new_head = NULL;
            while(head)
            {
                ListNode *next = head->next;
                head->next = new_head;
                new_head=head;
                head=next;
            }
            return new_head;
            
        }
    };

    92. 反转链表 II

    反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

    说明:
    1 ≤ m ≤ n ≤ 链表长度。

    示例:

    输入: 1->2->3->4->5->NULL, m = 2, n = 4
    输出: 1->4->3->2->5->NULL

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    /**
     * 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) {
        int change_len = n - m + 1;//要逆置链表数
        ListNode *pre_head = NULL;//开始逆置等等链表的前驱
        ListNode *result = head;//最终转换后链表的头结点
        while(head && --m)
        {
            pre_head = head;//记录head前驱
            head = head->next;
        }
        ListNode *modify_list_tail = head;
        ListNode *new_head = NULL;
        while(head && change_len)//逆置change_len个节点
        {
            ListNode *next = head->next;
            head->next = new_head;
            new_head = head;
            head = next;
            change_len--;//完成每一个节点逆置后change_len--;
        }
        modify_list_tail->next = head;//连接逆置后的链表尾部与逆置段的后一个节点
        if(pre_head)//如果pre不是NULL,说明不是从第一个节点开始的 M > 1
        {
            pre_head->next = new_head;//将逆置链表的开始节点与前驱相连
        }
        else
        {
            
            result = new_head;//如果是空说明从第一个节点开始逆置,结果就是头节点
        }
        return result;
        }
    };

    160. 相交链表

    编写一个程序,找到两个单链表相交的起始节点。

    如下面的两个链表:

     

    在节点 c1 开始相交。

    示例 1:

     

    输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
    输出:Reference of the node with value = 8
    输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
     

    示例 2:

     

    输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
    输出:Reference of the node with value = 2
    输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
     

    示例 3:

     

    输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
    输出:null
    输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
    解释:这两个链表不相交,因此返回 null。
     

    注意:

    如果两个链表没有交点,返回 null.
    在返回结果后,两个链表仍须保持原有的结构。
    可假定整个链表结构中没有循环。
    程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

     解题思路:

    先求得A和B链表的长度,让指针走到两个链表一样长度的地方。

    之后两个链表一起前进如果两个指针指向相同则说明有交点。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        int get_list_length(ListNode*head)
        {
            int len = 0;
            while(head)
            {
                len++;
                head = head ->next;
            }
            return len;
        }
        ListNode * forward_long_list(int long_len, int short_len, ListNode* head)
        {
            int delta = long_len - short_len;
            while(head && delta)
            {
                head = head->next;//将指针移动到多出节点个数后面的位置
                delta --;
            }
            return head;
        }
        ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
            int list_A_len = get_list_length(headA);
            int list_B_len = get_list_length(headB);
            if(list_A_len > list_B_len)
            {
                headA = forward_long_list(list_A_len,list_B_len,headA);
            }
            else
            {
                headB = forward_long_list(list_B_len,list_A_len,headB);
            }
            while(headA && headB)
            {
                if(headA == headB)
                {
                    return headA;
                }
                headA = headA->next;
                headB = headB->next; 
            }
            return NULL;
        }
        
    };

    141. 环形链表

     

    给定一个链表,判断链表中是否有环。

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

    示例 1:

    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。


    示例 2:

    输入:head = [1,2], pos = 0
    输出:true
    解释:链表中有一个环,其尾部连接到第一个节点。


    示例 3:

    输入:head = [1], pos = -1
    输出:false
    解释:链表中没有环。


    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/linked-list-cycle
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

     思路:利用快慢指针的方法来解决。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        bool hasCycle(ListNode *head) {
            ListNode *slow = head;
            if(slow == NULL)
            return false;
            
            ListNode *fast = head->next;
            
        
            while(fast && slow && fast->next)
            {
                if(fast == slow)
                {
                    
                    return true;
                }
                slow = slow->next;
                fast = fast->next->next;
            }
            return false;
        }
    };

    142. 环形链表 II

    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

    说明:不允许修改给定的链表。

    示例 1:

    输入:head = [3,2,0,-4], pos = 1
    输出:tail connects to node index 1
    解释:链表中有一个环,其尾部连接到第二个节点。


    示例 2:

    输入:head = [1,2], pos = 0
    输出:tail connects to node index 0
    解释:链表中有一个环,其尾部连接到第一个节点。


    示例 3:

    输入:head = [1], pos = -1
    输出:no cycle
    解释:链表中没有环。


    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    (图略)

    解题思路:首先找到一个环内的节点表明链表内确实有环,之后让链表内的相遇节点和链表外的头结点一起向前移动,这样相遇的节点就是链表的环开始的地方的节点

    class Solution {
    public:
         ListNode *detectCycle(ListNode *head) {
     ListNode *fast = head;
     ListNode *slow = head;
     ListNode *meet = nullptr;
     while  (fast)
     {
         slow = slow->next;
         fast = fast->next;
         if(!fast)
         {
             return nullptr;
         }
         fast = fast->next;
         
         if(fast == slow)
         {
             
             meet = slow;
             break;
         }
     }
     if(meet == nullptr)
     {
         return nullptr;
     }
     ListNode *start = head;
            while(start && meet)
            {
                if(start == meet)
                {
                    return start;
                }
                start = start->next;
                meet = meet->next;
            }
            return NULL;
        }
    };

    86. 分隔链表

     

    给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

    你应当保留两个分区中每个节点的初始相对位置。

    示例:

    输入: head = 1->4->3->2->5->2, x = 3
    输出: 1->2->2->4->3->5

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/partition-list
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路:建立两个临时链表morehead和lesshead 使用尾插法 遍历所给的head链表 把小于的插入lesshead把大于等于的插入到morehead里。这样就可以得出符合条件的两个链表 最后把morehead插入lesshead的尾部就可以了。返回lesshead头的下一个节点。

    /**
     * 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 less_head(0);
            ListNode more_head(0);
            ListNode *less_ptr = &less_head;
            ListNode *more_ptr = &more_head;
            while(head)
            {
                if(head->val < x)
                {
                    less_ptr->next = head;
                    less_ptr = less_ptr->next;
                }   
                else
                {
                    more_ptr->next = head;
                    more_ptr = more_ptr->next;
                }
                head = head->next;
            }
            less_ptr->next = more_head.next;
            more_ptr->next = nullptr;
            return less_head.next;
        }
    };

     在下一个题开始之前先复习一下stl中的映射使用方法:

    #include<stdio.h>
    #include<queue>
    #include<vector>
    #include<functional>
    #include<map>
    
    using namespace std;
    /*
    class Node {
    public:
        int val;
        Node* next;
        Node* random;
    
        Node(int _val) {
            val = _val;
            next = NULL;
            random = NULL;
        }
    };
    
    
    class Solution {
    public:
        Node* copyRandomList(Node* head) {
    
        }
    };
    */
    struct RandomListNode
    {
        int lable;
        RandomListNode *next, *random;
        RandomListNode(int x) : lable(x), next(NULL), random(NULL){}
    };
    int main()
    {
    map <RandomListNode* ,int> node_map;
    RandomListNode a(2);
    RandomListNode b(4);
    RandomListNode c(6);
    
    a.next = &b;
    b.next = &c;
    
    a.random = &c;
    b.random = &a;
    c.random = &c;
    
    node_map[&a] = 1;
    node_map[&b] = 2;
    node_map[&c] = 3;
    
    printf("a.random id is %d
    b.random id is %d
    c.random id is %d
    ",node_map[a.random],node_map[b.random],node_map[c.random]);
    
    return 0;
    }

     

    138. 复制带随机指针的链表

     

    给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

    要求返回这个链表的 深拷贝。 

    我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

    val:一个表示 Node.val 的整数。
    random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。
     

    示例 1:

     

    输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
    输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
    示例 2:

     

    输入:head = [[1,1],[2,1]]
    输出:[[1,1],[2,1]]
    示例 3:

     

    输入:head = [[3,null],[3,0],[3,null]]
    输出:[[3,null],[3,0],[3,null]]
    示例 4:

    输入:head = []
    输出:[]
    解释:给定的链表为空(空指针),因此返回 null。
     

    提示:

    -10000 <= Node.val <= 10000
    Node.random 为空(null)或指向链表中的节点。
    节点数目不超过 1000 。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路:

    第一步:

    遍历链表 每读到一个节点,就创建一个心的节点 把它放入vector中

    把当前遍历的链表地址和对应遍历的链表数放入map中

    第二步:

    再次遍历链表,首先根据遍历的进度把新链表(也就是vector里面的链表)首尾相接

    再根据遍历原链表 得到 对应当前 str所指向的 random指针域里存放(指向)的地址 所对应的map映射(也就是第几个)

    再把新链表(vector中存放的)中的random指向对应(第几个)vector的地址。

    这样就可以实现新链表的random链接了。

    class Node {
    public:
        int val;
        Node* next;
        Node* random;
    
        Node(int _val) {
            val = _val;
            next = NULL;
            random = NULL;
        }
    };
    
    
    class Solution {
    public:
        Node* copyRandomList(Node* head) {
        map <Node*, int> node_map;//地址到节点位置map
        vector <Node*> node_vec;
        Node *ptr = head;//使用vector根据存储节点位置访问地址
        int i = 0;
        while(ptr)//将新链表节点push到node_vec中
        {
            node_vec.push_back(new Node(ptr->val));
            node_map[ptr] = i;
            ptr = ptr->next;
            i++;//遍历原始链表
        }
        node_vec.push_back(0);
        ptr = head;
        i=0;//再次遍历原始链表,连接新的链表的next指针,random指针
        while(ptr)
        {
            node_vec[i]->next = node_vec[i+1];//连接新链表的next
            if(ptr->random)//当random指针不为空的时候
            {
                int id = node_map[ptr->random];//根据node_map确认
                node_vec[i]->random = node_vec[id];//原链表random指向的位置id
            }
            ptr = ptr->next;//连接新链表random指针
            i++;
        }
        return node_vec[0];
        }
    };

    21. 合并两个有序链表

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

    示例:

    输入:1->2->4, 1->3->4
    输出:1->1->2->3->4->4

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路:

    建立一个临时链表 两个指针指向链表的起始,之后分别遍历两个链表,把当前小的那个移动过去,再进行下一次判断。

    注意的是,每次操作后对应操作的链表和新链表都要向后移动。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode head(0);
        ListNode *ptr = &head;
        ListNode *p1 = l1, *p2 = l2;
        while(p1 && p2)
        {
            if(p1->val < p2->val)
            {
                ptr->next = p1;
                p1 = p1->next;
    
            }
            else
            {
                ptr->next = p2;
                p2 = p2->next;
            }
    
                ptr = ptr->next;
        }
        if(p1 == NULL && p2 != NULL)
        {
            ptr->next = p2;
        }
        else if(p2 == NULL && p1 != NULL)
        {
            ptr->next = p1;
        }
        else
        {
            ptr->next = NULL;
        }
        return head.next;
        }
    };

     最后来一个升级版的练习

    这里采用了的是归并思想,把N条链表进行分治处理最后归并也可以高效率的解决问题~

    23. 合并K个排序链表

    合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

    示例:

    输入:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    输出: 1->1->2->3->4->4->5->6

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode head(0);
        ListNode *ptr = &head;
        ListNode *p1 = l1, *p2 = l2;
        while(p1 && p2)
        {
            if(p1->val < p2->val)
            {
                ptr->next = p1;
                p1 = p1->next;
    
            }
            else
            {
                ptr->next = p2;
                p2 = p2->next;
            }
    
                ptr = ptr->next;
        }
        if(p1 == NULL && p2 != NULL)
        {
            ptr->next = p2;
        }
        else if(p2 == NULL && p1 != NULL)
        {
            ptr->next = p1;
        }
        else
        {
            ptr->next = NULL;
        }
        return head.next;
        }
    
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            if(lists.size() == 0)
                return NULL;
            if(lists.size() == 1)
            {
    
                return lists[0];
            }
            if(lists.size() == 2)
                return mergeTwoLists(lists[0],lists[1]);
    
            int mid = lists.size()/2;
            vector<ListNode*> sub1_lists;
            vector<ListNode*> sub2_lists;
    
            for(int i = 0; i < mid;i++)
            {
                sub1_lists.push_back(lists[i]);
            }
            for(int i = mid; i< lists.size();i++)
            {
                sub2_lists.push_back(lists[i]);
            }
            ListNode *l1 = mergeKLists(sub1_lists);
            ListNode *l2 = mergeKLists(sub2_lists);
            return mergeTwoLists(l1,l2);
        }
    };
  • 相关阅读:
    嵌入式工程师C语言面试常见的0x10个问题
    C语言初学者网站推荐
    strlen和sizeof
    基于Docker搭建GitLab和Maven私服
    linux暴露端口可以被外部访问
    MySQL新增用户及赋予权限
    Docker添加域名解析
    Netstat 网络命令详解
    Mysql索引太长导致同步数据结构失败解决方法
    完美解决Cannot download "https://github.com/sass/node-sass/releases/download/binding.nod的问题
  • 原文地址:https://www.cnblogs.com/KID-XiaoYuan/p/12217352.html
Copyright © 2011-2022 走看看