大三準備面試,開始做leetCode,遇到有意思的題在這裏做個總結。
這是一道easy題,但我已經很久沒用過鏈表所以還是做個總結。
做leetCode的題雖然不用自己寫main函數,但我還是習慣自己寫一個main函數去做測試。在寫main函數的過程中發現自己已經不會建表…
弄了半天總算把建表的邏輯弄明白,建表邏輯如下:
#define NUM 1
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
int main(){
ListNode *root,*node;
root = new ListNode(-1);
root->next = NULL;
node = root;
for(int i = 0; i< NUM;i++){
ListNode *now = new ListNode(i);
node->next = now;
node = now;
}
node -> next = NULL;
}
一開始有根節點和一個普通節點,讓根節點和普通節點爲統一節點以便後面的循環。這時候鏈表只有一個節點——根節點。然後在循環中建立一個新的節點,讓原有鏈表的末端指向新的節點,再把鏈表的末端擴展到包含新節點的位置。
遍歷鏈表:
node = root;
while(node != NULL){
cout<<node->val<<endl;
node = node->next;
}
節點不爲空就繼續往下,直到爲空
現在我們再來看原問題,問題要求我們去除鏈表的倒數第n個節點。我這裏使用的方法是用兩個指針一前一後去做遍歷,前面的指針要比後面的指針快n個位置,這樣當前面的指針到尾的時候,後面那個指針就讓當前節點的下一節點爲下下節點就可以了。
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *node,*node2;
node = node2 = head;
int temp = 0;
while(node->next!= NULL){
node = node->next;
if(temp >= n){
node2 = node2->next;
}
temp++;
}
if(temp+1==n && node2->next != NULL)
return node2->next;
if(node2->next == NULL){
return NULL;
}else if (node2->next->next == NULL && node2->next != NULL){
node2->next = NULL;
}else if(node2->next != NULL && node2->next->next != NULL){
node2->next = node2->next->next;
}
return head;
}
首先我們要注意到:
if(node2->next == NULL){
return NULL;
}else if (node2->next->next == NULL && node2->next != NULL){
node2->next = NULL;
}else if(node2->next != NULL && node2->next->next != NULL){
node2->next = node2->next->next;
}
在每次使用指針的時候,我們都要注意越界的問題,必須先要進行判斷該指針是否爲空,如若不然很容易造成運行出錯。比如說鏈表爲1,且我要去除倒數第一個節點時,如果不判斷node2->next是否爲空,那麼勢必會因爲1後面是空而造成運行出錯。
同時還有當鏈表的長度和n是一樣的時候的特殊處理:
if(temp+1==n && node2->next != NULL)
return node2->next;
因爲前面的邏輯只能去掉node2之後的節點或者直接返回空,如果遇到1->2,n=2時就會答案錯誤。
以上代碼是我通過leetCode的代碼,但在寫這篇博客的時候,我突然意識到還是有問題,如果傳進來的根節點就是空的,那我的代碼還是會運行出錯,所以應該再加一個根節點是否爲空的判斷。
總之遇到指針的問題必須要時時刻刻注意指針越界的問題。