876:鏈表的中間節點
206:反轉鏈表
143:重排練表
鏈表的中間節點
這個題一看就是最簡單的快慢指針,但是在具體實現的時候我還是猶豫思考了一下:要不要在鏈表前面放置啞節點,快指針應該什么時候判斷已經到達結尾。但是單純的想并沒有什么結果。對于這種不是算法本身的問題,而只是實現細節的問題,不要多想,沒有很大的意義,只要對于每種情況都動手(腦)模擬一遍,看這么樣能夠讓情形變得更加簡單即可。
我思考了一下以后寫了一下自己的代碼:
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode* middleNode(ListNode* head) {ListNode *fast = head, *slow = head;while(fast->next != nullptr && fast->next->next !=nullptr){fast = fast->next->next;slow = slow->next;}if(fast->next == nullptr) return slow;else return slow->next;}
};
看了一下題解的實現方法,更加的簡潔。我的這種雖然能夠解決問題,但是沒有考慮另一種判斷快指針是否到達結尾的方式:fast != nullptr && fast->next != nullptr
。以后應該都考慮一下,然后按照最簡單的方式實現。
反轉鏈表
就是將一個鏈表進行反轉。
不知怎么的我把題目看成了反轉輸出,可能是因為ACM里面很少對原數據進行操作的原因。反轉輸出我想到的只有遞歸輸出。
有兩種方法,迭代法和遞歸法。迭代法很容易想到,也很容易實現。
在實現迭代法的時候我在想能不能使用C++中的二級指針簡化操作(因為一般刪除之類的使用二級指針都會方便許多),但是稍微思考一下發現,我們使用二級指針是為了解決無法原地修改指針的問題,但是這個是可以直接修改的(因為每一個節點都要進行修改),而且還必須需要保存前一個節點的信息,因此使用二級指針就完全是雞肋。
遞歸法我想的是重新寫一個函數,然后進行處理。但是看到題解中一個十分優美的實現方式,雖然效率不一定高(不一定比迭代法低)
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode* reverseList(ListNode* head) {/*ListNode* pre = nullptr, *cur = head, *next = nullptr;while(cur != nullptr){next = cur->next;cur->next = pre;pre = cur;cur = next;}return pre;*/if(head == nullptr || head->next == nullptr){return head;}ListNode *tail = reverseList(head->next);head->next->next = head;head->next = nullptr;return tail;}
};
其中注釋部分為迭代法
遞歸法中比較難理解的就是返回的那個指針是什么,其實這個指針是鏈表的尾部,也就是新鏈表的頭部。
重排鏈表
將鏈表從頭部挑一個,尾部挑一個,然后重復這個過程直到鏈表為空。
我自己完全沒有思路,是學習了題解以后才明白的。
需要分三步完成重排:
- 找到鏈表的中點
- 將中點后面的鏈表反轉
- 將前后兩個鏈表合并
我手擼了一下,因為才學習了上面兩個問題,所以代碼寫的很流暢,但是為了盡可能少命名變量可能看起來有些迷惑。
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:void reorderList(ListNode* head) {if(head == nullptr) return;// 求鏈表的中點ListNode *fast =head, *slow = head;while(fast->next != nullptr && fast->next->next != nullptr){fast = fast->next->next;slow = slow->next;}// 將鏈表的后半部分反轉fast = slow->next;ListNode *pre = nullptr, *next = nullptr;while(fast != nullptr){next = fast->next;fast->next = pre;pre = fast;fast = next;}fast = pre;//進行合并slow->next = nullptr;slow = head;while(fast != nullptr){next = slow->next;slow->next = fast;pre = fast->next;fast->next = next;slow = next;fast = pre;}}
};