数据结构与算法中链表的多元操作:合并、分割及回文判断
1. 链表的合并
题目
将两个升序排列的链表合并成一个新的升序链表并返回。新链表由给定的两个链表的所有节点拼接而成。
示例
- 输入:l1 = [1,2,4],l2 = [1,3,4] 输出:[1,1,2,3,4,4]
- 输入:l1 = [],l2 = [] 输出:[]
- 输入:l1 = [],l2 = [0] 输出:[0]
分析
可以采用迭代的方法来解决这个问题。核心思路是不断比较两个链表当前节点的值,将较小的节点连接到新链表中。具体步骤如下:
首先处理两个链表都不为空的情况,通过循环比较两个链表当前节点的值,将较小的节点接入新链表:
while (list1 && list2) {
if (list1->val < list2->val) {
if (Tail == NULL) {
Head = Tail = list1;
} else {
Tail->next = list1;
Tail = list1;
}
list1 = list1->next;
} else {
if (Tail == NULL) {
Head = Tail = list2;
} else {
Tail->next = list2;
Tail = list2;
}
list2 = list2->next;
}
}
然后处理其中一个链表为空的情况,直接将非空链表剩余部分接入新链表:
if (list1 == NULL) {
return list2;
}
if (list2 == NULL) {
return list1;
}
if (list1) {
Tail->next = list1;
Tail = list1;
}
if (list2) {
Tail->next = list2;
Tail = list2;
}
return Head;
2. 链表的分割
题目
给定链表的头指针 ListNode* pHead
和一个值 x
,编写代码将所有小于 x
的节点排在其余节点之前,且不改变原数据的顺序,返回重新排列后的链表头指针。
示例
- 输入:head = [3,2,1,3,4,5,6],x = 4 输出:[3,2,1,3,5,6]
分析
可以通过创建两个新链表来分别存储小于 x
和大于等于 x
的节点,最后将两个链表连接起来。为了方便处理边界情况,使用哨兵位头节点:
首先创建两个哨兵位头节点分别用于存储小于 x
和大于等于 x
的节点:
ListNode* SmallHead = (ListNode*)malloc(sizeof(ListNode));
ListNode* SmallTail = SmallHead;
ListNode* BigHead = (ListNode*)malloc(sizeof(ListNode));
ListNode* BigTail = BigHead;
ListNode* cur = pHead;
遍历原链表,将节点根据值的大小分别接入对应的链表:
while (cur) {
if (cur->val < x) {
ListNode* temp = (ListNode*)malloc(sizeof(ListNode));
SmallTail->next = temp;
SmallTail = temp;
SmallTail->val = cur->val;
} else {
ListNode* temp = (ListNode*)malloc(sizeof(ListNode));
BigTail->next = temp;
BigTail = temp;
BigTail->val = cur->val;
}
cur = cur->next;
}
最后连接两个链表并返回结果:
BigTail->next = NULL;
SmallTail->next = BigHead->next;
return SmallHead->next;
3. 链表的回文结构判断
题目
给定链表的头指针 A
,设计一个时间复杂度为 O(n)、额外空间复杂度为 O(1) 的算法判断其是否为回文结构。
示例
- 输入:1->2->2->1 输出:true
分析
可以通过找到链表的中间节点,将后半部分链表反转,然后比较前后两部分是否相同来判断是否为回文结构。
首先找到链表的中间节点:
ListNode* fast = A;
ListNode* slow = A;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
然后反转后半部分链表:
ListNode* reverse_tail = slow;
ListNode* slow_prev = slow;
slow = slow->next;
ListNode* slow_next = slow->next;
while (slow) {
slow->next = slow_prev;
slow_prev = slow;
slow = slow_next;
slow_next = slow_next->next;
}
接着比较前后两部分是否相同:
// 处理特殊情况
if (slow == NULL || slow->next == NULL) {
return false;
}
if (slow->next == NULL) {
if (A->val == slow->val) {
return true;
} else {
return false;
}
}
// 正常情况比较
while (slow_prev != reverse_tail) {
if (slow_prev->val == A->val) {
A = A->next;
slow_prev = slow_prev->next;
} else {
return false;
}
}
// 处理奇偶不同情况
if (slow_prev != A) {
if (slow_prev->val == A->val) {
return true;
} else {
return false;
}
}
return true;
总结
本文介绍了链表的合并、分割和回文结构判断这三个问题。通过这些问题的解决,巩固了反转链表、找中间节点等相关知识,帮助我们更好地理解和应用链表操作的相关算法。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...