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

avatar
作者
筋斗云
阅读量:0

一、链表的回文结构

思路:

        找到链表的中间节点,然后逆置链表的后半部分,再一一遍历链表的前半部分和后半部分,判断是是否为回文结构。

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

        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;

思路:

        先遍历两个链表,记录两个链表的节点个数;再同时遍历两个链表 ,让节点个数多的链表先往前走s(链表的节点个数差);同时遍历两个链表,如果指向链表的指针相等,就返回当前节点;如果遍历链表结束后,都没有相等的节点,那就返回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或者fast->next为NULL,则链表不存在环。

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

        首先定义两个指针 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指针赋值,最后断开新链表和原链表的连接即可。

        深拷贝原链表

        拷贝过后

        给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; }

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!