当前位置: 代码网 > it编程>软件设计>算法 > 【链表】算法题(二) ----- 力扣/牛客

【链表】算法题(二) ----- 力扣/牛客

2024年07月28日 算法 我要评论
遍历链表,fast每次向前走两步,slow每次向前走一步,如果链表存在环,fast与slow指针一定会相遇;再定义两个指针从相遇节点和链表头结点开始遍历,两个指针相遇时的节点就是链表环的起始节点。先在原链表的基础上创建节点,形成新的链表,再给链表节点的random指针赋值,最后断开新链表和原链表的连接即可。找到链表的中间节点,然后逆置链表的后半部分,再一一遍历链表的前半部分和后半部分,判断是是否为回文结构。判断两个链表是否相交,如果相交就返回相交节点,如果链表不相交,那就返回NULL;

一、链表的回文结构

思路:

快慢指针找到链表的中间节点

        slow指针指向的就是中间节点

逆置链表后半部分

        逆置链表后半部分

遍历链表前半部分和后半部分

        如果left和right指向的数据不相等,就跳出循环,返回false;如果遍历到left或者right为null,数据都相等,那么链表具有回文结构,返回true。

这里如果是奇数个节点:

遍历结束后:

class palindromelist {
public:
    //找链表中间节点
    listnode* listmid(listnode* phead)
    {
        listnode* fast, *slow;
        fast=slow=phead;
        while(fast && fast->next)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }
    //逆置
    listnode* reverse(listnode* phead)
    {
        listnode* l1,*l2,*l3;
        l1=null;
        l2=phead;
        while(l2)
        {
            l3=l2->next;
            l2->next=l1;
            l1=l2;
            l2=l3;
        }
        return l1;
    }
    bool chkpalindrome(listnode* a) {
        // write code here
        //找到链表中间节点
        listnode* mid=listmid(a);
        //逆置后半部分
        listnode* phead = reverse(mid);
        //比较
        listnode* left, *right;
        left=a;
        right=phead;
        while(right && left)
        {
            if(right->val!=left->val)
            {
                return false;
            }
            left=left->next;
            right=right->next;
        }
        return true;
    }
};

二、相交链表

判断两个链表是否相交,如果相交就返回相交节点,如果链表不相交,那就返回null;

思路:

typedef struct listnode listnode;
struct listnode* getintersectionnode(struct listnode* heada,
                                     struct listnode* headb) {
    if (heada == null) {
        return null;
    }
    if (headb == null) {
        return null;
    }
    int sizea = 0, sizeb = 0;
    listnode *l1, *l2;
    l1 = heada;
    l2 = headb;
    while (l1) {
        sizea++;
        l1 = l1->next;
    }
    while (l2) {
        sizeb++;
        l2 = l2->next;
    }
    listnode* shortlist = heada;
    listnode* longlist = headb;
    int s = abs(sizea - sizeb);
    if (sizea > sizeb) {
        shortlist = headb;
        longlist = heada;
    }
    while (s) {
        s--;
        longlist = longlist->next;
    }
    while (longlist && shortlist) {
        if (longlist == shortlist) {
            return longlist;
        }
        longlist = longlist->next;
        shortlist = shortlist->next;
    }
    return null;
}

三、环形链表1

判断 链表中是否存在环,如果存在就返回true,如果不存在就返回false;

思路:快慢指针

根据题目所给示例来分析一下:

        首先定义两个指针 fast  slow

        fast向前走两步,slow向前走一步

        fast向前走两步,slow向前走一步

        fast向前走两步,slow向前走一步

此时,fast和slow相遇,证明链表中存在环,返回true。

        如果链表不存在环结构,遍历过程中fast或者fast->next指针会等于null,将这个作为结束条件即可。

typedef struct listnode listnode;
bool hascycle(struct listnode *head) {
    listnode* fast, *slow;
    fast=slow=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow == fast)
        {
            return true;
        }
    }
    return false;
}

四、环形链表2

        上面只是让我们判断链表是否带环,这道题让我们返回链表环的起始节点,如果不存在环就返回null。

思路:

根据题目的示例来分析:

        先找到链表快慢指针的相遇节点:

        定义两个指针从链表头部和相遇节点开始遍历链表

        遍历链表直到两个指针相遇

        两个指针相遇,此时指针指向的节点就是链表环的起始节点。

typedef struct listnode listnode;
listnode* hascycle(struct listnode *head) {
    listnode* fast, *slow;
    fast=slow=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow == fast)
        {
            return slow;
        }
    }
    return null;
}
struct listnode *detectcycle(struct listnode *head) {
    //找到快慢指针相遇节点
    listnode* pos=hascycle(head);
    if(pos==null)
    {
        return null;
    }
    //从头结点和相遇节点开始遍历
    listnode* ptail=head;
    while(1)
    {
        if(pos==ptail)
        {
            return pos;
        }
        pos=pos->next;
        ptail=ptail->next;
    }
}

五、随机链表的复制

这里题目上提到了一个深拷贝

  思路:

        深拷贝原链表

        拷贝过后

        给random指针赋值

        断开新链表和原链表之前的连接

这样就深拷贝了原链表,返回新链表的头节点即可。

typedef struct node node;
// 创建节点
node* buynode(int x) {
    node* newnode = (node*)malloc(sizeof(node));
    newnode->next = newnode->random = null;
    newnode->val = x;
    return newnode;
}
// 深拷贝
void copylist(node** head) {
    node* ptail = *head;
    node* next = null;
    while (ptail) {
        next = ptail->next;
        node* newnode = buynode(ptail->val);
        newnode->next = next;
        ptail->next = newnode;
        ptail = next;
    }
}
void connect(node** head) {
    node* ptail = *head;
    node* copy = (*head)->next;
    while (ptail) {
        copy = ptail->next;
        if (ptail->random)
            copy->random = ptail->random->next;
        ptail = copy->next;
    }
}
struct node* copyrandomlist(struct node* head) {
    if (head == null)
    {
        return null;
    } 
    // 深拷贝原链表
    copylist(&head);
    // 连接random指针
    connect(&head);
    // 断开链表
    node* ptail = head;
    node* newhead = head->next;
    node* copy = head->next;
    while (ptail->next->next) {
        ptail=copy->next;
        copy->next = copy->next->next;
        copy = copy->next;
    }
    return newhead;
}

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com