力扣学习day9

本文探讨了链表的基本操作,包括设计链表结构、插入节点、删除节点,以及如何反转链表。作者分享了关于虚拟头节点的使用心得,并讨论了如何判断链表环的存在及其入口。此外,还介绍了利用双指针解决环形链表问题的思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.学习目标

1.按照如下类型来刷题:数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心->动态规划->图论->高级数据结构,再从简单刷起,做了几个类型题目之后,再慢慢做中等题目、困难题目。
2.动手用多种语言来进行写题,并要有自己的代码模板。
3.总结程序员简历技巧。

学习网址


2.链表

707. 设计链表

2.1 题目

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

2.2 思考

题目绝对是好题,把链表的各种操作都考察了,没有涉及任何算法,但是对链表的理解是大有帮助。这在大一的时候应该是作为一个课后作业实现的,然后今天稍微写了下,还算是写的合格吧!!!
在这里插入图片描述

然后写的过程自己也总结了自己写链表的几个要点,大佬们莫笑!!!!

(1)链表结构(偷懒法)

我之前链表结构的声明十分的随便(其实已经忘的差不多了),但是在做链表结构的时候,如果对结构真的理解不怎么透彻,可以偷下懒:
typedef struct MyLinkedList{
int val;
struct MyLinkedList *next;

} MyLinkedList;

就是把结构体类型名和变量名用一个表示,这样就可以避免少量的错误,但如果想真的理解结构还是得认真学习和总结。

(2)虚拟头节点

这个在上篇也讲过,在链表中使用一个虚拟头节点对于删除头节点以及存储相关数据是真的有帮助,大家可以用一下。

(3)插入节点

我之前有个错误就是插入节点,当时我就是按照习惯写了判断,如果索引大于链表长度则直接返回,结果少考虑插入到最后一个节点的可能,算是判断失误。

(4)代码

渣渣的代码:

typedef struct MyLinkedList{
    int val;
    struct MyLinkedList *next;

} MyLinkedList;

/** Initialize your data structure here. */

MyLinkedList* myLinkedListCreate() {
MyLinkedList *p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
p->val=-1;
p->next=NULL;
return p; 
}

/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
if(obj->val<index) return -1;
MyLinkedList *p;
p=obj;
for(int i=0;i<=index;i++)    p=p->next;
return p->val;
}

/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
MyLinkedList *p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
p->val=val;
p->next=obj->next;
obj->next=p;
obj->val++;
}

/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
MyLinkedList *p,*q=(MyLinkedList*)malloc(sizeof(MyLinkedList));
p=obj;
for(int i=0;i<=obj->val;i++)
{
    p=p->next;
}
p->next=q;
q->next=NULL;
q->val=val;
obj->val++;
}

/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if(obj->val<index-1)
return ;
MyLinkedList *p;
p=obj;
for(int i=0;i<index;i++) p=p->next;
MyLinkedList *q=(MyLinkedList*)malloc(sizeof(MyLinkedList));
q->val=val;
q->next=p->next;
p->next=q;
obj->val++;
}

/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if(obj->val<index)
return ;
MyLinkedList *p,*q;
p=obj;
for(int i=0;i<index;i++) p=p->next;
q=p->next;
p->next=p->next->next;
free(q);
obj->val--;
}

void myLinkedListFree(MyLinkedList* obj) {

}

/**
 * Your MyLinkedList struct will be instantiated and called as such:
 * MyLinkedList* obj = myLinkedListCreate();
 * int param_1 = myLinkedListGet(obj, index);
 
 * myLinkedListAddAtHead(obj, val);
 
 * myLinkedListAddAtTail(obj, val);
 
 * myLinkedListAddAtIndex(obj, index, val);
 
 * myLinkedListDeleteAtIndex(obj, index);
 
 * myLinkedListFree(obj);
*/

3.链表

第206题:反转链表

3.1题目

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

3.2思考

这个思路也有很多,最差都能想到的是再申请一个空间,然后遍历一遍就行,但是这个方法十分耗费空间。这里我使用了几个指针进行操作就能实现反转,代码也十分的简单,大概就是一个指针pre,一个指针p,一个指针temp。首先,pre表示p前的节点,最开始的时候可以初始化为NULL,然后temp存储原p->next,因为p反转之后就找不到next了。

算法开始:
temp=p->next;//temp存储p下一个节点,避免找不到
p->next=pre;//反转
pre=p;//恢复
p=temp;
在这里插入图片描述

3.3 代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseList(struct ListNode* head){
struct ListNode *pre,*temp,*p;
pre=NULL;
temp=NULL;
p=head;
while(p!=NULL)
{
    temp=p->next;
    p->next=pre;
    pre=p;
    p=temp;
}
return pre;
}

4.链表(环)

环形链表II

4.1题目

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。

说明:不允许修改给定的链表。

进阶:

你是否可以使用 O(1) 空间解决此题?

4.2 思考

常见面试题,我第一次面试被问到时啥都不知道,这道题就快慢指针可以实现。需要一定程度的数学运算能力,初次遇见可能就是像我一样全部遍历得结果,蠢的不行,还一个劲的和面试官说,这算法就是O(n^2),没有更优的,回想起当时,真的慢慢的耻辱感。
这道题主要考察两个知识点,环链1考察的是判断有没有环,环2考察的是有没有环,且判断路口,因涉及到一定的运算,我就简述下算法。具体证明看这里

(1)判断有无环

这个很简单,设置快慢指针,一个步伐为2,一个步伐为1,然后开始遍历,如果二者相遇表示存在环,否则就是没有。

(2)环的入口

环的入口的算法是有一点数学证明的,还是双指针法,一个从起点出发,一个从前面的相遇点出,他们相遇的位置就是入口。

5.闲聊

最近事情也多,最近有几场面试还有毕设的开题报告,只能是每天抽时间来写了,因为今天想快点把链表结束,所以就仓促的全部写完。嗯嗯嗯,马上要出成绩了,听说今年初试预测线350,看来没太大希望了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

此人受打击,决定去力扣历练

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值