leetcode(链表专题)

数组模拟链表

#include<iostream>
using namespace std;const int N = 100;
// 单链表
// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;// 初始化
void init()
{head = -1;idx = 0;
}// 在链表头插入一个数a
void insert(int a)
{//先对新结点赋值e[idx] = a;//新结点的next指针指向前一个结点的next指针的位置ne[idx] = head;//把head的next位置更新为新结点,并且idx++,因为当前idx已经使用head = idx++;//  e[idx] = a, ne[idx] = head, head = idx ++ ;
}// 将头结点删除,需要保证头结点存在
void remove()
{head = ne[head];
}

​​​​​19. 删除链表的倒数第 N 个结点

思路

双指针,

第一个点可以能被删除,所以需要一个虚拟头节点。被删除的点位于倒数第n的位置,因为是单链表,即找到倒数n + 1最后,想要删除这个节点必须要保留它的前一个节点使其p->next  =  p->next->next。返回虚拟头节点的next。可以先使一个指针移动n步,然后两个指针

同时移动,第一个指针到达最后的时候,第二个指针恰好在倒数第n + 1的位置
 

code

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {auto p1 = new ListNode(-1);p1->next = head;auto p2 = p1 , p3 = p1;//先走n步while(n--)p2 = p2->next;//双指针同时向后移动,两个指针的距离是确定的while(p2->next){p2 = p2->next;p3 = p3->next;}p3->next = p3->next->next;return p1->next;}
};

21. 合并两个有序链表

思路:使用递归合并。口诀判空返,谁小递归谁,谁小返回谁。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {if(list1 == nullptr)return list2;if(list2 == nullptr)return list1;if(list1->val <= list2->val){list1->next = mergeTwoLists(list1->next,list2);return list1;}else{list2->next = mergeTwoLists(list1,list2->next);return list2;}   }
};

83. 删除排序链表中的重复元素

思路:相邻指针。使用相邻指针,对相邻两个结点进行对比,按照题意保留一个相同元素,那么就保留靠前的第一个。如果发现相邻的相同,则使用相同结点靠后的一个结点的下一个结点覆盖前面的结点,即p->next = p->next->next , 如果不同则把当前结点更新为下一个结点p = p->next

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {if(!head)return nullptr;auto p1 = head;while(p1){if(p1->next && p1->next->val == p1->val)p1->next = p1->next->next;else p1 = p1->next;}return head;}
};

82. 删除排序链表中的重复元素 II

思路

因为要删除所有相同的元素,所以head可能被修改,所以创建一个新的虚拟头节点dump。

需要声明一个结点p使得它为dump,一个结点q为dump->next。

如果q->val等于p-next->val的情况下,q就继续前进,直到找到一个与p->val不等的地方停下,判断当前q与p->next->next是否相等。作用就是(如果相等说明中间只有一个点),相反执行p->next = q ,删除中间的内容,最后循环完毕返回dump->next。

code

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {auto dummy = new ListNode(-1);dummy->next = head;auto p = dummy;while (p->next) {auto q = p->next;while (q && q->val == p->next->val) q = q->next;if (p->next->next == q) p = p->next;else p->next = q;}return dummy->next;}
};



 

思路

快慢指针算法,边界判断如果(快指针的next为空)则为奇数个,如果(快指针为空)则为偶数个。

code

class Solution {
public:ListNode* middleNode(ListNode* head) {auto p1 = head, p2 = head;while (p1 && p1->next){p2 = p2->next;p1 = p1->next->next;}return p2;}
};

206. 反转链表

思路

双指针算法,前后指针逐个翻转,直到最后一个节点,需要考虑边界问题。

code

//迭代法
class Solution {
public:ListNode* reverseList(ListNode* head) {if(!head)return NULL;auto p1 = head, p2 = p1->next;//定义两个相邻指针while(p2) {auto p3 = p2->next; //p3存储p2的后继节点p2->next = p1; //后面节点指针指向前面的节点p1 = p2;//双指针统一向后偏移p2 = p3;} head->next=NULL;return p1;}
};//递归法
class Solution {
public:ListNode* reverseList(ListNode* head) {if (!head || !head->next) return head;ListNode *tail = reverseList(head->next);head->next->next = head;head->next = nullptr;return tail;}
};

234. 回文链表

思路

使用vector来存储链表,然后来检查其中每一个元素,是否组成回文.。

code

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool isPalindrome(ListNode* head) {vector<int> v;while(head){v.push_back(head->val);head = head->next;}// 判断是否回文for(int i=0; i<v.size()/2; ++i){if(v[i] != v[v.size()-1-i]){return false;}}return true;}
};

141. 环形链表

思路

快慢指针,如果快指针被慢指针追上一定是环形链表。

code

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:bool hasCycle(ListNode *head) {ListNode *l1,*l2;l1=l2=head;while(l1!=NULL && l2!=NULL &&l1->next !=NULL){l1 = l1->next->next;l2 = l2->next;if(l1 == l2)return true;}return false;}
};

160. 相交链表

思路 

1.哈希表,通过把第一个链表的每个结点存入哈希表中,再遍历第二个链表来判断是否在哈希表中存在,入股存在即为相交结点。

2.双指针,即两个指针指向两个链表,同时走,如果相交那么就一定相等;如果不相交那么就是两条指针最后都为空。如图

code

//哈希表
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode(int x) : val(x), next(NULL) {}* };*/
class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {unordered_set<ListNode *> visited;ListNode *temp = headA;while (temp != nullptr) {visited.insert(temp);temp = temp->next;}temp = headB;while (temp != nullptr) {if (visited.count(temp)) {return temp;}temp = temp->next;}return nullptr;}
};//双指针
class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {if (headA == nullptr || headB == nullptr) {return nullptr;}ListNode *pA = headA, *pB = headB;while (pA != pB) {pA = pA == nullptr ? headB : pA->next;pB = pB == nullptr ? headA : pB->next;}return pA;}
};

148. 排序链表

思路

(归并排序) 时间:O(nlogn),空间O(1)
自顶向下递归形式的归并排序,由于递归需要使用系统栈,递归的最大深度是 logn,所以需要额外 O(logn)的空间。
所以我们需要使用自底向上非递归形式的归并排序算法。
基本思路是这样的,总共迭代 logn 次:

第一次,将整个区间分成连续的若干段,每段长度是2:[a0,a1],[a2,a3],…[an−1,an−1], 然后将每一段内排好序,小数在前,大数在后;
第二次,将整个区间分成连续的若干段,每段长度是4:[a0,…,a3],[a4,…,a7],…[an−4,…,an−1],然后将每一段内排好序,这次排序可以利用之前的结果,相当于将左右两个有序的半区间合并,可以通过一次线性扫描来完成;
依此类推,直到每段小区间的长度大于等于 n 为止;
另外,当 n 不是2的整次幂时,每次迭代只有最后一个区间会比较特殊,长度会小一些,遍历到指针为空时需要提前结束。

时间复杂度分析:整个链表总共遍历 logn 次,每次遍历的复杂度是 O(n),所以总时间复杂度是 O(nlogn)。
空间复杂度分析:整个算法没有递归,迭代时只会使用常数个额外变量,所以额外空间复杂度是 O(1)

code

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* sortList(ListNode* head) {int n = 0;for (auto p = head; p; p = p->next) n ++ ;for (int i = 1; i < n; i *= 2) {auto dummy = new ListNode(-1), cur = dummy;for (int j = 1; j <= n; j += i * 2) {auto p = head, q = p;for (int k = 0; k < i && q; k ++ ) q = q->next;auto o = q;for (int k = 0; k < i && o; k ++ ) o = o->next;int l = 0, r = 0;while (l < i && r < i && p && q)if (p->val <= q->val) cur = cur->next = p, p = p->next, l ++ ;else cur = cur->next = q, q = q->next, r ++ ;while (l < i && p) cur = cur->next = p, p = p->next, l ++ ;while (r < i && q) cur = cur->next = q, q = q->next, r ++ ;head = o;}cur->next = NULL;head = dummy->next;}return head;}
};

25. K 个一组翻转链表

思路

通过模拟法,模拟整个过程。需要提供双指针来维护修改某一区间的关系(例如相邻节点),

需要注意在修改节点的指针指向之前,要保存原有指向,以便利用。

解题步骤:

1.头节点可能要被改变,所以需要一个虚拟头节点

2.遍历是否够K个

3.交换K个元素,先将内部反转,然后处理连接前面部分,再处理连接后面部分

code

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseKGroup(ListNode* head, int k) {auto dump = new ListNode(-1);dump->next = head;for(auto p = dump;;){auto q = p;//计算后面是否有足够的k来支撑for(int i = 0; i < k && q;i++) q = q->next;//如果不够直接结束if(!q)break;auto a = p->next,b = a->next;//如果有k个节点,需要把内部反转k - 1次for(int i = 0; i < k -1 ;i++){auto c = b->next;b->next = a;a = b, b = c;}auto c = p->next;p->next = a, c->next = b;p = c;}return dump->next;}
};

Leetcode 146. LRU 缓存机制

思路:使用双链表模拟队列,使用哈希表记录键值对

class LRUCache {
public:struct Node {int key, val;Node *left, *right;Node(int _key, int _val): key(_key), val(_val), left(NULL), right(NULL) {}}*L, *R;unordered_map<int, Node*> hash;int n;void remove(Node* p) {p->right->left = p->left;p->left->right = p->right;}void insert(Node* p) {p->right = L->right;p->left = L;L->right->left = p;L->right = p;}LRUCache(int capacity) {n = capacity;L = new Node(-1, -1), R = new Node(-1, -1);L->right = R, R->left = L;}int get(int key) {if (hash.count(key) == 0) return -1;auto p = hash[key];remove(p);insert(p);return p->val;}void put(int key, int value) {if (hash.count(key)) {auto p = hash[key];p->val = value;remove(p);insert(p);} else {if (hash.size() == n) {auto p = R->left;remove(p);hash.erase(p->key);delete p;}auto p = new Node(key, value);hash[key] = p;insert(p);}}
};/*** Your LRUCache object will be instantiated and called as such:* LRUCache* obj = new LRUCache(capacity);* int param_1 = obj->get(key);* obj->put(key,value);*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lagom cqrs_Java和Lagom的CQRS

lagom cqrs我很高兴在Chicago Java User Group上进行了讨论&#xff0c;并讨论了Lagom如何实现CQRS&#xff08;命令查询责任隔离模式&#xff09;。 值得庆幸的是&#xff0c;有一个录音&#xff0c;我还把这些幻灯片发布在slideshare上 。 抽象&#xff1a; 一旦应用程序变…

【WebRTC---源码篇】(四)WebRTC线程模型

常见的线程模型 1.为了解决频繁线程创建与销毁,在此模型中使用的线程池。在线程池创建的时候就将一些线程创建起来,以提高效率。通过控制线程数量来解决线程频繁切换。 2.一般线程与线程存在前后关系的,线程执行完毕之后生成一个新的任务(task1 , task2,task3---)插入到任…

java cuba_CUBA平台–用于快速应用程序开发的开源Java框架

java cuba传统上&#xff0c;自计算时代开始以来&#xff0c;企业软件开发自然面临着一个挑战&#xff0c;当时自然而然地&#xff0c;企业软件开发本应专注于解决实际的业务问题&#xff0c;但与此同时&#xff0c;开发人员必须在技术上花费大量时间和精力。解决方案的一面&am…

java中什么时候应用异常_生产Java应用程序中的十大异常类型-基于1B事件

java中什么时候应用异常Pareto记录原理&#xff1a;97&#xff05;的记录错误语句是由3&#xff05;的唯一错误引起的 在最新的数据整理帖子之后&#xff0c;我们收到了很多反馈和问题&#xff0c;我们发现97&#xff05;的记录错误是由10个唯一错误引起的 。 根据大众的需求&…

C++ 11 深度学习(十四)C++类

(一)综述&#xff1a;类是我们自己定义的数据类型 设计时要考虑的角度&#xff1a; 站在设计和实现的角度来考虑&#xff1b;站在使用者的角度考虑&#xff1b;父类&#xff0c;子类之间的考虑&#xff1b; &#xff08;二&#xff09;explicit 首先, C中的explicit关键字只…

手动编译 lombok_Lombok,一种编译时Java注释预处理器,可最大程度地减少代码大小...

手动编译 lombok在本文中&#xff0c;我们将看到如何在常规Java代码中使用lombok来最大程度地减少代码长度和冗余。 什么是Lombok&#xff1f; Lombok&#xff0c;一个编译时注释预处理器&#xff0c;有助于在编译时注入一些代码。 在详细介绍之前&#xff0c;我要求您应该从…

mysql超大表处理方式是_第29问:MySQL 的复制心跳说它不想跳了

问题最近年底&#xff0c;大家的数据库经常跑批量大事务&#xff0c;会发现复制突然断开&#xff0c;报错“心跳与本地信息不兼容”&#xff1a;会是什么原因&#xff1f;实验我们先来复现一下&#xff0c;再进行分析。宽油&#xff0c;做一对主从数据库&#xff1a;我们先造一…

sap 分摊分配不产生会计凭证的原因_SAP软件的物料分类账功能

物料账介绍物料分类账(Material Ledger)是SAP财务模块的重要功能之一&#xff0c;用于对标准价计价的物料进行差异处理。激活ML后&#xff0c;系统会在"工厂物料"层(或更细的层次)为每个物料建立子账簿&#xff0c;记录该物料在各个期间的数量、价值变化情况。月底运…

忽略异常_忽略已检查的异常,所有出色的开发人员都在这样做–基于600,000个Java项目...

忽略异常Github和Sourceforge上超过600,000个Java项目中的异常处理概述 Java是使用检查异常的少数几种语言之一。 它们在编译时强制执行&#xff0c;并且需要某种处理。 但是……在实践中会发生什么&#xff1f; 大多数开发人员实际上会处理任何事情吗&#xff1f; 他们怎么做…

数据结构【队列专题】

先进先出&#xff08;First In First Out&#xff0c;FIFO&#xff09;的线性序列&#xff0c;成为“队列”。 队列也是一种线性表&#xff0c;只不过它是操作受限的线性表&#xff0c;只能在两端操作&#xff1a; 一端进&#xff0c;一端出。进的一端成为队尾&#xff08;re…

oracle安装卡在create inventory_滴滴云服务器上安装Oracle12cR2单实例数据库

一、相关说明Oracle数据库是由美国甲骨文公司推出的一款优秀的关系型数据库。当前最新版为Database 19c。本文简述Oracle Database 12cR2在滴滴云主机上的安装过程。如需更权威的指导方法请参考Oracle官方安装文档。二、环境概述一台DC2云主机&#xff08;2c4g&#xff09;一个…

【WebRTC---序篇】(二)Windows平台WebRTC源码编译

需要准备的东西 (一)一个强大的梯子(懂得都懂)!!!!!!!!! (二) 下载depot_tools Windows指定地址必须在此下载 打开这个页面,找 install depot_tools 这个关键字 请把他解压到C盘,并且设置到PATH环境变量种,且让它处于最顶端。 其他需要设置的额外变量 DEPOT_TOOLS_…

商品管理后台发布商品时,规格值组合的前端交互的实现逻辑

方案1&#xff1a;先计算总行数&#xff0c;再循环填充规格值 根据每种规格值数量计算得到总行数&#xff0c;如果下图有3种规格&#xff1a;长度、重量、大小&#xff0c;规格值个数分别为&#xff1a;3、3、2,3x3x218行。 规格种类有3种&#xff0c;于是写3层嵌套递归循环填…

【WebRTC---源码篇】(五)WebRTC视频引擎

1. 视频数据的采集时间 2.视频分发器VideoBroadCaster

activiti异步执行_对基于消息队列的Activiti异步执行器进行基准测试

activiti异步执行一点历史 永无休止的一件事是&#xff0c;Activiti在某些非常大的规模的大型组织中的使用方式。 过去&#xff0c;这导致了各种优化和重构&#xff0c;其中包括异步执行器-替换旧的作业执行器。 对于未启动的用户&#xff1a;这些执行器在流程实例中处理计时器…

chrome浏览器设置网页快速到顶部和到底部的方法

鼠标移到浏览器的书签任意位置&#xff0c;点击鼠标右键添加书签&#xff0c;在添加书签的窗口输入名称和js代码&#xff0c;然后把书签移到浏览器书签栏的最左侧&#xff0c;这样每次浏览网页就可以使用快捷方式快速到底部或者顶部了。 快速到顶部的js代码&#xff1a;javascr…

apache pdfbox_Apache PDFBox命令行工具:无需Java编码

apache pdfbox在博客文章Apache PDFBox 2中 &#xff0c;我演示了将Apache PDFBox 2用作从Java代码中调用的库来操作PDF。 事实证明&#xff0c;Apache PDFBox 2还提供了可以直接从命令行直接使用的命令行工具 &#xff0c;而无需其他Java编码。 有几种命令行工具可用&#xff…

【WebRTC---源码篇】(六)NACK判断包位置的关键算法

首先保证a与b不相等 template <typename T, T M = 0> inline bool AheadOf(T a, T b) {static_assert(std::is_unsigned<T>::value,"Type must be an unsigned integer.");return a != b && AheadOrAt<T, M>(a, b); } template <type…

spring集成mq_使用Spring Integration Java DSL与Rabbit MQ集成

spring集成mq我最近参加了在拉斯维加斯举行的2016年Spring大会 &#xff0c;很幸运地看到了我在软件世界中长期敬佩的一些人。 我亲自遇到了其中的两个人&#xff0c;他们实际上合并了几年前我与Spring Integration相关的一些次要贡献– Gary Russel和Artem Bilan &#xff0c;…

MyEclipse 如何使用断点调试

文章目录1、在需要的代码行处打断点右键添加断点双击添加断点快捷键添加断点2、以debug模式开启服务器通过debug执行列表&#xff0c;选择服务器启动当前程序按右键&#xff0c;选择debug as&#xff0c;再选择服务器启动开发视图底部server列表选择服务器开启debug视图&#x…