LeetCode連結串列篇C++ [逆序、迴文、逆序II]
阿新 • • 發佈:2019-01-01
1. 關鍵點
- 結點定義
//Definition for singly-linked list.
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
迴圈過程如下:
next = head->next;
head->next = prev;
prev = head;
head = next;
初始條件為“` prev = NULL;
迭代停止條件為 head == NULL
2. 建立連結串列
ListNode* create()
{
ListNode* pHead, *pNode, *temp;
int x;
pHead = pNode = (ListNode*)malloc(sizeof(ListNode)); //帶頭節點的連結串列
// 先把第一個結點做了。
printf("請輸入連結串列資料,以小於0 的為結束標誌:\n");
scanf("%d", &x);
pNode->val = x;
pNode->next = NULL;
scanf("%d", &x);
while (x>=0)
{
temp = (ListNode*)malloc(sizeof(ListNode));
temp->val = x;
temp->next = NULL;
pNode->next = temp;//上一個結點指向當前新建立的結點
pNode = temp;
scanf("%d", &x);
}
pNode->next = nullptr;
return pHead;
}
3. 實現逆序
ListNode* ReverseLink(LINK_NODE *head)
{
ListNode *next;
ListNode *prev = NULL;
while(head != NULL)
{
next = head->next;
head->next = prev;
prev = head;
head = next;
}
return prev; //返回的是prev
}
4. 判斷迴文
1 2 3 4 5 5 4 3 2 1 -> 是迴文
同樣藉助上面的逆序的方法,採用龜兔演算法
- 【234. Palindrome Linked List】
迴文連結串列的特點就是對稱,那麼要判斷是否迴文就可以用兩個指標指向對稱的節點,看裡面的資訊是否一樣。即對稱的位置是否有對稱的資訊。由於是單向連結串列,不能同時用兩個指標從頭尾向內部遍歷取值比較。那麼就考慮從連結串列中間開始,用兩個指標向兩頭遍歷取值比較,顯然這也需要進行連結串列逆置。
(1). 獲取連結串列的中點,使用龜兔演算法的方法,兩個指標,一個遍歷速度是另外一個的兩倍,找到中點
(2). 然後反轉連結串列的後半部分
(3). 對比連結串列的前後兩個部分是否一樣
(4). 最後將原連結串列的後半部分反轉恢復原來的連結串列(恢復作案現場)
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (!head || !head->next) return true;
ListNode *slow = head, *fast = head;
while (fast->next && fast->next->next) {
slow = slow->next;//slow 每次移動一個
fast = fast->next->next;//fast 每次移動2位
}
ListNode *last = slow->next, *pre = head;
ListNode* prev = NULL;
while (last != NULL) //這裡就是前面的逆序部分
{
ListNode* tmp = last->next;
last->next = prev;
prev = last;
last = tmp;
}
while (prev) //一一與正序的進行比較
{
if (prev->val != pre->val)
return false;//只要有不相等,提前結束
prev = prev->next;
pre = pre->next;
}
return true;
}
};
5. 部分逆序
- 只翻轉從m到n部分的連結串列
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int m, int n) {
int L = 0;//total length
ListNode* result = NULL;
ListNode* pre = head;
ListNode* prev = head;
while (pre != NULL)
{
L++;
pre = pre->next;//求總長度用
}
if (m > n || m < 1 || n < 1 || m > L || n > L)
return NULL; //不滿足條件,返回NULL
if (m == n)
return head;// 不翻轉
for (int i = 1; i < m; i++)
prev = prev->next;//此時的prev之後的需要逆轉
ListNode* result2 = head;
ListNode* Next;
ListNode* PreNode = NULL; //用來記錄前一個結點
ListNode* Now = prev; //需要反轉的結點
for (int i = m; i <= n; i++) //從m到n, 進行反轉,與上面的逆序操作一樣
{
Next = Now->next;
Now->next = PreNode;//反轉
PreNode = Now;
Now = Next;
}
int u = 1;
ListNode* result3 = head;//最後要返回的結果儲存
while (u < m-1 && result2->next !=NULL)
{
u++;
result2 = result2->next;//獲取不變的第一部分
}
if (m == 1)
{
result3 = PreNode;//從第一個開始的話,就沒有前面了部分了。
}
else
{
result2->next = NULL;
result2->next = PreNode;//接上第二部分
}
ListNode* tmp2 = result3;
u = 1;
while (u < n )
{
tmp2 = tmp2->next;
u++;
}
if (tmp2 != NULL)
tmp2->next = Now;//接上第三部分
return result3;
}
};