💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
- 876.链表的中间节点
- 203.移除链表元素
- 牛客题---链表中倒数第k个结点
- 反转链表
- cm11-链表分割
- 链表的回文结构
- 160.相交链表
- 141.环形链表(LeetCode)
876.链表的中间节点
题目要求:
给你单链表的头结点 head ,请你找出并返回链表的中间结点。 如果有两个中间结点,则返回第二个中间结点。 |
输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。
示例 2:
输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4,返回第二个结点。
思路:
1.定义快指针和慢指针
2.快指针一次走两步,慢指针一次走一步,
3.快指针走到链表最后时,快指针所走的距离正好是慢指针的二倍。
代码实现:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* low = head;
struct ListNode* fast = head;
while(fast && fast->next)
{
low = low->next;
fast = fast->next->next;
}
return low;
}
203.移除链表元素
题目要求:
给你一个链表的头节点 head 和一个整数 val , 请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。 |
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1 输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7 输出:[]
思路:
1.如果第一个节点就是要删除的。进行头删
2.如果head一开始就是空,或者,进行N次头删之后,为空。就返回head
3.中间的节点正常删除。尾删与之一样。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
while(head && head->val == val)
head = head->next; //排除第一个节点就相等的情况
if(!head) //如果删除第一个,判断是否就空了
return head;
struct ListNode* slow = head; //定义快慢指针,也要写在上一步之后
struct ListNode* fast = head->next;
while(fast) {
if(fast->val==val) { //遇到相等就删除
slow->next = fast->next;
fast = slow->next;
} else { //否则快慢指针依次后移
slow = slow->next;
fast = fast->next;
}
}
return head;
}
牛客题—链表中倒数第k个结点
题目要求:
输入一个链表,输出该链表中倒数第k个结点。
示例1
输入: 1,{1,2,3,4,5}
返回值: {5}
思路分析:
注意点:考虑链表为空的情况,K的值大于链表的长度。
代码:.
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
struct ListNode* fast = pListHead;
struct ListNode* low = pListHead;
int i = k-1;
//判断是否为空,或这k有问题
if(pListHead==NULL||k<=0)
return NULL;
while(i--)
{
if(fast->next==NULL)
{
return NULL;
}
fast = fast->next;
}
//两个指针开始同时移动,到最后low表示倒数k的节点
while(fast->next)
{
low = low->next;
fast = fast->next;
}
return low;
}
答案正确!
注意:在测试样例中我发现个问题。
倒数第五个不应该是1吗?
原因是,fast后移k-1个,此时fast指针已经指向最后一个元素(fast->next==NULL),所以,根本就没有进行while循环,两个指针同步移动中去。又因为我们最开始给 low= =plisthead,所以,此时返回的是整个链表。
反转链表
头插法:
思路:
从头开始取链表的每一个节点插入到newnode之前
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur = head;
struct ListNode* newnode = NULL;
//头插
while(cur)
{
//定义一个之指针用来保存下一个节点
struct ListNode* tmp = cur->next;
cur->next = newnode;//头插
newnode = cur;//将newnode指针前移
cur = tmp;
}
return newnode;
}
cm11-链表分割
描述
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
思路:
代码:
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
struct ListNode* ghead,* gtail,* lhead,* ltail;
lhead = ltail = (struct ListNode*)malloc(sizeof(struct ListNode));
ghead = gtail = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* cur = pHead;
//遍历链表,大于等于x的放ghead链表中,小于x的放lhead链表
while(cur)
{
if(cur->val >= x)
{
gtail->next = cur;//尾插
gtail = gtail->next;//移向下一位
}
else
{
ltail->next = cur;//尾插
ltail = ltail->next;
}
cur = cur->next;
}
ltail->next = ghead->next;
gtail->next = NULL;
struct ListNode* head = lhead->next;
free(lhead);
free(ghead);
return head;
}
};
链表的回文结构
题目:对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例: 1->2->2->1 返回:true
思路:
1.找到中间节点
2.从中间节点往后逆置
3.定义快慢指针,向后遍历判断是否相等。
class PalindromeList {
public:
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* reveseList(struct ListNode* head)
{
struct ListNode* cur = head;
struct ListNode* newhead = nullptr;
while(cur)
{
struct ListNode* next = cur->next;
cur->next = newhead;
newhead = cur;
cur = next;
}
return newhead;
}
bool chkPalindrome(ListNode* head) {
// write code here
struct ListNode* mid = middleNode(head);
struct ListNode* rmid = reveseList(mid);
while(rmid && head)
{
if(rmid->val !=head->val)
{
return false;
}
rmid = rmid->next;
head = head->next;
}
return true;
}
};
160.相交链表
题目:
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0 listA - 第一个链表 listB - 第二个链表
skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数 skipB - 在 listB
中(从头节点开始)跳到交叉节点的节点数 评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB
传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
思路:
1.分别计算listA,listB链表的长度
2.取两绝对值,对齐两个链表,同时开始遍历,当相同就相交了。
代码:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA = headA,*curB = headB;
//分别计算A,B链表的长度
int lenA =1,lenB =1;
while(curA->next)
{
curA = curA->next;
lenA++;
}
while(curB->next)
{
curB = curB->next;
lenB++;
}
//此时curA,B都已指向最后节点,如果不相等,则说明不相交
if(curA != curB)
{
return NULL;
}
//求出相差的步数
int n = abs(lenA-lenB);
struct ListNode* LongList = headA,* ShortList = headB;
if(lenA<lenB)
{
LongList = headB;
ShortList = headA;
}
//先让长的链表走n步,与短链表对齐
while(n--)
{
LongList = LongList->next;
}
//同时走,找相同;
while(LongList!=ShortList)
{
LongList = LongList->next;
ShortList = ShortList->next;
}
return ShortList;
}
141.环形链表(LeetCode)
给你一个链表的头节点 ,判断链表中是否有环。head
如果链表中有某个节点,可以通过连续跟踪 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。nextpos
如果链表中存在环 ,则返回 。否则,返回 。truefalse
思路:
代码:
bool hasCycle(struct ListNode *head) {
struct ListNode *fast = head,*low = head;
while(fast && fast->next)
{
fast = fast->next->next;
low = low->next;
if(fast == low)
{
return true;
}
}
return false;
}