一、链表的回文结构
思路:
找到链表的中间节点,然后逆置链表的后半部分,再一一遍历链表的前半部分和后半部分,判断是是否为回文结构。
快慢指针找到链表的中间节点
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; }