链表的相关考点总结:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
//由于说明了给定的k值一定有效,所以不用考虑k值比元素个数多的情况。
int kthToLast(struct ListNode* head, int k){
struct ListNode*pre = head,*p=head;
while(k--){
p = p->next;
} //先让p指针向前走k步,然后q和p同时前行,当p到null时,q所指的便是倒数第k个。
while(p!=NULL){
p=p->next;
pre=pre->next;
}
return pre->val;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* reversePrint(struct ListNode* head, int* returnSize){
if(head == NULL){
*returnSize = 0;
return malloc(sizeof(int) * 10000);
} //当指针指向null时创建大小为1000的数组。
int *ans = reversePrint(head->next, returnSize); //ans是数组指针
ans[(*returnSize)++] = head->val;
return ans;
}
//这里使用的是递归方法
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL||head->next==NULL){
return head;
}
else{
struct ListNode *p = head->next;
struct ListNode *q = p;
if(p->next!=NULL){
q = reverseList(p);
}
p->next = head;
head->next = NULL;
return q;
}
}
//非递归方法,此题链表不带头结点,所以个人觉得不适合用头插入法
struct ListNode* reverseList(struct ListNode* head){
if(head==NULL){
return head;
}
struct ListNode *p = head->next,*r;
head->next = NULL;
while(p!=NULL){
r = p->next;
p->next = head;
head = p;
p = r;
}
return head;
}
//这里采用的是暴力的遍历方法。
struct ListNode* removeDuplicateNodes(struct ListNode* head){
struct ListNode *p=head,*u,*q;
while(p!=NULL){
q=p;
while(q->next!=NULL){
if(p->val==q->next->val){
u = q->next;
q->next = u->next;
free(u);
}
else{
q = q->next;
}
}
p = p->next;
}
return head;
}
//这里先分析链表公共节点的特征,两个链表从公共节点开始后面便一直是公共节点,
//只需要找出两个链表的长度,然后计算它们的长度差inters,让长的链表先走inters,
//然后两个链表同时走,直到两者相遇,即为公共节点。
//时间复杂度为O(lena+lenb)
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *p = headA,*q = headB;
int lena=0;
int lenb = 0;
int inters;
while(p!=NULL){
lena = lena+1;
p = p->next;
}
while(q!=NULL){
lenb = lenb+1;
q = q->next;
}
p = headA;
q = headB;
if(lena>lenb){
inters = lena-lenb;
while(inters--){
p = p->next;
}
}
else{
inters = lenb-lena;
while(inters--){
q = q->next;
}
}
while(p!=q&&p!=NULL&&q!=NULL){
p = p->next;
q = q->next;
}
if(p==NULL||q==NULL){
return NULL;
}
return p;
}
方法2:也可以使用暴力的方法,固定一个链表,然后顺序遍历另外一个链表。时间复杂度为O(lena*lenb)
//这里采用一个快指针fast和一个慢指针slow,当快指针和慢指针第一次相遇时,p1指针从头出发,
//根据公式计算,发现它们一定能相遇,相遇点正好是环的第一个节点
bool hasCycle(struct ListNode *head) {
struct ListNode*fast = head,*slow = head;
if(head==NULL||head->next==NULL){
return false;
}
while(slow!=NULL&&fast->next!=NULL){
slow =slow->next;
fast = fast->next->next;
if(slow==fast){
break;
}
if(fast==NULL){
return false;
}
}
if(slow==NULL||fast->next==NULL){
return false;
}
struct ListNode *p1 = head,*p2=slow;
while(p1!=p2){
p1=p1->next;
p2=p2->next;
}
return true;
}
//先找到中间节点,然后就地逆置中间节点后面的节点,最后同时移动指针,如果值相等则是回文。
bool isPalindrome(struct ListNode* head){
struct ListNode *mid = head,*r = head,*p,*q;
if(head==NULL){
return true;
}
if(head->next==NULL){
return true;
}
while(r->next!=NULL){
r = r->next;
if(r->next!=NULL){
r = r->next;
mid = mid->next;
}//这里使得当链表元素个数为偶数时,mid指向中间两个节点中的前面一个。方便后面的元素对比。
}
p = mid;
q = p->next;
p->next=NULL;
while(q!=NULL){
r = q->next;
q->next = p;
p=q;
q=r;
}
while(p!=mid){ //前面找mid的方法方便了这里的对比。
if(head->val!=p->val){
return false;
}
p = p->next;
head = head->next;
}
return true;
}