链表经典问题(二)

合并升序列表

递归法

当其中一个链表为空时,直接返回另一个。当都不空,假设除较小的头节点外都已合并,则只需要把头结点与以排列好的的头相连。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if(list1==nullptr)
        return list2;
        if(list2==nullptr)
        return list1;
        if(list1->val<=list2->val)
        {
            list1->next=mergeTwoLists(list1->next,list2);
            return list1;
        }
        else
        {
            list2->next=mergeTwoLists(list1,list2->next);
            return list2;
        }
    }
};

 扁平化多级双向链表

 递归法

 每个结点有两种一般情况:有child,无child。

在无child时,我们只要将头结点之后的结点扁平化。

有child时,我们需要分别将child及其后的链表和next及其后的链表扁平化,然后找到child扁平化后的最后一个节点,将其与next扁平后的第一个节点连接,并删除原来的child。注意next及其后的链表为空的情况。

class Solution {
public:
    Node* flatten(Node* head) {
        Node *t1,*t2,*t3; 
        if(head==NULL||(head->next==NULL&&head->child==NULL)) 
        return head;
        if(head->child==NULL)
        {
            head->next=flatten(head->next);
        }
        else
        {
            t1=flatten(head->next);
            t2=flatten(head->child);
            head->child=NULL;
            head->next=t2;
            t2->prev=head;
            t3=head;
            while(t3->next!=NULL)
            t3=t3->next;
            if(t1!=NULL)
            {
                t3->next=t1;
                t1->prev=t3;
            }

        }
        return head;
    }
};

复制带随机指针的链表

问题描述:

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

构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。

例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。

注意是深拷贝,也就是说新链表不能使用任何原链表中的指针。 

先拷贝一条单链表,这只需要按顺序new一个节点并复制每个节点的数据元素就可以了。

然后我们用a1指针遍历原链表,用a2指针指向每个对应的random。a2存在两种情况:顺着next可以到达a1;顺着a2可以到达链表末尾(NULL)。让a2顺着next遍历下去,直到遇到a1或者走完链表,记录下步数i。为了区分两种步数,第二种步数乘上一个-1。

正的i代表random指向该节点的前i个节点,负的i代表random指向整个链表的倒数第i个节点。

最后通过一组间隔为i的双指针找行链表中的对应节点。

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head==NULL)
        return NULL;
        Node *a1,*a2,*b1,*b2,*b3,*newhead;
        newhead=new Node(head->val);
        a1=head;a2=head->next;
        b1=newhead;
        while(a2!=NULL)
        {
            b2=new Node(a2->val);
            b1->next=b2;
            a1=a1->next;
            b1=b1->next;
            a2=a1->next;
        }//复制单链表
        a1=head;b1=newhead;
        int i=0;
        while(a1!=NULL)
        {
            a2=a1->random;
            if(a2==NULL)
            {
                b1->random=NULL;
                a1=a1->next;
                b1=b1->next;
                continue;
            }
            i=0;
            while(a2!=a1&&a2!=NULL)
            {
                a2=a2->next;
                i++;
            }
            if(a2==NULL)
            i*=-1;//找到间隔i
            a1=a1->next;

            if(i>=0)
            {
                b2=newhead;b3=newhead;
                for(int j=0;j<i;j++)
                b3=b3->next;
                while(b3!=b1)
                {
                    b2=b2->next;
                    b3=b3->next;
                }
                b1->random=b2;
            }
            else
            {
                b2=b1;b3=b1;
                for(int j=0;j>i;j--)
                b3=b3->next;
                while(b3!=NULL)
                {
                    b2=b2->next;
                    b3=b3->next;
                }
                b1->random=b2;
            }
            b1=b1->next;
        }
        return newhead;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值