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

数据结构——线性表(链表,力扣中等篇,增删查改)

文章目录

  • 一、增删查改
    • 1.1增(插入节点)
      • 1.1.1两数后插入公约数
      • 1.1.2循环有序链表的插入
    • 1.2删(移除节点)
      • 1.2.1删除已知的node节点【交换val值】
      • 1.2.2移除数组中已存在的节点【unordered_set】
      • 1.2.3删除和为0的节点【前缀和】
    • 1.3改(交换节点)
      • 1.3.1链表中的下一个最大节点
      • 1.3.2删除右侧有一个更大数值的节点
      • 1.3.3交换K和倒数第K个节点
      • 1.3.4合并0之间的节点
    • 1.4其他
      • 1.4.1链表组件
      • 1.4.2螺旋矩阵
      • 1.4.3临界值的距离

一、增删查改

1.1增(插入节点)

序号题目链接
1两数后插入公约数https://leetcode.cn/problems/insert-greatest-common-divisors-in-linked-list/description/?envType=problem-list-v2&envId=linked-list
2循环有序链表的插入https://leetcode.cn/problems/4ueAj6/description/?envType=problem-list-v2&envId=linked-list

1.1.1两数后插入公约数

在两个数A和B的中间插入A和B的公约数【公约数的值可以用gcd直接求】

//求最大公约数gcd
ListNode* insertGreatestCommonDivisors(ListNode* head) {if(head==nullptr || head->next==nullptr)return head;ListNode* p=head;while(p->next!=nullptr){ListNode* node=new ListNode(gcd(p->val,p->next->val));node->next=p->next;p->next=node;p=p->next->next;}return head;
}

1.1.2循环有序链表的插入

给定循环单调非递减列表中的一个点,写一个函数向这个列表中插入一个新元素 insertVal ,使这个列表仍然是循环升序的。
在这里插入图片描述

Node* insert(Node* head, int insertVal) {Node* node=new Node(insertVal);//创建新节点if(head==nullptr){node->next=node;return node;}if(head->next==head){head->next=node;node->next=head;return head;}Node* cur=head;Node* next=head->next;while(next != head){if(cur->val <= insertVal && insertVal <= next->val) break;if((cur->val > next->val) && (insertVal >= cur->val || insertVal <= next->val) )  break;cur=cur->next;next=next->next;}node->next=next;cur->next=node;return head;
}

1.2删(移除节点)

序号题目链接
1删除链表中值为val的节点(简单)https://leetcode.cn/problems/remove-linked-list-elements/description/?envType=problem-list-v2&envId=linked-list
2删除已知的node节点https://leetcode.cn/problems/delete-node-in-a-linked-list/description/?envType=problem-list-v2&envId=linked-list
3移除链表中数组已存在的元素https://leetcode.cn/problems/delete-nodes-from-linked-list-present-in-array/?envType=problem-list-v2&envId=linked-list
4删除和为0的连续节点https://leetcode.cn/problems/remove-zero-sum-consecutive-nodes-from-linked-list/description/?envType=problem-list-v2&envId=linked-list

1.2.1删除已知的node节点【交换val值】

void deleteNode(ListNode* node) {//将node和后面的节点换个位置,然后删除int val=node->val;//暂存节点信息node->val=node->next->val;node->next->val=val;//删除node->next即可node->next=node->next->next;
}

1.2.2移除数组中已存在的节点【unordered_set】

ListNode* modifiedList(vector<int>& nums, ListNode* head) {ListNode* dummy=new ListNode(-1,head);unordered_set<int> s(nums.begin(),nums.end());ListNode* pre=dummy;ListNode* cur=dummy->next;while(cur!=nullptr){if(s.count(cur->val)){pre->next=cur->next;cur = pre->next;}else{cur=cur->next;pre=pre->next;}}return dummy->next;
}

1.2.3删除和为0的节点【前缀和】

前缀和的原理:
在这里插入图片描述
反复删去链表中由 总和值为0连续节点组成的序列,直到不存在这样的序列为止。
在这里插入图片描述

ListNode* removeZeroSumSublists(ListNode* head) {ListNode* dummy=new ListNode(0,head);//哈希表存储前缀和,以及最后出现的节点unordered_map<int,ListNode*> mp;int prefixsum=0;ListNode* p=dummy;while(p!=nullptr){prefixsum += p->val;mp[prefixsum]=p;// 相同前缀和会覆盖,保留最后一个p=p->next;}//第二次遍历prefixsum=0;p=dummy;while(p!=nullptr){prefixsum+=p->val;p->next=mp[prefixsum]->next;p=p->next;}return dummy->next;
}

1.3改(交换节点)

序号题目链接
1链表中的下一个最大节点https://leetcode.cn/problems/next-greater-node-in-linked-list/description/?envType=problem-list-v2&envId=linked-list
2删除右侧有一个更大数值的节点https://leetcode.cn/problems/remove-nodes-from-linked-list/?envType=problem-list-v2&envId=linked-list
3交换K和倒数第K个节点https://leetcode.cn/problems/swapping-nodes-in-a-linked-list/description/?envType=problem-list-v2&envId=linked-list
4合并0之间的节点https://leetcode.cn/problems/merge-nodes-in-between-zeros/description/?envType=problem-list-v2&envId=linked-list

1.3.1链表中的下一个最大节点

遍历整个链表,找到第一个比当前值大的元素。没有则为0。

解法1:

  • p指向当前节点
  • q指向当前节点的下一个节点。q向后移动直到找到第一个比p值大的节点,添加到数组中。
vector<int> nextLargerNodes(ListNode* head) {vector<int> result;ListNode* p=head;while(p!=nullptr){ListNode* q=p->next;int maxval=0;while(q!=nullptr){if(q->val > p->val){maxval=q->val;break;//找到第一个最大的就退出}q=q->next;}result.push_back(maxval);p=p->next;}return result;
}

解法2:单调栈。
右侧更大可以使用单调栈。单调栈的关键是维持栈内元素的单调性。
栈中每个索引对应的 values 值从栈底到栈顶逐渐变小。在这里插入图片描述

vector<int> nextLargerNodes(ListNode* head) {//将链表转换为数组vector<int> values;ListNode* p=head;while(p!=nullptr){values.push_back(p->val);p=p->next;}//初始化结果数组int n=values.size();vector<int> result(n,0);//单调栈stack<int> st;for(int i=0;i<n;i++){//将要出栈的元素全部出完while(!st.empty() && values[i] > values[st.top()]){int idx=st.top();st.pop();result[idx]=values[i];}//栈空 || 当前值<栈顶值——入栈st.push(i);}return result;
}

1.3.2删除右侧有一个更大数值的节点

当前值与后面值比较:若存在一个值 > 当前值,将当前值删掉。
思路与上述的单调栈差不多。重点在于栈内存储的是节点,最后返回时候需要使用头插法进行连接。

ListNode* removeNodes(ListNode* head) {stack<ListNode*> st;ListNode* p=head;while(p!=nullptr){//单调栈while(!st.empty() && p->val > st.top()->val){st.pop();}st.push(p);p=p->next;}//单调栈的元素“底大顶小”,因此实际需要从头向下连接//重构链表ListNode* dummy=new ListNode();ListNode* q=dummy;while(!st.empty()){ListNode* node=st.top();st.pop();// 将当前节点插入到dummy和dummy->next之间node->next = dummy->next;dummy->next = node;}return dummy->next;
}

1.3.3交换K和倒数第K个节点

ListNode* swapNodes(ListNode* head, int k) {ListNode* dummy=new ListNode(0,head);//求链表的长度int length=0;ListNode* cur=head;while(cur!=nullptr){cur=cur->next;length++;}//找到第k个节点p,下标为k-1ListNode* p=dummy;for(int i=0;i<=k-1;i++){p=p->next;}//找到倒数第k个节点q,下标为length-kListNode* q=dummy;for(int i=0;i<=length-k;i++){q=q->next;}//交换swap(p->val,q->val);return head;
}

1.3.4合并0之间的节点

ListNode* mergeNodes(ListNode* head) {//新建一个链表ListNode* dummy=new ListNode(0);ListNode* cur=dummy;int sum=0;ListNode* p=head->next;while(p!=nullptr){if(p->val!=0){sum += p->val;}else{ListNode* newnode=new ListNode(sum);cur->next=newnode;cur=cur->next;sum=0;}p=p->next;}return dummy->next;;
}

1.4其他

序号题目链接
1链表组件https://leetcode.cn/problems/linked-list-components/description/?envType=problem-list-v2&envId=linked-list
2螺旋矩阵https://leetcode.cn/problems/spiral-matrix-iv/description/?envType=problem-list-v2&envId=linked-list
3临界值间的距离https://leetcode.cn/problems/find-the-minimum-and-maximum-number-of-nodes-between-critical-points/description/?envType=problem-list-v2&envId=linked-list

1.4.1链表组件

在这里插入图片描述

int numComponents(ListNode* head, vector<int>& nums) {// 将nums中的值存入哈希集合,便于快速查找unordered_set<int> numSet(nums.begin(), nums.end());int count=0;int flag=0;ListNode* p=head;while(p!=nullptr){//当前节点值在nums中if(numSet.count(p->val)){//之前没碰到过:新的组件if(!flag){count++;flag=1;}}//当前节点值不在nums中else{ flag=0;}p=p->next;}return count;
}

1.4.2螺旋矩阵

给你两个整数:m 和 n ,表示矩阵的维数。
另给你一个整数链表的头节点 head 。
请你生成一个大小为 m x n 的螺旋矩阵,矩阵包含链表中的所有整数。链表中的整数从矩阵 左上角 开始、顺时针 按 螺旋 顺序填充。如果还存在剩余的空格,则用 -1 填充。

模拟螺旋填充的过程:

  • 螺旋填充的路径是 “右→下→左→上” 的循环,每次完成一圈后缩小边界。
    • 从左到右填充上边界,完成后上边界下移
    • 从上到下填充右边界,完成后右边界左移
    • 从右到左填充下边界(如果还有空间),完成后下边界上移
    • 从下到上填充左边界(如果还有空间),完成后左边界右移
  • 用四个变量控制当前填充的边界:上边界 (top)、下边界 (bottom)、左边界 (left)、右边界 (right)
  • 从链表中依次取元素,按照螺旋路径填充,直到所有元素用完或矩阵填满
vector<vector<int>> spiralMatrix(int m, int n, ListNode* head) {// 初始化m×n矩阵,全部填充为-1vector<vector<int>> matrix(m, vector<int>(n, -1));//定义边界int top=0;int bottom=m-1;int left=0;int right=n-1;//ListNode* current=head;while(current!=nullptr && top <= bottom && left <= right){// 1. 从左到右填充上边界for (int col = left; col <= right && current != nullptr; col++) {matrix[top][col] = current->val;current = current->next;}top++; // 上边界下移,该排已填满// 2. 从上到下填充右边界for (int row = top; row <= bottom && current != nullptr; row++) {matrix[row][right] = current->val;current = current->next;}right--; // 右边界左移,该列已填满// 3. 从右到左填充下边界(需确保还有未填充的行)if (top <= bottom) {for (int col = right; col >= left && current != nullptr; col--) {matrix[bottom][col] = current->val;current = current->next;}bottom--; // 下边界上移,该排已填满}// 4. 从下到上填充左边界(需确保还有未填充的列)if (left <= right) {for (int row = bottom; row >= top && current != nullptr; row--) {matrix[row][left] = current->val;current = current->next;}left++; // 左边界右移,该列已填满}}return matrix;
}

1.4.3临界值的距离

模拟即可:

  • 使用三个指针prev、curr和next分别指向当前节点的前一个节点、当前节点和后一个节点。
  • 对于每个节点,检查它是否是局部极大值点(大于前后节点)或局部极小值点(小于前后节点)。
  • 记录所有临界点的位置索引(从 1 开始计数)。
  • 计算出最小距离和最大距离。
vector<int> nodesBetweenCriticalPoints(ListNode* head) {if(head==nullptr || head->next==nullptr) return{-1,-1};vector<int> result;ListNode* pre=head;ListNode* cur=head->next;ListNode* next=cur->next;int pos=1;while(next!=nullptr){int ismax=(cur->val > pre->val) && (cur->val > next->val);int ismin=(cur->val < pre->val) && (cur->val < next->val);if(ismax || ismin) result.push_back(pos);//每一组极值pre=cur;cur=next;next=next->next;pos++;}if(result.size()<2) return {-1,-1};//计算最小距离(相邻临界点之间的最小距离)int mind=INT_MAX;for(int i=1;i<result.size();i++){mind=min(mind,result[i]-result[i-1]);}//最大距离(第一个和最后一个极值的距离)int maxd=result.back()-result.front();return {mind,maxd};
}
http://www.xdnf.cn/news/19217.html

相关文章:

  • AWS集成开发最佳实践:构建高效可靠的云管理平台
  • React前端开发_Day4
  • 2025年06月 Python(四级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • SyncBack 备份同步软件: 使用 FTPS、SFTP 和 HTTPS 安全加密传输文件
  • IDEA之GO语言开发
  • 虚拟私有网络笔记
  • 成都五块石写字楼出租,国际数字影像产业园影像企业专属
  • Tinymce富文本编辑器封装
  • 云手机技术中都有着哪些局限性?
  • mysql中cross join于普通join的区别
  • 无懈可击的 TCP AIMD
  • 网络请求优化:用 Retrofit 拦截器玩转日志、重试与缓存,OkHttp 和 Volley 谁更香?
  • STM32 USBx Device MSC standalone 移植示例 LAT1488
  • Product Hunt 每日热榜 | 2025-08-29
  • typescript postgres@3.x jsonb数据插入绕过类型检测错误问题
  • SwiGLU激活函数的原理
  • TensorFlow 面试题及详细答案 120道(51-60)-- 模型保存、加载与部署
  • 微软正在公开测试其首个完全自主训练的大语言模型——MAI-1-preview
  • python 日常学习记录
  • Java全栈开发工程师面试实录:从基础到微服务的深度技术解析
  • 【python】相机输出图片时保留时间戳数据
  • Blender模拟结构光3D Scanner(三)获取相机观测点云的真值
  • 信息系统生命周期
  • 小程序版碰一碰发视频:源码搭建与定制化开发的源头技术解析
  • CSS scale函数详解
  • nginx 怎么将 https 请求转为 http
  • Docker 实战 -- EMQX
  • 第22章笔记|把“可传参脚本”打磨成“高级好用的工具”
  • 链表(LinkedList)
  • docker compose设置命令别名的方法