当前位置: 首页 > news >正文

数据结构:单链表的应用(力扣算法题)第一章

每题代码汇总:登录 - Gitee.com

关于使用VS调试OJ代码,见:使用VS调试OJ代码-CSDN博客

基础单链表知识,见:数据结构:单链表(详解)-CSDN博客

1.移除链表元素

203. 移除链表元素 - 力扣(LeetCode)

首先理解题意:

以及力扣已经提供了单链表的节点结构和待实现的函数。

思路一:

遍历链表,查找值为val的节点,并返回节点,删除指定位置的节点,再return,时间复杂度为O(n^2)

这样的代码直观但效率不高。

大致的逻辑:
while(遍历)
{//SLTNode* SLTFind(x);//SLTErase(pos);
}

代码:

typedef struct ListNode ListNode;//自定义,方便后续引用
//查找
ListNode* SLTFind(ListNode* phead, int val)
{ListNode* pcur = phead;while(pcur){if(pcur->val == val){return pcur;}pcur = pcur->next;}return NULL;
}
//删除
void SLTErase(ListNode** pphead,ListNode* pos)
{assert(pphead && pos);//pos为头节点if(pos == *pphead){*pphead = pos->next;free(pos);return;}else{ListNode* prev = *pphead;while(prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}
struct ListNode* removeElements(struct ListNode* head, int val) {ListNode* pos;while((pos = SLTFind(head,val))!= NULL){SLTErase(&head,pos);}return head;
}

最终通过测试。

思路二:

创建新链表,将原链表中不为val的节点拿下来尾插。时间复杂度:O(N)。

newHead为新链表头指针,newTail为新链表尾指针,pcur为遍历原链表的指针。

基本逻辑:
while(遍历)
{//尾插
}

代码:

typedef struct ListNode ListNode;//自定义,方便后续引用
struct ListNode* removeElements(struct ListNode* head, int val) {//创建新链表ListNode* newHead,*newtail;newHead = newtail = NULL;ListNode* pcur = head;while(pcur){//判断if(pcur->val != val){//尾插if(newHead == NULL){//链表为空newHead = newtail = pcur;}else{//链表非空newtail->next = pcur;newtail = newtail->next;}}pcur = pcur->next;}if(newtail)newtail->next = NULL;//避免残留原链表的指针return newHead;
}

最终通过测试。

2.反转链表

206. 反转链表 - 力扣(LeetCode)

理解题意:

思路一:

创建新链表,遍历原链表将节点头插到新链表中,时间复杂度:O(N)。

代码见下:

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {ListNode* newHead = NULL;while(head){ListNode* temp = head->next;head->next = newHead;newHead = head;head = temp;}return newHead;
}

最终通过测试。

思路二:

创建n1,n2,n3三个指针,改变指针的指向。

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {if(head == NULL){return head;}//创建三个指针ListNode*n1,*n2,*n3;n1 = NULL, n2 = head, n3 = n2->next;while(n2){n2->next = n1;n1 = n2;n2 = n3;if(n3)n3 = n3->next;}return n1;
}

最终通过测试。

3.链表的中间结点

876. 链表的中间结点 - 力扣(LeetCode)

理解题意:

思路一:

求得链表总长度,根据下标,总长度/2就是中间节点,再遍历找到中间节点及新链表。时间复杂度:O(N)。

代码如下:

typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {int len = 0;ListNode* curr = head;while(curr){len++;curr = curr->next;}int mid = len / 2;curr = head;for(int i = 0;i < mid; i++){curr = curr->next;}return curr;
}

最终测试通过。

思路二:

使用快慢指针法,慢指针每次走一步,快指针每次走两步。

代码:

typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {//创建指针ListNode* slow = head;ListNode* fast = head;while(fast != NULL && fast->next != NULL){slow = slow->next;fast = fast->next->next;}return slow;
}

注意:在while循环中,不能将条件改为fast->next != NULL && fast != NULL,否则会导致空指针解引用错误(具体错误:当fast为NULL时,会先尝试访问fast->next,导致崩溃),在涉及指针的条件表达式时,应该先检查指针本身是否为空,再访问其他成员,这样才能写出健壮,无崩溃的代码。

4.合并两个有序链表

21. 合并两个有序链表 - 力扣(LeetCode)

之前有过合并两个有序数组的文章:数据结构:顺序表-CSDN博客,除过我文章中的,还可以通过这篇文章c语言内存函数以及数据在内存中的存储_函数在内存里是如何存储的-CSDN博客中的memcpy解决。

先理解题意:

思路一:

创建新链表,遍历并比较原链表中结点的值,小的插入到新链表。

编写代码方式一:

代码:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {//创建空链表ListNode* newHead, *newTail;newHead = newTail = NULL;ListNode* l1 = list1;ListNode* l2 = list2;if(l1 == NULL){return l2;}if(l2 == NULL){return l1;}//遍历while(l1 != NULL && l2 != NULL){if(l1->val < l2->val){//l1尾插//空链表if(newHead == NULL){newHead = newTail = l1;}else{//非空newTail->next = l1;newTail = newTail->next;}l1 = l1->next;}else{//l2尾插//空链表if(newHead == NULL){newHead = newTail = l2;}else{//非空newTail->next = l2;newTail = newTail->next;}l2 = l2->next;}}//遍历下去,l1为空或l2为空时if(l1){newTail->next = l1;}if(l2){newTail->next = l2;}return newHead;
}

最终测试通过。

编写代码方式二:

上述代码有冗余,以往有联合的方式进行整合:自定义类型:联合和枚举-CSDN博客,不过此处根本原因是:初始时链表为空,那如果我创建非空链表呢?

代码如下:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {//创建非空链表ListNode* newHead, *newTail;newHead = newTail = (ListNode*)malloc(sizeof(ListNode));ListNode* l1 = list1;ListNode* l2 = list2;if(l1 == NULL){return l2;}if(l2 == NULL){return l1;}//遍历while(l1 != NULL && l2 != NULL){if(l1->val < l2->val){//l1尾插newTail->next = l1;newTail = newTail->next;l1 = l1->next;}else{//l2尾插newTail->next = l2;newTail = newTail->next;l2 = l2->next;}}//遍历下去,l1为空或l2为空时if(l1){newTail->next = l1;}if(l2){newTail->next = l2;}ListNode* retHead = newHead->next;free(newHead);newHead = NULL;return retHead;
}

最终通过测试。

思路二:

使用递归,假设 “当前两个链表的剩余部分已合并为有序链表”,只需决定当前头节点的选择,递归处理剩余部分。

代码如下:

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {ListNode* l1 = list1;ListNode* l2 = list2;// 基准情况:如果一个链表为空,返回另一个链表if (l1 == NULL) return l2;if (l2 == NULL) return l1;// 递归选择较小的节点作为当前节点if (l1->val <= l2->val) {l1->next = mergeTwoLists(l1->next, l2);return l1;} else {l2->next = mergeTwoLists(l1, l2->next);return l2;}
}

最终通过测试。

5.链表的回文结构

链表的回文结构_牛客题霸_牛客网

本题在牛客网上,选择编程语言没有c语言,只能选c++,不过此题涉及到的也只是不需要写这串代码:typedef struct ListNode ListNode; 其余按照c语言完成即可。

理解题意:

思路一:

创建一个新链表,保存原链表所有结点,反转新链表,判断两者结点是否相同。

代码如下:

class PalindromeList {public:// 复制链表ListNode* copyList(ListNode* head) {if (head == NULL) return NULL;ListNode* copyHead = new ListNode(head->val);ListNode* curCopy = copyHead;ListNode* curOrg = head->next;while (curOrg != NULL) {curCopy->next = new ListNode(curOrg->val);curCopy = curCopy->next;curOrg = curOrg->next;}return copyHead;}// 反转链表ListNode* reverseList(ListNode* head) {ListNode* prev = NULL;ListNode* cur = head;while (cur != NULL) {ListNode* next = cur->next;cur->next = prev;prev = cur;cur = next;}return prev;}bool chkPalindrome(ListNode* A) {if (A == NULL) return true; // 空链表视为回文ListNode* copy = copyList(A);ListNode* reversed = reverseList(copy);ListNode* p1 = A;ListNode* p2 = reversed;// 逐节点比较while (p1 != NULL && p2 != NULL) {if (p1->val != p2->val) {return false;}p1 = p1->next;p2 = p2->next;}return true;}
};

最终测试通过。

思路二(投机取巧):

题中保证链表长度小于等于900即可,那么创建数组大小为900,遍历链表,将其依次存储在数组中,若数组为回文结构,那么链表也是回文结构。

代码如下:

class PalindromeList {
public:bool chkPalindrome(ListNode* A) {// write code hereint arr[900] = {0};//遍历ListNode* curr = A;int i = 0;while(curr){arr[i++] = curr->val;curr = curr->next;}//判断int left = 0;int right = i - 1;while(left < right){if(arr[left] != arr[right]){return false;}left++;right--;}return true;}
};

最终测试通过。

思路三:

找到链表的中间节点,将中间节点作为新链表的头节点,反转链表,遍历原链表和反转后的链表节点是否相等。

代码如下:

class PalindromeList {public://快慢指针找中间结点ListNode* middleNode(struct ListNode* head) {//创建指针ListNode* slow = head;ListNode* fast = head;while (fast != NULL && fast->next != NULL){slow = slow->next;fast = fast->next->next;}return slow;
}//反转ListNode* reverseList(struct ListNode* head) {if (head == NULL) {return head;}//创建三个指针ListNode* n1, * n2, * n3;n1 = NULL, n2 = head, 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//找中间节点ListNode* mid = middleNode(A);//反转ListNode* rev = reverseList(mid);//比较ListNode* left = A;while(rev){if(left->val != rev->val){return false;}left = left->next;rev = rev->next;}return true;}
};

最终测试通过。

本章完。

http://www.dtcms.com/a/353059.html

相关文章:

  • 腾讯云人脸识别API技术深度解析:从算法原理到工程实践
  • Diagnosing bias and variance|诊断偏差和方差
  • 文件系统中的核心数据结构
  • 链表-25.k个一组翻转链表-力扣(LeetCode)
  • 镜中万象:论观察即存在的递归拓扑与生命的意识本质
  • FPGA的工作原理
  • AI赋能CRM:纷享销客访销大脑重构快消品销售策略
  • d435i相机读取镜头内参和相对之间的外参
  • 三方相机问题分析八:【返帧异常导致性能卡顿】Snapchat后置使用特效预览出现卡顿
  • Jmeter5.3性能测试:文件下载脚本编写后,导出文件的接收
  • 第五章:Go运行时、内存管理与性能优化之栈与堆内存分配 (逃逸分析)
  • 在语言模型监督式微调(SFT)中的 负对数似然(Negative Log-Likelihood, NLL)等价于最大化似然
  • 开发者如何在 Gitee 上开源一个自己的项目
  • 开源 C++ QT Widget 开发(七)线程--多线程及通讯
  • keepalived mysql 主从复制 容器实现(失败)
  • JVM之【Java对象在内存中的结构】
  • windows下 docker desktop 清理ext4.vhdx文件 并缩小ext4.vhdx文件
  • 二次校验请求源 IP 是否在 WAF 官方 IP 段内” + “校验是否携带 WAF 专属 HTTP 头
  • 基于Spark的白酒行业数据分析与可视化系统的设计与实现
  • [后端快速搭建]基于 Django+DeepSeek API 快速搭建智能问答后端
  • 域名、ip、DSN、URL
  • springbootr如何调用dolphinshceduler
  • 【记录】R|Windows 下的 R studio 安装调研准备工作、安装过程以及 ggplot2 包的引入测试
  • GIP电路
  • leetcode 974 和可被K整除的子数组
  • 【LeetCode 热题 100】287. 寻找重复数——双指针
  • 初始Linux——指令与权限
  • 【大前端】封装一个React Native与Android/IOS 端通用的埋点接口
  • 数据结构(C语言篇):(三)顺序表算法题解析
  • FPGA学习笔记——Verilog中可综合和常见的不可综合的系统函数