关于链表问题,个人总结了几个考点,可以作为解题思路,今后也会补充。
1. 找到链表的中点,可以使用快慢指针。
2. 单链表翻转。
3. 两个链表合并。
-----------------------------------单链表中点-----------------------------------------------------------------------------------------------------------------
如何在单链表中找到链表的中点,最暴力的方法是遍历链表,求得链表的长度,在遍历链表的一半找到中点,但是如果遇到特别长的链表,这个效率太差,所以我们可以使用“快慢指针”的方法来解决。
上例子:求0 --> 1 --> 2 --> 3 -->4 -->5 --> NULL 的中点。
设置slow,fast指针,slow指向head,fast指向head->next,快指针一次走两步,慢指针一次走一步,当快指针走到最后的时候,慢指针就是中点啦。
代码如下:
/**
* Definition of ListNode
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
class Solution {
public:
/**
* @param head: The first node of linked list.
* @return: You should return the head of the sorted linked list,
using constant space complexity.
*/
ListNode *sortList(ListNode *head) {
// write your code here
if (head == NULL || head->next == NULL) {
return head;
}
ListNode *slow, *fast;
slow = head;
fast = head;
while (fast->next != NULL && fast->next->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
ListNode *mid = slow->next;
slow->next = NULL;
ListNode *l1 = sortList(head);
ListNode *l2 = sortList(mid);
ListNode *sorted = mergeList(l1, l2);
return sorted;
}
ListNode* mergeList(ListNode *list1, ListNode *list2) {
if (list1 == NULL) {
return list2;
}
if (list2 == NULL) {
return list1;
}
ListNode *dummy = new ListNode(-1);
ListNode *temp = dummy;
while (list1 != NULL && list2 != NULL) {
if (list1->val < list2->val) {
temp->next = list1;
list1 = list1->next;
} else {
temp->next = list2;
list2 = list2->next;
}
temp = temp->next;
}
if (list1 != NULL) {
temp->next = list1;
}
if (list2 != NULL) {
temp->next = list2;
}
return dummy->next;
}
};
翻转链表,这个就不细说了,需要三个指针分别指向前一个节点,当前节点,后一个节点
依然是代码:
ListNode *reverseList(ListNode *head) {
if (head == NULL || head->next == NULL) {
return head;
}
ListNode *pre, *cur;
pre = head;
cur = head->next;
head->next = NULL;
while (cur != NULL) {
ListNode *temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
来一个例子说明吧:
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes' values.
For example,
Given {1,2,3,4}
, reorder it to {1,4,2,3}
.
我们试一个比较长的链表,为了容易理解,节点中的数字代表节点的位置,并不是说这个链表的有序链表,因为这样比较直观:
0 --> 1--> 2--> 3--> 4--> 5--> 6--> 7--> 8--> 9--> NULL
排序后应该是这样的:
0 --> 9--> 1-->
8--> 2--> 7-->
3--> 6--> 4-->
5--> NULL
排序后的链表特点是,奇数位置的节点正序(位置),偶数位置的节点是逆序(位置),由此可以想见,就是要把链表分成两部分,对后一部分进行翻转,然后再把两个链表归并起来。对于归并,根据要求不同会略有不同,但是万变不离其宗,但是要注意链表的“来龙去脉”。
把代码贴上来吧,自己写的,可能有点挫。。。。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
if (head == NULL || head->next == NULL) {
return;
}
ListNode *fast = head, *slow = head;
while (fast->next != NULL && fast->next->next != NULL) {
fast = fast->next->next;
slow = slow->next;
}
fast = slow->next;
slow->next = NULL;
slow = head;
fast = reverseList(fast);
ListNode* dummy = new ListNode(0);
ListNode* temp = dummy;
while (slow != NULL && fast != NULL) {
temp->next = slow;
temp = temp->next;
slow = slow->next;
temp->next = fast;
temp = temp->next;
fast = fast->next;
}
if (slow != NULL) temp->next = slow;
if (fast != NULL) temp->next = fast;
head = dummy->next;
}
ListNode* reverseList(ListNode* head) {
if (head == NULL || head->next == NULL) {
return head;
}
ListNode* pre = head;
ListNode* cur = head->next;
ListNode* temp = head;
head->next = NULL;
while (cur != NULL) {
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
head = pre;
return head;
}
};