1.給定一個帶有頭結點 head 的非空單鏈表,返回鏈表的中間結點。如果有兩個中間結點,則返回第二個中間結點。
輸入:[1,2,3,4,5]
輸出:此列表中的結點 3 (序列化形式:[3,4,5])
返回的結點值爲 3 。 (測評系統對該結點序列化表述是 [3,4,5])。
輸入:[1,2,3,4,5,6]
輸出:此列表中的結點 4 (序列化形式:[4,5,6])
解法思路:先求出單鏈表的長度length,再定義一個指針初識指向單鏈表的頭部,讓指針走length/2步,即爲所求。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int Getlength(struct ListNode* head)
{
int count = 0;
if(head==NULL)
{
return 0;
}
struct ListNode* cur=head;
while(cur!=NULL)
{
count++;
cur=cur->next;
}
return count;
}
struct ListNode* middleNode(struct ListNode* head) {
if(head==NULL)
{
return NULL;
}
int k = Getlength(head);
int step = k/2;
struct ListNode* middle = head;
while(step)
{
middle=middle->next;
step--;
}
return middle;
}
2.刪除鏈表中等於給定值 val 的所有節點。
示例:
輸入: 1->2->6->3->4->5->6, val = 6
輸出: 1->2->3->4->5
解法思路:定義一個指針cur指向鏈表的第二個節點,指針prev初始值爲NULL,
只要cur不空,就遍歷整個鏈表,同時cur 與 prev分別向後走一步。若遇到要刪除的值,就進行單鏈表的刪除操作。若還未遇到,就一直向後遍歷,直到cur爲NULL。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
if(head == NULL)
{
return NULL;
}
struct ListNode* cur = head->next ;
struct ListNode* prev = head;
while(cur!=NULL)
{
if(cur->val != val)
{
prev = cur;
cur = cur->next;
}
else
{
struct ListNode* old_cur = cur;
cur = cur->next;
prev->next = cur;
free(old_cur);
}
}
struct ListNode* newHead = head;
if(head->val == val)
{
newHead = head->next;
free(head) ;
}
return newHead;
}
3.反轉一個單鏈表。
示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL
解法思路:可以對舊鏈表進行頭刪操作,然後將刪除的節點頭插在新鏈表中,最後返回新鏈表的頭結點。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
if(head == NULL)
{
return NULL;
}
struct ListNode* newHead = NULL;
struct ListNode* node ;
while(head != NULL)
{
//對舊鏈表做頭刪操作
node = head ;
head = head->next;
//把刪掉的節點頭插在新鏈表中
node->next = newHead;
newHead = node ;
}
return newHead;
}
4.輸入一個鏈表,輸出該鏈表中倒數第k個結點。
解法思路:定義兩個指針fast與slow,先讓fast走k步,再讓兩個指針每次走一步,直到fast爲NULL,則slow指向的即爲所求。
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* fast = pListHead;
ListNode* slow = pListHead;
//先讓fast走
while(k)
{
fast = fast->next;
k--;
}
//再讓兩個指針每次走一步
while(fast!=NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
5.將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
示例:
輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4
解法思路:定義兩個指針與一個新鏈表的頭尾指針。讓兩個指針分別指向兩個鏈表。逐一的進行值比較,然後將節點插入新的鏈表的末端。最後返回新鏈表的頭指針。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
if(l1 == NULL)
{
return l2;
}
if(l2 == NULL)
{
return l1;
}
struct ListNode* p1 = l1;
struct ListNode* p2 = l2;
struct ListNode* r = NULL; //新鏈表的頭
struct ListNode* rtail = NULL; //新鏈表的尾
while(p1 && p2)
{
if(p1->val <= p2->val)
{
if(rtail == NULL)
{
r = rtail = p1;
}
else
{
rtail->next = p1;
rtail = rtail->next;
}
p1 = p1->next;
}
else
{
if(rtail == NULL)
{
r = rtail = p2;
}
else
{
if(rtail == NULL)
{
r = rtail = p2;
}
else
{
rtail->next = p2;
rtail = p2;
}
}
p2 = p2->next;
}
}
if(p1 == NULL)
{
rtail->next = p2;
}
if(p2 == NULL)
{
rtail->next = p1;
}
return r ;
}
6.編寫代碼,以給定值x爲基準將鏈表分割成兩部分,所有小於x的結點排在大於或等於x的結點之前
給定一個鏈表的頭指針 ListNode* pHead,請返回重新排列後的鏈表的頭指針。注意:分割以後保持原來的數據順序不變。
解法思路:將鏈表分割成三部分,然後進行遍歷,按要求插入即可。
ListNode* partition(ListNode* pHead, int x) {
// write code here
if(pHead == NULL)
{
return NULL;
}
//將鏈表分割成三部分,小,等於,大
ListNode* lt = NULL; //小的部分的頭
ListNode* ltail = NULL ;//小的部分的尾
ListNode* eq = NULL ; //相等的部分的頭
ListNode* eqtail = NULL;//相等的部分的尾
ListNode* gt = NULL; //大的部分的頭
ListNode* gtail = NULL ;//大的部分的尾
ListNode* cur = pHead;
while(cur != NULL)
{
if(cur->val < x)
{
if(lt == NULL)
{
lt = ltail = cur;
}
else
{
ltail->next = cur;
ltail = ltail->next;
}
}
else if(cur->val == x)
{
if(eq == NULL)
{
eq = eqtail = cur;
}
else
{
eqtail->next = cur ;
eqtail = eqtail->next ;
}
}
else
{
if(gt == NULL)
{
gt = gtail = cur;
}
else
{
gtail->next = cur;
gtail = gtail->next;
}
}
cur = cur->next ;
}
return pHead;
}
7.編寫一個程序,找到兩個單鏈表相交的起始節點。
如下面的兩個鏈表:
在c1處相交,則返回c1的地址。
解法思路:分別求出兩個鏈表的長度len1和len2,定義兩個指針longer與shorter,先讓長的走兩者長度之差步,以保證兩個指針的相對位置一樣。然後循環遍歷,只要節點的位置不同則繼續向後走,直到節點地址相等時跳出循環並返回此相交節點的地址。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int Getlength(struct ListNode* head)
{
int count = 0 ;
struct ListNode* cur = head;
while(cur!=NULL)
{
count++;
cur = cur->next;
}
return count;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if(headA == NULL)
{
return NULL;
}
if(headB == NULL)
{
return NULL;
}
int len1 = Getlength(headA) ;
int len2 = Getlength(headB) ;
struct ListNode* longer ;
struct ListNode* shorter;
int dif; //長度之差
if(len1 >= len2)
{
longer = headA;
shorter = headB;
dif = len1 - len2;
}
else
{
longer = headB;
shorter = headA;
dif = len2 - len1;
}
//先讓長的走dif步保證兩者相對距離一樣
while(dif)
{
longer = longer->next;
dif--;
}
while(longer!=shorter)
{
longer = longer->next;
shorter = shorter->next;
}
//注意,此處是地址相等即可
if(longer == shorter)
{
return longer;
}
else
return NULL;
}
8.給定一個鏈表,判斷鏈表中是否有環。
解法思路:利用快慢指針法。具體解法請看以下代碼。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* fast = head;
struct ListNode* slow = head;
do{
if(fast == NULL)
{
break;
}
fast = fast->next;
if(fast == NULL)
{
break;
}
fast = fast->next;
slow = slow->next;
}while(fast != slow);
if(fast == NULL)
{
return false;
}
else
return true;
}