目錄
- 1. 單鏈表相關練習題
- 1.1 移除鏈表元素
- 1.2 反轉鏈表
- 1.3 鏈表的中間結點
- 1.4 鏈表的倒數第k個結點
- 1.5 合并兩個有序鏈表
- 1.6 鏈表分割
- 1.7 鏈表的回文結構
- 1.8 相交鏈表
- 1.9 判斷一個鏈表中是否有環
- 1.10 尋找環狀鏈表相遇點
- 1.11 鏈表的深度拷貝
1. 單鏈表相關練習題
注:單鏈表結構上存在一定缺陷,所以鏈表相關的題目一般都針對與單鏈表。
1.1 移除鏈表元素
題目要求:
題目信息:
- 頭節點head
- 移除值val
題目鏈接:
移除鏈表元素
方法(順序處理法):
思路:分析鏈表結構與結點所處的位置(是否為空鏈表,結點是否為頭結點),分情況依次處理。
過程演示:
struct ListNode* removeElements4(struct ListNode* head, int val)
{struct ListNode* pre = NULL;struct ListNode* cur = head;while (cur){if (cur->val == val){//頭刪if (cur == head){head = head->next;free(cur);cur = head;}else//中間刪{pre->next = cur->next;free(cur);cur = pre->next;}}else{pre = cur;cur = cur->next;}}return head;
}
1.2 反轉鏈表
題目要求:
題目鏈接:
反轉鏈表
過程演示:
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* pre = NULL;struct ListNode* mid = head;struct ListNode* cur = NULL;if(head){cur = head->next;}while(mid){mid->next = pre;pre = mid;mid = cur;if(cur){cur = cur->next;}}return pre;}
1.3 鏈表的中間結點
題目要求:
題目鏈接:
鏈表的中間結點
過程演示(快慢指針法):
struct ListNode* middleNode(struct ListNode* head)
{struct ListNode* fast = head;struct ListNode* slow = head;while(fast != NULL && fast->next != NULL){fast = fast->next->next;slow = slow->next;}return slow;
}
1.4 鏈表的倒數第k個結點
題目要求:
題目鏈接:
倒數第k個結點
過程演示:
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{struct ListNode* cur = pListHead;struct ListNode* pre = pListHead;while(cur && k--){cur = cur->next;}if(k > 0){pre = NULL;}while(cur){pre = pre->next;cur = cur->next;}return pre;
}
1.5 合并兩個有序鏈表
題目要求:
題目鏈接:
合并兩個鏈表
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{struct ListNode* newhead = NULL;struct ListNode* cur = NULL;struct ListNode* newnode = NULL;if(list1 == NULL)return list2;if(list2 == NULL)return list1;while(list1 != NULL && list2 != NULL){if(list1->val <= list2->val){newnode = list1;list1 = list1->next;}else{newnode = list2;list2 = list2->next;}if(newhead == NULL){newhead = newnode;newnode->next = NULL;cur = newhead;}else{//在遍歷過程中,list1 或 list2 會等于 NULLcur->next = newnode;if(newnode != NULL){newnode->next = NULL;cur = cur->next;}}}//有一個鏈表本就為空if(list1){cur->next = list1;}if(list2){cur->next = list2;}return newhead;
}
1.6 鏈表分割
題目要求:
題目鏈接:
合并兩個鏈表
ListNode* BuyNewNode(int val){ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->val = val;newnode->next = nullptr;return newnode;}ListNode* partition(ListNode* pHead, int x) {ListNode* newhead1 = nullptr;ListNode* end1 = nullptr;ListNode* newhead2 = nullptr;ListNode* end2 = nullptr;ListNode* cur = pHead;while(cur){if(cur->val < x){if(newhead1 == nullptr){newhead1 = BuyNewNode(cur->val);end1 = newhead1; }else {end1->next = BuyNewNode(cur->val);end1 = end1->next;}}else {if(newhead2 == nullptr){newhead2 = BuyNewNode(cur->val);end2 = newhead2; }else {end2->next = BuyNewNode(cur->val);end2 = end2->next;}}cur = cur->next;}if(newhead1 == nullptr){newhead1 = newhead2;}else {end1->next = newhead2;}return newhead1;}
1.7 鏈表的回文結構
題目要求:
題目鏈接:
回文串
ListNode* reverse(ListNode* head){ListNode* pre = nullptr;ListNode* mid = head;ListNode* cur = head->next;while (mid){mid->next = pre;pre = mid;mid = cur;if (cur){cur = cur->next;}}return pre;}bool chkPalindrome(ListNode* A){//找相同,逆置//逐點比較//回文結構存在奇數個結點//獲取中間結點ListNode* fast = A;ListNode* slow = A;while(fast && fast->next){fast = fast->next->next;if(fast){slow = slow->next;}}//表1ListNode* newhead2 = slow->next;//表2slow->next = nullptr;ListNode* newhead1 = reverse(A);if(fast){newhead1 = newhead1->next;}while (newhead1 && newhead2 && newhead1->val == newhead2->val){newhead1 = newhead1->next;newhead2 = newhead2->next;}if (newhead1 == nullptr && newhead2 == nullptr){return true;}return false;}
1.8 相交鏈表
題目要求:
題目鏈接:
相交鏈表
void swap(struct ListNode** node1, struct ListNode** node2)
{struct ListNode* tmp = *node1;*node1 = *node2;*node2 = tmp;
}struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{struct ListNode* short_list1 = headA;struct ListNode* short_list2 = headA;struct ListNode* long_list1 = headB;struct ListNode* long_list2 = headB;while(short_list1 && long_list1){short_list1 = short_list1->next;long_list1 = long_list1->next;}if(short_list1){swap(&short_list1, &long_list1);swap(&short_list2, &long_list2);}while(long_list1){long_list1 = long_list1->next;long_list2 = long_list2->next;}//while((short_list2 && long_list2) || short_list2 != long_list2)while(short_list2 && long_list2 && short_list2 != long_list2){long_list2 = long_list2->next;short_list2 = short_list2->next;}return short_list2;
}
1.9 判斷一個鏈表中是否有環
題目要求:
題目鏈接:
判斷是否有環
//邏輯步驟存疑
bool hasCycle(struct ListNode *head)
{struct ListNode* fast = head;struct ListNode* slow = head;//err: while(fast && slow != fast)while(fast && fast->next){fast = fast->next->next;slow = slow->next;if(slow == fast){return true;}}return false;
}
1.10 尋找環狀鏈表相遇點
題目要求:
題目鏈接:
尋找環狀鏈表相遇點
思路依靠結論:一個結點從起始點,一個結點從相遇點(快慢指針相遇點),以同速行走(一次走一步),當他們再一次初次相遇時,此相遇結點即為入環點。
struct ListNode *detectCycle(struct ListNode *head)
{//快慢指針確定首次相遇點//起始點與相遇點出發,同速移動,最后的相遇的點即為環的進入點struct ListNode* fast = head;struct ListNode* slow = head;//遍歷尋找相遇點while(fast && fast->next){fast = fast->next->next;slow = slow->next;if(fast == slow){break;}}//判斷是否為環狀鏈表if(fast == NULL || fast->next == NULL){return NULL;}slow = head;while(fast != slow){fast = fast->next;slow = slow->next;}return fast;
}
1.11 鏈表的深度拷貝
題目要求:
>題目鏈接:
鏈表的深度拷貝
//思路:
//生成拷貝結點
//調整拷貝結點的指針
//還原原鏈表,鏈接拷貝結點
struct Node* BuyNewNode(int val)
{struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));newnode->val = val;newnode->next = NULL;newnode->random = NULL;return newnode;
}struct Node* copyRandomList(struct Node* head)
{struct Node* node1 = head;//判斷是否為空鏈表if(head == NULL){return head;}//創建新節點while (node1){struct Node* newnode = BuyNewNode(node1->val);newnode->next = node1->next;node1->next = newnode;node1 = node1->next->next;}//調整新節點的隨機指針struct Node* node2 = head->next;node1 = head;while (node2){if (node1->random){node2->random = node1->random->next;}node1 = node1->next->next;if (node2->next){node2 = node2->next->next;}else{node2 = node2->next;}}//還原鏈表,鏈接新鏈表node1 = head;node2 = head->next;struct Node* newhead = head->next;while (node1){node1->next = node1->next->next;if (node2->next){node2->next = node2->next->next;}node1 = node1->next;node2 = node2->next;}return newhead;
}