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

数据结构——线性表(链表,力扣简单篇)

文章目录

  • 一、链表的一些基本操作
    • 1.1归并
      • 1.1.1 升序+升序=升序【尾插法】
      • 1.1.2升序+升序=降序【头插法 or 反转】
    • 1.2反转
      • 1.2.1反转整个链表【头插法】
      • 1.2.2反转部分链表【q后尾插】
    • 1.3双指针
      • 1.3.1寻找中间节点
      • 1.3.2寻找倒数第N个节点
    • 1.4 回文 & 环形 & 相交
      • 1.4.1回文【数组】
      • 1.4.2环形【visited or 双指针】
      • 1.4.3相交【遍历 or 长度对齐】
      • 1.4.4二进制链表转换为整数

一、链表的一些基本操作

序号题目链接
1归并https://leetcode.cn/problems/merge-two-sorted-lists/description/?envType=problem-list-v2&envId=linked-list
2反转https://leetcode.cn/problems/reverse-linked-list/solutions/3735891/lian-biao-fan-zhuan-by-yang-zhi-gan-lu-j-w65m/?envType=problem-list-v2&envId=linked-list
3反转2https://leetcode.cn/problems/reverse-linked-list-ii/description/?envType=problem-list-v2&envId=linked-list
4中间节点https://leetcode.cn/problems/middle-of-the-linked-list/?envType=problem-list-v2&envId=linked-list
5倒数第N个节点https://leetcode.cn/problems/remove-nth-node-from-end-of-list/submissions/652645354/?envType=problem-list-v2&envId=linked-list
6回文https://leetcode.cn/problems/palindrome-linked-list/?envType=problem-list-v2&envId=linked-list
7环形https://leetcode.cn/problems/linked-list-cycle/description/?envType=problem-list-v2&envId=linked-list
8相交https://leetcode.cn/problems/intersection-of-two-linked-lists/description/?envType=problem-list-v2&envId=linked-list

1.1归并

1.1.1 升序+升序=升序【尾插法】

对于二路归并来说,将两个有序的线性表归并成一个。
链表并不需要开辟新的空间。

情况1:升序+升序=升序

  • 对于链表1,用p指向当前链表。
  • 对于链表2,用q指向当前链表。
  • 若p->val < q->val,则将p连入链表:将p往后挪动一个。cur也向后移动一个。同理q也进行同样的操作。
  • 当p==null,表示链表1已经完了,直接将链表2接到最终结果后就行了。q同理。
    在这里插入图片描述
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {if(list1==nullptr && list2==nullptr) return list1;//创建一个头结点和cur指针ListNode* dummy=new ListNode();ListNode* cur=dummy;ListNode* p=list1;ListNode* q=list2;//当两个链表都没遍历完时,进行比较操作,并移动指针while(p!=nullptr && q!=nullptr){if(p->val <= q->val){//尾插法插入cur->next=p;//向后移动一个p=p->next;cur=cur->next;}else{//尾插法插入cur->next=q;//向后移动一个q=q->next;cur=cur->next;}}//当其中有一个链表已经遍历完时:直接接入另一个链表if(p==nullptr) cur->next=q;if(q==nullptr) cur->next=p;return dummy->next;
}

1.1.2升序+升序=降序【头插法 or 反转】

情况2:升序+升序=降序

  • 方法1:归并成升序后,反转链表
  • 方法2:用两个指针p和q指向链表,比较链表的值,将较小的那个用头插法插入到dummy的后面即可。
    在这里插入图片描述
    需要注意的是:头插法中必须先保存当前节点的下一个指针,否则会丢失原链表的后续节点。原代码:
  • p->next=dummy->next;
  • dummy->next=p;
  • p=p->next;
    最后一个p=p->next; 此时再执行 p = p->next,p=dummy->next,而不是原链表中 p 的下一个节点。
while(p!=nullptr && q!=nullptr){if(p->val <= q->val){//头插法插入ListNode* pnext=p->next;p->next=dummy->next;dummy->next=p;//向后p=pnext;}else{ListNode* qnext=q->next;//头插法插入q->next=dummy->next;dummy->next=q;//向后q=qnext;}
}
// 处理剩余节点:将剩余节点依次头插
while (p != nullptr) {ListNode* pnext=p->next;p->next = dummy->next;dummy->next=p;p=pnext;
}
while (q != nullptr) {ListNode* qnext=q->next;q->next = dummy->next;dummy->next = q;q = qnext;;
}

1.2反转

1.2.1反转整个链表【头插法】

反转1(反转整个链表):将整个链表反转

使用头插法将整个链表重新插入,注意保存p的下一个指针 pnext。
在这里插入图片描述
需要注意的是:如果初始化dummy指向头结点,那么在第一次循环时,容易形成闭环。正常的1和2之间已经没有了联系,但是并不影响p的头插。
在这里插入图片描述

ListNode* reverseList(ListNode* head) {if(head==nullptr || head->next==nullptr) return head;ListNode* dummy=new ListNode();dummy->next=nullptr;//注意dummy初始指向空ListNode* p=head;while(p!=nullptr){ListNode* pnext=p->next;p->next=dummy->next;dummy->next=p;p=pnext;}return dummy->next;}

1.2.2反转部分链表【q后尾插】

反转2(反转部分链表):给出指针 p 以及指针 q 指向链表中的某个节点。要求从 p->next 开始一直到 q 范围内的链表逆置。

  • 记录一下p后面待反转的节点t
  • 然后类似于将 t 从序列中删除,然后插入到 q 的后面。
  • 当p->next==q 循环停止在这里插入图片描述
    在这里插入图片描述
ListNode* reverseList(ListNode* head) {if(head==nullptr || head->next==nullptr) return head;ListNode* dummy=new ListNode();dummy->next=head;ListNode* p=dummy;ListNode* q=dummy;while(q->next!=nullptr) q=q->next;while(p->next!=q){ListNode* t=p->next;//t必须写在里面p->next=t->next;t->next=q->next;q->next=t;}return dummy->next;
}

1.3双指针

1.3.1寻找中间节点

  • 思路1:遍历链表,得到链表的长度,中间节点为 index=n/2 的节点
  • 思路2:利用指针:快指针 fast 每次走 2 步。慢指针 slow 每次走 1 步
    • 对于6个元素的:快指针【1-3-5-null】,慢指针【1-2-3-4】。fast==null 结束
    • 对于7个元素的:快指针【1-3-5-7-null】,慢指针【1-2-3-4】。fast->next==null 结束。
while (fast != nullptr && fast->next != nullptr) {slow = slow->next;       // 慢指针走1步fast = fast->next->next; // 快指针走2步
}

1.3.2寻找倒数第N个节点

  • 思路1:遍历链表,得到链表的长度,倒数第N个节点的下标应该为length-n,其前一个节点的下标为length-n-1。
  • 思路2:慢指针和快指针之间相差k个节点。【先让 fast 指针走到下标为n-1的节点处】。当快指针走到终点时,慢指针所指的节点刚好就是倒数第N个节点。
    在这里插入图片描述
    在这里插入图片描述
int kthToLast(ListNode* head, int k) {ListNode* dummy=new ListNode();dummy->next=head;ListNode* fast=dummy;ListNode* slow=dummy;for(int i=0;i<=k-1;i++){fast=fast->next;}while(fast!=nullptr){fast=fast->next;slow=slow->next;}return slow->val;}

1.4 回文 & 环形 & 相交

1.4.1回文【数组】

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。

遍历整个数组,将val值存储在vector数组中。然后用双指针(头和尾)分别指向,判断,移动。

bool isPalindrome(ListNode* head) {vector<int> result;//将val存入resultwhile(head!=nullptr){result.push_back(head->val);head=head->next;}//判断int left=0;int right=result.size()-1;while(left<right){if(result[left]==result[right]) {left++;right--;}else return 0;}return 1;
}

1.4.2环形【visited or 双指针】

给你一个链表的头节点 head ,判断链表中是否有环。

  • 思路1:遍历整个链表,然后看该节点是否已经被访问过了。用类似于visited数组来存储访问过的元素。
    • 若节点被访问过了:有环
    • 否则:没环,将当前节点加入数组。直到链表访问完成。

需要注意的是:unordered_set(无序)查找的时间复杂度为O(1),vector查找的时间复杂度为O(n)

bool hasCycle(ListNode *head) {unordered_set<ListNode*> visited;while(head!=nullptr){if(visited.count(head)) return 1;else visited.insert(head);head=head->next;}return 0;
}
  • 思路2:设计快慢指针。慢指针每次移动 1 步;快指针每次移动 2 步。初始slow=head fast=head
  • 若链表有环,当慢指针进入环后,快指针也会进入环并以更快的速度绕环移动,最终会追上慢指针(类似跑道上的套圈)。
    在这里插入图片描述
    若链表无环,快指针会先于慢指针到达尾部。在这里插入图片描述
    在这里插入图片描述
bool hasCycle(ListNode *head) {if(head==nullptr || head->next==nullptr) return 0;ListNode* fast=head;ListNode* slow=head;while(fast!=nullptr && fast->next!=nullptr){slow=slow->next;fast=fast->next->next;if(slow==fast) return 1;}return 0;}

1.4.3相交【遍历 or 长度对齐】

给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

思路1:长度对齐法:

  • 分别计算两个链表的长度 lenA 和 lenB。
  • 让较长的链表的指针先移动 |lenA - lenB| 步,使两个指针处于 “同一起跑线”(距离各自链表尾部的长度相等)。
  • 同时移动两个指针,若相遇则为相交节点;若同时到达尾部仍未相遇,则不相交。
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {if(headA==nullptr && headB==nullptr) return nullptr;int lenA=getlength(headA);int lenB=getlength(headB);//调整指针位置至一样多ListNode* pA=headA;ListNode* pB=headB;if(lenA<lenB){for(int i=1;i<=lenB-lenA;i++){pB=pB->next;}}else{for(int i=1;i<=lenA-lenB;i++){pA=pA->next;}}//判断是否指向同样的节点while(pA!=nullptr && pB!=nullptr){if(pA==pB) return pA;else{pA=pA->next;pB=pB->next;}}return nullptr;
}

思路2:

  • 遍历第一个链表,将所有节点的地址(指针)存入哈希表(如 unordered_set)。
  • 遍历第二个链表,对每个节点检查是否在哈希表中存在:
    • 若存在,说明该节点是第一个相交节点,返回该节点。
    • 若遍历结束均不存在,说明两链表不相交,返回 null。
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {unordered_set<ListNode*> nodes;while(headA!=nullptr){nodes.insert(headA);headA=headA->next;}while(headB!=nullptr){if(nodes.count(headB)) return headB;headB=headB->next;}return nullptr;
}

1.4.4二进制链表转换为整数

将对每一位数字乘以对应的幂指数就行了。

int getDecimalValue(ListNode* head) {long long sum=0;int l=getlength(head);for(int i=0;i<=l-1;i++){sum+=head->val * pow(2,l-i-1);head=head->next;}return sum;
}

优化1:
例:123(十进制)=【12】*10 + 【3】。将每次得到的sum * 进制 + val即可。

sum = sum * 2 + head->val; // 每一步等价于左移1位(×2)再加上当前值sum = (sum << 1) | head->val; // 左移1位(×2)+ 当前位值
http://www.dtcms.com/a/331224.html

相关文章:

  • vscode的wsl环境,ESP32驱动0.96寸oled屏幕
  • 失败存储:查看未成功的内容
  • vscode使用keil5出现变量跳转不了
  • 如何让手机访问本地服务器部署的网页?无公网IP内网主机应用,自定义外网地址,给任意网设备访问
  • 利用 Java 爬虫按图搜索 1688 商品(拍立淘)实战指南
  • 第一章 java基础
  • 手写MyBatis第17弹:ResultSetMetaData揭秘:数据库字段到Java属性的桥梁
  • 《C++》哈希表解析与实现
  • 能源行业数字化转型:边缘计算网关在油田场景的深度应用
  • Python机器学习与深度学习;Transformer模型/注意力机制/目标检测/语义分割/图神经网络/强化学习/生成式模型/自监督学习/物理信息神经网络等
  • 基于51单片机倒计时器秒表定时器数码管显示设计
  • vue+后端
  • 微服务、分布式概念-以及集群部署 vs 分布式部署
  • 容器运行时支持GPU,并使用1panel安装ollama
  • 将 pdf 转为高清 jpg
  • 数巅中标中建科技AI知识库项目,开启建筑业数智化新篇章
  • CSS aspect-ratio 属性
  • Multimodal RAG Enhanced Visual Description
  • Linux 对 RPM 包的管理
  • 19 ABP Framework 本地化系统
  • hashmap和concurrentHashmap是否允许null值和null健
  • PiscCode使用光流法计算漂浮物位移速度
  • 把 AI 推理塞进「 8 位 MCU 」——0.5 KB RAM 跑通关键词唤醒的魔幻之旅
  • 监控插件SkyWalking(一)原理
  • 嵌入式学习的第四十九天-时钟+EPIT+GPT定时器
  • 无人机探测器技术解析
  • 阿里巴巴 Qwen-Image:免费开源,还要挑战 GPT-4.1 和 Midjourney?
  • 恢复GPT-4o,增加付费配额:OpenAI的“补救措施”如何重塑用户金字塔
  • OpenCV ------图像基础处理(一)
  • 【OpenCV】Mat详解