一.链表的中间结点
题目描述:
给定一个头结点为 head 的非空单链表,返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
这是归属在一类快慢指针的解题类型中的题目。
//可以定义两个指针,一个每次走两步,一个每次只走一步,你就会发现,当快指针走到结尾的时候,慢指针刚好走到中间
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;
}
二.
题目描述:
输入一个链表,输出该链表中倒数第k个结点。
解题思路:定义两个指针,slow和fast,先让fast走k步,然两个指针一起走,那么他们之间的差值就一直是K,然后当fast为NULL的时候未结束的标志,此时的slow就是需要找的倒数第K个结点
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* slow = pListHead,* fast = pListHead;
//你这里的K值有可能比你链表本身的长度长,所以要保证其实有效的,
//这一题最不好想到的就是这里。
while(k--)
{
if(fast != NULL)
fast = fast->next;
else
return NULL;
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
牛客网–链表的回文结构
题目描述:
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例:
1->2->2->1
返回:true
什么是回文?
就是链表是可以对称的
解题思路:这道题很巧妙的使用到了我们前面所学识使用的方法,快慢指针+逆置链表方法来解决这题
//1->2->3->3->2->1 对于偶数个slow刚好走到他的下中位数处
//1->2->3->2->1 对于奇数个slow刚好走到中间
①找到中间对称的那个结点
②翻转后半部分链表
③比较两个链表是否相等(注意:对于前半部分的链表的最后一个结点来说,他的下一个指向的还是原先的哪一个结点的地址,但是对于后半部分最后一个结点指向的是NULL,所以要给前面那半部分最后一个结点指向的下一个地址置为NULL)
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
//①找出中间的那个结点
ListNode* slow = A;
ListNode* fast = A;
ListNode* prev = NULL;
//在下面逆置的时候需要知道slow的上一个结点的位置
while(fast && fast->next)
{
prev = slow;
slow = slow->next;
fast = fast->next->next;
}
//这一步就是所写的“注意”
prev->next = NULL;
//②逆置链表
ListNode* newHead = NULL;
ListNode* cur = slow;
while(cur)
{
ListNode* next = cur->next;
cur->next = newHead;
newHead = cur;
cur = next;
}
//③比较(此时你使用A或者newhead都是可以的)
while(A)
{
if(newHead->val != A->val)
{
return false;
}
else
{
newHead = newHead->next;
A = A->next;
}
}
return true;
}
};