返回倒数第K个节点
快慢指针
让快指针先走k步,再使得快指针与慢指针同时走一步,这样没有开额外空间,空间复杂度较低。
代码实现如下:
struct ListNode {int val;struct ListNode* next;};
int kthToLast(struct ListNode* head, int k)
{struct ListNode* fast = head;struct ListNode* slow = head;while (k--){fast = fast->next;}while (fast){fast = fast->next;slow = slow->next;}return slow->val;
}
这里给的k不会大于链表长度。
链表的回文结构
这里要求空间复杂度为O(1),所以不能创建新数组,在这里我们首先访问中间节点,需要访问中间节点函数:
struct ListNode* middleNode(struct ListNode* head){struct ListNode* fast = head;struct ListNode* slow = head;while(fast && fast->next)//不能交换位置,fast为空,即证明为偶数节点,fast->next为空,即证明为奇数节点{slow = slow->next;fast = fast->next->next;}//此时slow就是指向中间节点的指针return slow; }
还需要反转链表函数:
struct ListNode* reverseList(struct ListNode* head) {//判空if(head == NULL)return head;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;}
假设现有一偶数链表
找到中间节点后将其反转,再对比头节点A与反转后的中间节点rmid,如果相等则继续往后走,如果不相等则直接返回false。
假设为奇数链表
对于奇数链表来说,其实存在一种特殊的偶然性:
即当2指向下一个节点时,我们发现指向的是3,因为我们反转了后面的链表,但并没有影响前面链表与后面链表的连接,所以这里将A与rmid进行比较时相当于自己与自己比较,仍会返回true.
综上,代码如下:
truct ListNode* middleNode(struct ListNode* head){struct ListNode* fast = head;struct ListNode* slow = head;while(fast && fast->next)//不能交换位置,fast为空,即证明为偶数节点,fast->next为空,即证明为奇数节点{slow = slow->next;fast = fast->next->next;}//此时slow就是指向中间节点的指针return slow; } struct ListNode* reverseList(struct ListNode* head) {//判空if(head == NULL)return head;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;}
bool chkPalindrome(ListNode* A)
{// write code herestruct ListNode* mid = middleNode(A);struct ListNode* rmid = reverseList(mid);while(A && rmid){if(rmid->val != A->val)return false;A = A->next;rmid = rmid->next;}return true;
}
};
链表的相交
对于链表的相交,我们可以先让长的链表先走几步,再让长短链表同时移动,当两链表的值相同时就是交叉点,而其中先走的步数是长链表的长度减去短链表长度的值。
代码如下:
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode *curA = headA, *curB = headB;int lenA = 1, lenB = 1;//因为cur到尾节点就不会向后移动了,所以如果设置的len初始值为0,会导致最终结果比链表实际长度少一个,所以这里我们将其初始化为1.while(curA){curA = curA->next;lenA++;}while(curB){curB = curB->next;lenB++;}if(curA != curB)//若到尾节点还不相等那么就没有相交节点return NULL;struct ListNode *LongList = headA,*ShortList = headB;if(lenA < lenB){LongList = headB;ShortList = headA;}int gap = abs(lenA - lenB);while(gap--){LongList = LongList->next;}while(LongList != ShortList){ShortList = ShortList->next;LongList = LongList->next;}return ShortList;
}
总结
做题时要多画图,通过画图将题目弄清楚可以起到事半功倍的效果。