返回倒数第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 here
struct 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;
}
总结
做题时要多画图,通过画图将题目弄清楚可以起到事半功倍的效果。