一、使用常量空間複雜度在O(n log n)時間內對鏈表進行排序。java
思路:算法
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: //找到鏈表中的中點 ListNode *findMiddle(ListNode *head){ ListNode *chaser = head; ListNode *runner = head->next; while(runner !=NULL &&runner->next != NULL){ chaser = chaser->next; runner = runner->next->next; } return chaser; } //將兩組鏈表進行排序 ListNode *mergeTwoLists(ListNode* l1, ListNode* l2){ if(l1==NULL) return l2; if(l2==NULL) return l1; ListNode *dummy = new ListNode(0); ListNode *head = dummy; while(l1!=NULL && l2!=NULL){ if(l1->val > l2->val){ head->next = l2; l2 = l2->next; }else{ head->next = l1; l1 = l1->next; } head = head->next; } if(l1==NULL) head->next = l2; if(l2==NULL) head->next = l1; return dummy->next; } ListNode *sortList(ListNode *head) { if(head==NULL || head->next == NULL) return head; ListNode* middle = findMiddle(head); ListNode* right = sortList(middle->next); middle -> next = NULL; ListNode* left = sortList(head); return mergeTwoLists(left, right); } };
二、給出單鏈表L:L 0→L 1→...→L n-1→L n,數組
將其從新排序爲:L 0→L n→L 1→L n-1→L 2→L n-2→......
您必須在不改變節點值的狀況下就地執行此操做。
例如,
給定{1,2,3,4},將其從新排序爲{1,4,2,3}。dom
思路:快慢指針找到中間節點,將後面的鏈表反轉(前插法),合併鏈表函數
/** * 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) { ListNode *slow = head; ListNode *fast = head; //快慢指針找到中間節點 while(fast->next!=NULL && fast->next->next!=NULL){ slow = slow->next; fast = fast->next->next; } //拆分鏈表,並反轉中間節點以後的鏈表 ListNode *after = slow->next; slow->next = NULL; ListNode *pre = NULL; while(after!=NULL){ ListNode *temp = after->next; after->next = pre; pre = after; after = temp; } // 合併兩個表 ListNode *left = head; after = pre; while(left!=NULL && after!=NULL){ ListNode *ltemp = left->next; ListNode *rtemp = after->next; left->next = after; left = ltemp; after->next = left; after = rtemp; } } };
三、給定鏈表,返回循環開始的節點。 若是沒有循環,則返回null。
跟進:
你能不用額外的空間解決它嗎?spa
思路:指針
1)首先判斷是否有環,有環時,返回相遇的節點,無環,返回null
2)有環的狀況下, 求鏈表的入環節點
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *detectCycle(ListNode *head) { ListNode *slow = head; ListNode *fast = head; //找到相遇點 while(fast!=NULL && fast->next!=NULL){ slow=slow->next; fast=fast->next->next; //若是快慢指針相遇 if(slow==fast){ ListNode *temp = NULL; //一邊走一邊將走過的路清空,當遇到空時,此時就是相遇點 while(head->next){ temp = head->next; head->next = NULL; head = temp; } return head; } } return NULL; } };
四、給定一個鏈表,肯定它是否有一個循環。
跟進:
你能不用額外的空間解決它嗎?code
思路:blog
利用快慢節點相遇即有環,排序
慢節點一次走一格
快捷點一次走兩格
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: bool hasCycle(ListNode *head) { ListNode *slow = head; ListNode *fast = head; //找到相遇點 while(fast!=NULL && fast->next!=NULL){ slow=slow->next; fast=fast->next->next; //若是快慢指針相遇 if(slow==fast) return true; } return false; } };
五、給出鏈表,使得每一個節點包含一個附加的隨機指針,該指針能夠指向列表中的任何節點或爲空。
返回列表的深層副本。
思路:
先拷貝新節點,插入到原節點的後邊;而後再 拷貝隨機指針;最後將新節點從原鏈表中分離出,注意要保證原鏈表正常。
/** * Definition for singly-linked list with a random pointer. * struct RandomListNode { * int label; * RandomListNode *next, *random; * RandomListNode(int x) : label(x), next(NULL), random(NULL) {} * }; */ class Solution { public: RandomListNode *copyRandomList(RandomListNode *head) { RandomListNode *p,*copy; if (!head) return NULL; //先將拷貝原節點產生的新節點,放在原節點的後面 for(p=head;p;p=p->next){ copy = new RandomListNode(p->label); copy->next = p->next; p = p->next = copy; } //拷貝random指針 for(p=head;p;p=copy->next){ copy = p->next; copy->random = (p->random?p->random->next:NULL); } //刪除新節點 for(p=head,head=copy=p->next;p;){ p = p->next = copy->next; copy = copy->next = (p?p->next:NULL); } return head; } };
六、將位置m的連接列表反轉到n。 在原地和一次經過。
例如:
給定1-> 2-> 3-> 4-> 5-> NULL,m = 2且n = 4,
return1->4->3-> 2->5-> NULL。
注意:
給定m,n知足如下條件:
1≤m≤n≤列表長度。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *reverseBetween(ListNode *head, int m, int n) { ListNode *dummy = new ListNode(-1); ListNode *preStart,*Start; dummy->next = head; preStart = dummy; Start = head; for(int i=1;i<m;i++){ preStart = Start; Start = Start->next; } for(int i=0;i<n-m;i++){ ListNode *temp = Start->next; Start->next = temp->next; temp->next = preStart->next; preStart->next = temp; } return dummy->next; } };
七、給定鏈表和值x,對其進行分區,使得小於x的全部節點都在大於或等於x的節點以前。
您應該保留兩個分區中每一個分區中節點的原始相對順序。
例如,
給定1-> 4-> 3-> 2-> 5-> 2和x = 3,
return1-> 2->2->4->3->5。
思路:
建立兩張鏈表,分別我list01和list01
把節點值小於x的節點連接到鏈表1上,節點值大等於x的節點連接到鏈表2上。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *partition(ListNode *head, int x) { //建立兩個鏈表 ListNode *list01 = new ListNode(-1); ListNode *list02 = new ListNode(-2); ListNode *cur1 = list01; ListNode *cur2 = list02; while(head!=NULL){ //把節點值小於x的節點連接到鏈表1上 if(head->val < x){ cur1->next = head; cur1=cur1->next; } //節點值大等於x的節點連接到鏈表2上 else{ cur2->next = head; cur2=cur2->next; } head = head->next; } //合併兩個鏈表 cur1->next = list02->next; cur2->next = NULL; return list01->next; } };
八、給定一個列表,將列表向右旋轉k個位置,其中k爲非負數。
例如:
給定1-> 2-> 3-> 4-> 5-> NULL和k = 2,
返回4-> 5-> 1-> 2-> 3-> NULL。
思路:
先遍歷一遍,得出鏈表長度len,注意k可能會大於len,所以k%=len。
將尾結點next指針指向首節點,造成一個環,接着日後跑len-k步,從這裏斷開,就是結果
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *rotateRight(ListNode *head, int k) { if(head==NULL) return NULL; ListNode *p=head; int len=1; //計算連鏈表的長度 while(p->next){ len++; p=p->next; } k = len - k%len; //首尾相連 p->next = head; for(int i=0;i<k;i++){ p=p->next; } head = p->next; p->next = NULL; return head; } };
九、給定已排序的連接列表,刪除全部具備重複數字的節點,只留下原始列表中的不一樣數字。
例如,
給定1-> 2-> 3-> 3-> 4-> 4-> 5,返回1-> 2-> 5。
給定1-> 1-> 1-> 2-> 3,return2-> 3。
思路:
首先要找到第一個非重複的節點做爲頭結點,
直接找比較麻煩,能夠添加一個新結點list做爲僞頭結點,
最後返回list->next便可。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *deleteDuplicates(ListNode *head) { if(head==NULL) return NULL; ListNode *list = new ListNode(head->val-1); list->next = head; ListNode *preStart = list; while(preStart->next && preStart->next->next){ ListNode *Start = preStart->next; ListNode *aftStart = Start->next; if(Start->val!=aftStart->val){ preStart->next = Start; preStart = Start; }else{ while(aftStart && Start->val==aftStart->val){ aftStart=aftStart->next; } preStart->next = aftStart; } } return list->next; } };
十、給定已排序的連接列表,刪除全部重複項,使每一個元素只出現一次。
例如,
給定1-> 1-> 2,return1-> 2。
給定1-> 1-> 2-> 3-> 3,返回1-> 2-> 3。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *deleteDuplicates(ListNode *head) { if(head == NULL || head->next == NULL) return head; ListNode* p1 = head; while(p1 != NULL && p1->next != NULL) { ListNode* p2 = p1->next; if(p1->val != p2->val) { p1->next = p2; p1 = p1->next; continue; } while(p2->next != NULL && p1->val == p2->next->val) p2 = p2->next; p1->next = p2->next; delete p2; p1 = p1->next; } return head; } };
十一、合併兩個已排序的連接列表並將其做爲新列表返回。 新列表應該經過拼接前兩個列表的節點來完成。
思路:和歸併排序的思想同樣
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) { ListNode *head = new ListNode(0); ListNode *t = head; while (l1 != NULL || l2 != NULL) { if (l1 == NULL) { t->next = l2; l2 = l2->next; } else if (l2 == NULL) { t->next = l1; l1 = l1->next; } else if (l1->val < l2 -> val){ t->next = l1; l1 = l1->next; } else { t->next = l2; l2 = l2->next; } t = t->next; } return head->next; } };
十二、給定鏈表,一次反轉鏈表k的節點並返回其修改後的列表。
若是節點數不是k的倍數,那麼最後的剩餘節點應該保持不變。
您可能沒法更改節點中的值,只能更改節點自己。
只容許常量內存。
例如,
鑑於此鏈表:1-> 2-> 3-> 4-> 5
對於k = 2,您應該返回:2-> 1-> 4-> 3-> 5
對於k = 3,您應該返回:3-> 2-> 1-> 4-> 5
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *reverseKGroup(ListNode *head, int k) { /* if(head==NULL || head->next==NULL || k<2) return head; ListNode *dummy = new ListNode(-1); dummy->next = head; ListNode *Start = head; ListNode *preStart = dummy; ListNode *temp; int len = 1; while(head!=NULL){ len++; head=head->next; } for(int i=0;i<len/2;i++){ for(int j=i+1;j<len;j++){ temp = Start->next; Start->next = temp->next; temp->next = preStart->next; preStart->next = temp; } preStart = Start; Start = Start->next; } return dummy->next; */ if(head == NULL || head->next == NULL || k < 2) return head; ListNode *dummy = new ListNode(-1); dummy->next = head; ListNode *pre = dummy, *cur = head, *temp; int len = 0; //計算鏈表的長度 while (head != NULL) { len ++ ; head = head->next; } for (int i = 0; i < len / k; i ++ ) { for (int j = 1; j < k; j ++ ) { temp = cur->next; cur->next = temp->next; temp->next = pre->next; pre->next = temp; } pre = cur; cur = cur->next; } return dummy->next; } };
1三、給定鏈表,交換每兩個相鄰節點並返回其頭部。
例如,
給定1-> 2-> 3-> 4,您應該返回列表as2-> 1-> 4-> 3。
您的算法應該只使用恆定空間。 您可能沒法修改列表中的值,只能更改節點自己。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *swapPairs(ListNode *head) { if(head==NULL || head->next==NULL ) return head; ListNode *dummy = new ListNode(-1); dummy->next = head; ListNode *Start = head; ListNode *aftStart = head->next; ListNode *preStart = dummy; ListNode *temp; while(Start!=NULL && aftStart!=NULL){ temp = aftStart->next; Start->next = temp; aftStart->next = Start; preStart->next = aftStart; preStart = Start; Start = temp; aftStart = temp->next; } return dummy->next; } };
1四、給定鏈表,從列表末尾刪除第n個節點並返回其頭部。
例如,
給定鏈表:1-> 2-> 3-> 4-> 5,n = 2。
從末尾刪除第二個節點後,鏈表變爲1-> 2-> 3-> 5。
注意:
給定n將始終有效。
嘗試一次性完成此操做。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *removeNthFromEnd(ListNode *head, int n) { if(head==NULL ) return head; ListNode *dummy = new ListNode(0); dummy->next = head; head = dummy; ListNode *slow = head; ListNode *fast = head; for(int i=0;i<n;i++){ fast = fast->next; } while(fast->next!=NULL){ fast = fast->next; slow = slow->next; } ListNode *temp = slow->next; slow->next = slow->next->next; delete temp; return dummy->next; } };