1.算法之链表

<LeetCode>

链表逆序

206. 反转链表 反转一个单链表。

示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->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
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
       int change_len = n - m +1;//计算需要逆置节点个数
    ListNode *pre_head = NULL; // 初始化开始逆置节点的前驱
    ListNode *result = head; //最终转化后的链表头节点,非特殊情况即为head
    while(head && --m ){// 将head向前移动m-1位置
        pre_head = head;
        head = head->next;
    }
    ListNode * modify_list_tail = head;//将modify_list_tail 指向当前的head,即逆置后的链表尾
    ListNode * new_head = NULL;
    while(head && change_len){
          ListNode * next = head->next;
          head->next = new_head;
          new_head = head;
          head = next;
          change_len -- ;

    }
    modify_list_tail->next = head;
    if(pre_head){
        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) 内存。
在这里插入图片描述

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        set<ListNode *> test_set;
        ListNode* head=headA;
        while(headA)
        {
            test_set.insert(headA);
            headA=headA->next;
        }
        while(headB)
        {
            if(test_set.find(headB)!=test_set.end())
            {
                return headB;
            }
            headB=headB->next;
        }
        return NULL;
    }
};

在这里插入图片描述

class Solution {
public:
    int get_list_len(ListNode *head)
    {
        int len=0;
        while(head)
        {
            ++len;
            head=head->next;
        }
        return len;
    }
    
    ListNode *forward_long_list(ListNode *head,int long_len,
                                int short_len)
    {
        int offset=long_len-short_len;
        while(head&&offset)
        {
            head=head->next;
            --offset;
        }
        return head;
    }
    
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
       int list_A_len=get_list_len(headA);
       int list_B_len=get_list_len(headB);
        if(list_A_len>list_B_len)
        {
            headA=forward_long_list(headA,list_A_len,
                                    list_B_len);
        }
        else{
            headB=forward_long_list(headB,list_B_len,
                                    list_A_len);
        }
        while(headA&&headB)
        {
            if(headA==headB)
            {
                return headA;
            }
            headA=headA->next;
            headB=headB->next;
        }
        return NULL;
    }
};

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
解释:链表中没有环。
在这里插入图片描述
思路一:同上题目,使用set<>
思路二:
在这里插入图片描述
思路:设链表结点总数为m+n,其中n为链表头结点到环开始的结点的个数,m为环的结点个数,设快慢指针在第n+x(x<m)结点处相遇:
快指针:n/2+x/2+m/2 ,其中m/2时快指针多跑的一圈
慢指针:n+x
n+x=n/2+x/2+m/2
得出n=m-x,则相遇结点再走n个结点就到环开始的结点,开年表头结点走n个结点就到环开始的结点。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow=head;
        ListNode *fast=head;
        ListNode *meet=NULL;
        while(fast)
        {
            slow=slow->next;
            fast=fast->next;
            if(!fast)
            {
                return NULL;
            }
            fast=fast->next;
            if(fast==slow)
            {
                meet=fast;
                break;
            }
        }
        if(meet==NULL)
        {
            return NULL;
        }
        while(head&&meet)
        {
            if(head==meet)
            {
                return head;
            }
            head=head->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
在这里插入图片描述

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=NULL;
        return less_head.next;
    }
};

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

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
在这里插入图片描述
输入:
{"$id":“1”,“next”:{"$id":“2”,“next”:null,“random”:{"$ref":“2”},“val”:2},“random”:{"$ref":“2”},“val”:1}
解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
提示:
你必须返回给定头的拷贝作为对克隆列表的引用。

class Solution {
public:
    Node* copyRandomList(Node* head) {
        std::map<Node *,int> node_map;
        std::vector<Node *> node_vec;
        Node *ptr = head;
        int i = 0;
        while(ptr)
        {
            node_vec.push_back(new Node(ptr->val,NULL,NULL));
            node_map[ptr] = i;
            ptr = ptr->next;
            i++;
         }
        node_vec.push_back(0);
        ptr = head;
        i = 0;
        while(ptr)
        {
           node_vec[i]->next = node_vec[i+1];
           if(ptr->random)
           {
                   int id = node_map[ptr->random]; 
                   node_vec[i]->random = node_vec[id];   
                                    
           } 
              ptr = ptr->next;
              i++;
         }
        return node_vec[0];
    }
};

21. 合并两个有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
在这里插入图片描述

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode temp_head(0);
        ListNode *pre=&temp_head;
        while(l1&&l2)
        {
            if(l1->val<l2->val)
            {
                pre->next=l1;
                l1=l1->next;
            }else{
                pre->next=l2;
                l2=l2->next;
            }
            pre=pre->next;
        }
        pre->next=l1==NULL?l2:l1;
        return temp_head.next;
    }
};

23. 合并K个排序链表

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

class Solution {
public: 
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode temp_head(0);
        ListNode *pre=&temp_head;
        while(l1&&l2)
        {
            if(l1->val<l2->val)
            {
                pre->next=l1;
                l1=l1->next;
            }else{
                pre->next=l2;
                l2=l2->next;
            }
            pre=pre->next;
        }
        pre->next=l1==NULL?l2:l1;
        return temp_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);

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值