练习
1. 删除val节点
oj链接
这道题最先想出来的方法肯定是在遍历链表的同时删除等于val的节点,我们用第二中思路:不等于val的节点尾插,让后返回新节点。代码如下:
struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* newhead = NULL,*tail = NULL,*cur = head;//tail解决尾插每次都要找尾的问题while(cur){if(cur->val == val){struct ListNode* del = cur;cur = cur->next;free(del);}else{if(newhead == NULL){newhead = tail = cur;}else{tail->next = cur;tail = cur;}cur = cur->next;tail->next = NULL;}}return newhead;
}
2.返回中间节点
oj链接
找中间节点,利用快慢指针,快指针一次走两步,慢指针一次走一步。快指针到终点,慢指针刚好走一半,慢指针走到的节点就是中间节点。唯一的区别就是偶数个节点和奇数个节点判断结束的条件略有不同。
struct ListNode* middleNode(struct ListNode* head) {struct ListNode* slow = head;struct ListNode* fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;
}
3.合并链表
oj链接
这道题的思路和第一题大同小异,就是小的尾插。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if(list1 ==NULL)return list2;if(list2 == NULL)return list1; struct ListNode* head1 = list1;struct ListNode* head2 = list2;struct ListNode* newhead =NULL, *tail = NULL;while(head1 && head2){if(head1->val < head2->val){if(newhead == NULL){newhead = tail = head1;}else{tail->next = head1;tail = tail->next;}head1 = head1->next;}else{if(newhead == NULL){newhead = tail = head2;}else{tail->next = head2;tail = tail->next;}head2 = head2->next;}}if(head1){tail->next = head1;}if(head2){tail->next = head2;}return newhead;
}
4.反转链表
oj链接
方法一: 头插
struct ListNode* reverseList(struct ListNode* head) {struct ListNode* cur = head;struct ListNode* newhead = NULL;while(cur){struct ListNode* next = cur->next;cur->next = newhead;newhead = cur;cur = next;} return newhead;
}
方法二:每个节点挨个反转
// 方法二:每个节点挨个反转
struct ListNode* reverseList(struct ListNode* head) {if(NULL == head){return NULL;}struct ListNode* n1 = NULL;struct ListNode* n2 = head;struct ListNode* n3 = n2->next;while(n2){n2->next = n1;n1 = n2;n2 = n3;if(n3)n3 = n3->next; }return n1;
}
5.链表分割
oj链接
这道题小于x的尾插一个链表,大于等于x的尾插另一个链表。最后把两个链表连接起来。两个链表使用带哨兵位的头结点会方便一些。
class Partition {
public:ListNode* partition(ListNode* pHead, int x) {// write code herestruct ListNode* lesshead,*lesstail,*greathead,*greattail;lesshead = lesstail =(struct ListNode*)malloc(sizeof(struct ListNode));greathead = greattail = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* cur = pHead;while(cur){if(cur->val < x){lesstail->next = cur;lesstail = lesstail->next;}else {greattail->next = cur;greattail = greattail->next;}cur = cur->next;}lesstail->next = greathead->next;greattail->next = NULL;pHead = lesshead->next;free(lesshead);free(greathead);return pHead;}
};
6.链表的回文结构
oj链接
这道题先找到中间节点,再反转中间节点后面的链表,之后再逐一对比即可。
struct ListNode* middleNode(struct ListNode* head){struct ListNode* slow =head,*fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}return slow;
}
struct ListNode* reverseList(struct ListNode* head){struct ListNode* curr = head,*prev = NULL;while(curr){struct ListNode* tmp = curr->next;curr->next = prev;prev = curr;curr = tmp;}return prev;
}
class PalindromeList {
public:bool chkPalindrome(ListNode* A) {// write code herestruct ListNode* mid = middleNode(A);struct ListNode* rmid = reverseList(mid);while(rmid){if(A->val != rmid->val){return false;}else {A = A->next;rmid = rmid->next;}}return true;}
};
7.相交链表
oj链接
先判断是否相交,计算两链表的长度,长链表先走长度的差值,之后一起走找相交节点即可。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* list1 = headA;struct ListNode* list2 = headB;int len1 = 1,len2 = 1;while(list1->next){list1 = list1->next;++len1;}while(list2->next){list2 = list2->next;++len2;}if(list1 != list2){return NULL;}int len = abs(len1-len2);struct ListNode* shortlist = headA;struct ListNode* longlist = headB;if(len1 > len2){shortlist = headB;longlist = headA;}while(len--){longlist = longlist->next;}while(longlist != shortlist){longlist = longlist->next;shortlist = shortlist->next;}return shortlist;
}
8.环形链表
oj链接
利用快慢指针解决,如果有环快慢指针会相遇。
bool hasCycle(struct ListNode *head) {struct ListNode* fast = head,*slow = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;while(fast == slow){return true;}}return false;
}
9.环形链表 ||
oj链接
让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环 运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* fast = head,*slow = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;//带环if(fast == slow){struct ListNode* meet = slow;while(head != meet){meet = meet->next;head = head->next;}return meet;}}return NULL;}
证明: