(11)链表分割
-
[链表分割_牛客题霸_牛客网](https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking)\]:
- 一个原链表,两个新链表
- 遍历原链表,为了防止因为维护原链表(保留比x大的节点并维持顺序)而进行复杂操作,我们直接选择创建2个新链表进行大节点和小节点的维护
- 比x大的我们尾插到大链表,比x小的我们尾插到小链表
注意:
- 正确初始化尾指针:在第一次添加节点时,同时设置头指针和尾指针
- 断开原链表连接:在将节点添加到新链表前,先保存下一个节点,然后断开当前节点的连接,避免形成循环链表
- 处理空链表情况:如果小链表为空,直接返回大链表
- 统一处理方式:对大小链表的处理采用相同的模式,提高代码一致性
c++/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Partition { public: ListNode* partition(ListNode* pHead, int x) { // 定义两个新的空链表(头节点和尾节点) ListNode* BigList = nullptr; ListNode* BigCur = nullptr; ListNode* SmallList = nullptr; ListNode* SmallCur = nullptr; // 定义一个指针遍历原链表 ListNode* cur = pHead; if(pHead == nullptr) { return nullptr; } while(cur) { ListNode* next = cur->next; // 保存下一个节点 cur->next = nullptr; // 断开当前节点的连接 if(cur->val < x) { // 将节点尾插到小链表中 if(SmallList == nullptr) { SmallList = cur; SmallCur = cur; } else { SmallCur->next = cur; SmallCur = SmallCur->next; } } else { // 将节点尾插到大链表中 if(BigList == nullptr) { BigList = cur; BigCur = cur; } else { BigCur->next = cur; BigCur = BigCur->next; } } cur = next; } // 如果小链表为空,直接返回大链表 if(SmallList == nullptr) { return BigList; } // 将大链表连接到小链表尾部 SmallCur->next = BigList; return SmallList; } };
-
第二种解法:
用指针遍历原链表,小于x的不做处理,大于等于x的尾插到原链表上,并删除之前的节点
- 找到链表原始尾部
- 遍历链表,遇到≥x的节点就移动到尾部
- 如果是头节点,更新head指针
- 更新tail指针指向新的尾部
- 继续处理直到完成
c++/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class Partition { public: ListNode* partition(ListNode* pHead, int x) { if (pHead == nullptr) return nullptr; // 找到链表尾部 ListNode* tail = pHead; while (tail->next != nullptr) { tail = tail->next; } ListNode* head = pHead; ListNode* prev = nullptr; ListNode* cur = head; ListNode* end = tail; // 记录原始尾部,避免重复移动 while (cur != end && cur != nullptr) { if (cur->val >= x) { // 移动到尾部 if (prev == nullptr) { // 头节点需要移动 head = cur->next; tail->next = cur; cur->next = nullptr; tail = cur; cur = head; } else { prev->next = cur->next; tail->next = cur; cur->next = nullptr; tail = cur; cur = prev->next; } } else { prev = cur; cur = cur->next; } } // 处理最后一个节点(原始尾部) if (cur != nullptr && cur->val >= x && cur != tail) { if (prev == nullptr) { head = cur->next; } else { prev->next = cur->next; } tail->next = cur; cur->next = nullptr; } return head; } };
关键处理点:
- 头节点移动的特殊处理:当需要移动头节点时,需要更新head指针
- prev指针的处理:prev为nullptr表示当前节点是头节点
- 尾部指针维护:每次移动节点后更新tail指针
- 循环终止条件:避免重复移动已经移动到尾部的节点
(12)链表的回文结构
-
[链表的回文结构_牛客题霸_牛客网](https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking)\]:
算法思路:
- 找到链表中点:使用快慢指针法,快指针每次走两步,慢指针每次走一步,当快指针到达末尾时,慢指针正好在中间位置。
- 反转后半部分链表:将链表的后半部分反转,这样就可以从两端向中间比较。
- 比较前后两部分:从链表头部和反转后的后半部分头部开始,逐个节点比较值是否相等。
- 恢复链表(可选):如果需要保持原链表结构不变,可以将反转的后半部分再次反转恢复原状。
时间复杂度: O(n) - 遍历链表3次(找中点、反转、比较)
空间复杂度: O(1) - 只使用了固定数量的指针变量c++/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ class PalindromeList { public: bool chkPalindrome(ListNode* A) { //如果原链表是空链表或者只有一个节点的链表默认就是回文结构 if(A == nullptr && A->next == nullptr){return true;} //第一步:使用快慢指针找到链表的中间节点 ListNode* fast = A; ListNode* slow = A; //因为fast一次走两步,所以当fast走到最后只会是指向最后一个节点(单数节点)或者指向最后一个节点的next(双数节点) //所以循环的结束条件fast != nullptr && fast->next != nullptr while(fast != nullptr && fast->next != nullptr){ slow = slow->next; fast = fast->next->next; } //第二步:将找到的中间节点地址传给翻转链表函数(三个指针)进行翻转 ListNode* newList = reverseList(slow); //第三步:通过两个链表的头指针进行遍历比较来判断是否是回文结构 ListNode* Old = A; ListNode* New = newList; while(Old != nullptr && New != nullptr){ if(Old->val != New->val){ return false; } Old = Old->next; New = New->next; } return true; } private: struct ListNode* reverseList(struct ListNode* head) { //如果传入的链表头指针head为空,直接返回NULL,因为空链表不需要反转 if(head == nullptr){ return nullptr; } struct ListNode* n1,*n2,*n3; n1 = nullptr; n2 = head; n3 = head->next; while(n2){ //翻转 n2->next = n1; //迭代往后走 n1 = n2; n2 = n3; if(n3){ n3 = n3->next; } } return n1; } };