leetcode刷题链表

反转链表Ⅱ

  • 题目描述将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。例如:
    给出的链表为9->7->2->5->4->3->6->NULL , m=3,n=6,
    返回9->7->3->4->5->2->6 ->NULL

    ​ 要求:时间复杂度 O(n)O(n) ,空间复杂度 O(n)O(n)

    ​ 进阶:时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)

  • 解题方法:穿针引线法,在需要反转的区间里,每遍历到一个节点,让这个新节点来到反转部分的起始位置。

  • 使用三个指针变量 pre、curr、next 来记录反转的过程中需要的变量,它们的意义如下:

    ​ curr:指向待反转区域的第一个节点 left;
    ​ next:永远指向 curr 的下一个节点,循环过程中,curr 变化以后 next 会变化;
    ​ pre:永远指向待反转区域的第一个节点 left 的前一个节点,在循环过程中不变。

    class Solution {
    public:ListNode *reverseBetween(ListNode *head, int left, int right) {ListNode *dummyNode = new ListNode(-1);dummyNode->next = head;ListNode *pre = dummyNode;for (int i = 0; i < left - 1; i++) {pre = pre->next;}ListNode *cur = pre->next;ListNode *next;for (int i = 0; i < right - left; i++) {next = cur->next;cur->next = next->next;next->next = pre->next;pre->next = next;}return dummyNode->next;}
    };

复杂链表的复制

  • 题目描述:请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

  • 解题方法一:回溯+哈希表

    class Solution {
    public:unordered_map<Node*, Node*> cachedNode;Node* copyRandomList(Node* head) {if (head == nullptr) {return nullptr;}if (!cachedNode.count(head)) {Node* newHead = new Node(head->val);cachedNode[head] = newHead;headNew->next = copyRandomList(head->next);headNew->random = copyRandomList(head->random);}return cachedNode[head];}
    };
  • 解题方法二:迭代 + 节点拆分,复制每一个节点并插入节点之后,每个复制节点的random 指针在前一节点random 指针的下一个指针。

    class Solution {
    public:Node* copyRandomList(Node* head) {if (head == nullptr) {return nullptr;}for (Node* node = head; node != nullptr; node = node->next->next) {Node* nodeNew = new Node(node->val);nodeNew->next = node->next;node->next = nodeNew;}for (Node* node = head; node != nullptr; node = node->next->next) {Node* nodeNew = node->next;nodeNew->random = (node->random != nullptr) ? node->random->next : nullptr;}Node* headNew = head->next;for (Node* node = head; node != nullptr; node = node->next) {Node* nodeNew = node->next;node->next = node->next->next;nodeNew->next = (nodeNew->next != nullptr) ? nodeNew->next->next : nullptr;}return headNew;}
    };
    

链表K个一组进行翻转

  • 题目描述:对于给定链表1->2->3->4->5,k=2,反转后返回2->1->4->3->5

  • 解题方法:把链表节点按照 k 个一组分组,所以可以使用一个指针 head 依次指向每组的头节点。这个指针每次向前移动 k 步,直至链表结尾。对于每个分组,我们先判断它的长度是否大于等于 k。若是,我们就翻转这部分链表,否则不需要翻转。

    class Solution {
    public:// 翻转一个子链表,并且返回新的头与尾pair<ListNode*, ListNode*> reverseList(ListNode* head, ListNode* tail) {ListNode* prev = tail->next;ListNode* cur = head;while (prev != tail) {ListNode* nex = cur->next;cur->next = prev;prev = cur;cur= nex;}return {tail, head};}ListNode* reverseKGroup(ListNode* head, int k) {ListNode* hair = new ListNode(0);hair->next = head;ListNode* pre = hair;while (head) {ListNode* tail = pre;// 查看剩余部分长度是否大于等于 kfor (int i = 0; i < k; ++i) {tail = tail->next;if (!tail) {return hair->next;}}ListNode* nex = tail->next;   auto res = reverseList(head, tail);head = res.first;tail = res.second;      // 把子链表重新接回原链表pre->next = head;tail->next = nex;pre = tail;head = tail->next;}return hair->next;}
    };
    

合并k个排序链表

  • 题目描述:合并 k 个升序的链表并将结果作为一个升序的链表返回其头节点。要求:时间复杂度 O(nlogk)

  • 解题方法一:分治法

    class Solution {
    public:ListNode* mergeTwoLists(ListNode* pHead1, ListNode* pHead2) {if(pHead1==NULL) return pHead2;if(pHead2==NULL) return pHead1;ListNode*dummy= new ListNode(-1); ListNode*temp=dummy;while(pHead1 && pHead2){if(pHead1->val>pHead2->val){temp->next=pHead2;pHead2=pHead2->next;}else{temp->next=pHead1;pHead1=pHead1->next;}temp=temp->next;}if(pHead1){temp->next=pHead1;}if(pHead2){temp->next=pHead2;}return dummy->next;}ListNode* merge(vector <ListNode*> &lists, int l, int r) {if (l == r) return lists[l];if (l > r) return nullptr;int mid = (l + r) >> 1;return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));}ListNode *mergeKLists(vector<ListNode *> &lists) {int n=lists.size();return merge(lists,0,n-1);}
    };
    
  • 解题方法二:使用优先队列去存储所有链表。按照链表头结点值,进行从小到大的排序,最小的头结点的链表在堆顶。

    1. 每次将堆顶的链表取出
    2. 将头结点从取出的链表上去除,并插在所需目标链表的尾部。
    3. 将取出的链表放回堆中。若链表为null,则不放回。
      重复1,2,3过程,直到堆为空,循环终止。
class Solution {
public:struct Aux{int val;ListNode * ptr;bool operator <(const Aux& aux) const{return val>aux.val;}};priority_queue<Aux> myqueue;ListNode *mergeKLists(vector<ListNode *> &lists) {int n=lists.size();if(n==0) return NULL;if(n==1) return lists[0];    for(auto node:lists){if(node){Aux a={node->val,node};myqueue.push(a);     }}ListNode*dummy=new ListNode(-1);ListNode * pre=dummy;while(!myqueue.empty()){Aux aux=myqueue.top();myqueue.pop();pre->next=aux.ptr;pre=pre->next;ListNode * nxt=aux.ptr->next;if(nxt==NULL) continue;myqueue.push({nxt->val,nxt});   }return dummy->next;}
};

删除链表的第N个节点

  • 题目描述:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

  • 解题方法一:双指针

  • 解题方法二:栈先进后出,在遍历链表的同时将所有节点依次入栈。弹出栈的第 N个节点就是需要删除的节点,并且目前栈顶的节点就是待删除节点的前驱节点。

class Solution {
public: ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode * dummy=new ListNode(-1);dummy->next=head;ListNode * cur=dummy;stack<ListNode*> stk;while(cur){stk.push(cur);cur=cur->next;}for(int i=0;i<n;++i){stk.pop();}ListNode * pre=stk.top();pre->next=pre->next->next;return dummy->next;}
};

两个链表的第一个公共节点

  • 题目描述:输入两个无环的单向链表L1,L2,找出它们的第一个公共结点,如果没有公共节点则返回空。

  • 解题方法:双指针。两个指针分别指向L1,L2,保证两指针走过的距离相等,当指针走到链表NULL节点(末尾节点的后继),令其等于另一个链表的头节点,直到两个指针相遇为止,如果有公共节点,两个指针将在此节点处相遇,如果没有则会在NULL相遇。

    class Solution {
    public:ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {ListNode * p1=pHead1;ListNode * p2=pHead2;while(p1 != p2){p1=p1==NULL?pHead2:p1->next;p2=p2==NULL?pHead1:p2->next;}return p1;}
    };
    

链表相加Ⅱ

  • 题目描述:假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数,头节点存放整数的高位。给定两个这种链表,请生成代表两个整数相加值的结果链表。例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

  • 解题方法:整数相加由低位到高位,两个链表从末尾节点开始相加,方向与指针方向相反,考虑栈先进后出的特点,利用两个辅助栈,相加后用头插法构造新链表。

    class Solution {
    public:ListNode* addInList(ListNode* head1, ListNode* head2) {// write code herestack<int> stk1;stack<int> stk2;while(head1){stk1.push(head1->val);head1=head1->next;}while(head2){stk2.push(head2->val);head2=head2->next;}int carry=0;ListNode * temp=NULL;while(!stk1.empty()||!stk2.empty()){int s1,s2;if(!stk1.empty()){s1=stk1.top();stk1.pop();}else{s1=0;}if(!stk2.empty()){s2=stk2.top();stk2.pop();}else{s2=0;}int sum=s1+s2+carry;ListNode* headNew=new ListNode(sum%10);carry=sum/10;headNew->next=temp;temp=head;}if(carry!=0){ListNode* headNew=new ListNode(carry);headNew->next=temp;temp=head;}return temp;}
    };
    

单链表排序

  • 题目描述:给定一个节点数为n的无序单链表,对其按升序排序。数据范围:0 < <n≤100000;要求:时间复杂度*** O(nlogn)***

  • 解题方法一:自顶向下归并排序。

    1. 找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
    2. 对两个子链表分别排序。
    3. 将两个排序后的子链表合并,得到完整的排序后的链表。
    class Solution {
    public:ListNode* merge(ListNode* head1, ListNode* head2) {ListNode* dummyHead = new ListNode(0);ListNode* temp = dummyHead;while (head1 != NULL && head2 != NULL) {if (head1->val <= head2->val) {temp->next = head1;head1 = head1->next;} else {temp->next = head2;head2 = head2->next;}temp = temp->next;}if (head1 != NULL) {temp->next = head1;} else if (head2 != NULL) {temp->next = head2;}return dummyHead->next;}ListNode * sortlist(ListNode*head,ListNode*tail){if(head==NULL){return head;}if(head->next==tail){  //当链表中只有两个元素时,断开指针并返回第一个元素head->next=NULL;return head;}ListNode*fast=head;ListNode*slow=head;while(fast!=tail){fast=fast->next;slow=slow->next;if(fast!=tail) fast=fast->next;}ListNode * mid=slow;return merge(sortlist(head,mid), sortlist(mid,tail));//左右两半递归均包含mid,当仅剩两个节点时丢弃第二个}ListNode* sortInList(ListNode* head) {return sortlist(head, NULL);}
    };
    
  • 解题方法二:自底向上归并排序

    首先求得链表的长度 length,然后将链表拆分成子链表进行合并。具体做法如下。

    1. 用 subLength 表示每次需要排序的子链表的长度,初始时subLength=1。

    2. 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。合并两个子链表仍然使用合并两个有序链表的做法。

    3. 将subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。

    class Solution {
    public:ListNode* merge(ListNode* head1, ListNode* head2) {ListNode* dummyHead = new ListNode(0);ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;while (temp1 != NULL && temp2 != NULL) {if (temp1->val <= temp2->val) {temp->next = temp1;temp1 = temp1->next;} else {temp->next = temp2;temp2 = temp2->next;}temp = temp->next;}if (temp1 != NULL) {temp->next = temp1;} else if (temp2 != NULL) {temp->next = temp2;}return dummyHead->next;}ListNode* sortInList(ListNode* head) {if(head == NULL || head->next == NULL)return head;int nodeNum=0;ListNode * temp1=head;while(temp1){nodeNum++;temp1=temp1->next;}ListNode*dummy=new ListNode(0);dummy->next=head;for(int sublength=1;sublength<nodeNum;sublength<<=1){ListNode*pre=dummy;ListNode*cur=dummy->next;  while(cur!=NULL){ListNode*head1=cur;for(int i=1;i<sublength&&cur->next != NULL;++i){cur=cur->next;}ListNode*head2=cur->next;cur->next=NULL;cur=head2;for(int i=1;i<sublength&&cur!=NULL&&cur->next != NULL;++i){cur=cur->next;}if(cur!=NULL){nxt=cur->next;cur->next=NULL;}ListNode* merged=merge(head1,head2);pre->next=merged;while(pre->next!=NULL){pre=pre->next;}cur=nxt;}}return dummy->NULL;}
    };
    

判断一个链表是否为回文结构

  • 题目描述:给定一个链表,请判断该链表是否为回文结构。回文是指该字符串正序逆序完全一致。

  • 解题方法一:将链表转化为数组

  • 解题方法二:快慢指针。初始化fast与slow指向头节点,fast移动速度是slow的两倍,fast到链表末尾时,slow到达中心位置;翻转后半部分的链表,与前半部分进行比较。

    class Solution {
    public:ListNode* reservelist(ListNode*head){ListNode* pre=NULL;while(head){ListNode * nxt=head->next;head->next=pre;pre=head;head=nxt;}return pre;   }bool isPail(ListNode* head) {ListNode * fast=head,*slow=head;while(fast&& fast->next ){fast=fast->next->next;slow=slow->next;}if(fast!=NULL){         //当fast不为NULL时,链表节点个数为奇数,此时slow为中心节点slow=slow->next;}fast=head;              //fast重新指向头节点slow=reservelist(slow); //翻转后半链表while(slow){if(fast->val!=slow->val) return false;fast=fast->next;slow=slow->next;}return true;}
    };
    

链表的奇偶重排

  • 题目描述:给定一个单链表,请设定一个函数,将链表的奇数位节点和偶数位节点分别放在一起,重排后输出。

    注意是节点的编号而非节点的数值。

  • 解题方法:双指针,第一个指针为奇数位,第二个指针位偶数位,奇数位在前,偶数位在后

    class Solution {
    public:ListNode* oddEvenList(ListNode* head) {//如果链表为空,不用重排if(head == NULL) return head;//even开头指向第二个节点,可能为空ListNode* even = head->next; //odd开头指向第一个节点ListNode* odd = head; //指向even开头ListNode* evenhead = even; while(even != NULL && even->next != NULL){ //odd连接even的后一个,即奇数位odd->next = even->next; //odd进入后一个奇数位odd = odd->next; //even连接后一个奇数的后一位,即偶数位even->next = odd->next; //even进入后一个偶数位even = even->next; } //even整体接在odd后面odd->next = evenhead; return head;}
    };
    

删除链表中的重复元素Ⅰ

  • 题目描述:删除给出链表中的重复元素(链表中元素从小到大有序),使链表中的所有元素都只出现一次例如:给出的链表为1->1->2,返回1-> 2。

  • 解题方法:遇到连续相同的元素,保留第一个

  • class Solution {
    public:ListNode* deleteDuplicates(ListNode* head) {// write code hereif(!head) return NULL;ListNode * cur=head;while(cur&&cur->next){ListNode *nxt=cur->next;if(cur->val==nxt->val){    //相邻元素相同,跳过下一位,之后的元素继续与上一位比较cur->next=nxt->next;}else{cur=cur->next;        //相邻元素不同,正常遍历}}return head;}
    };
    

删除链表中重复元素Ⅱ

  • 题目描述:给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。给出的链表为1->1->1->2->3,返回2->3。
  • 解题方法:这是一个升序链表,重复的节点都连在一起,我们就可以很轻易地比较到重复的节点,然后将所有的连续相同的节点都跳过,连接不相同的第一个节点。注意添加一个虚拟的头节点,以便于删除第一个节点。
    1. 链表前加虚拟的头节点。
    2. 遍历链表,从虚拟节点的后继节点开始每次比较相邻两个节点,如果遇到了两个相邻节点相同,则新开内循环将这一段所有的相同都遍历过去。
    3. 在2中这一连串相同的节点前的节点直接连上后续第一个不相同值的节点。
    4. 返回时去掉添加的表头。
class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {if(!head) return NULL;ListNode * dummy=new ListNode(0);dummy->next=head;ListNode * cur=dummy;while(cur->next && cur->next->next){if(cur->next->val==cur->next->next->val){int num=cur->next->val;while(cur->next!=NULL&&cur->next->val==num){cur->next=cur->next->next;}}else{cur=cur->next;}          }return dummy->next;}
};

返回时去掉添加的表头。

class Solution {
public:ListNode* deleteDuplicates(ListNode* head) {if(!head) return NULL;ListNode * dummy=new ListNode(0);dummy->next=head;ListNode * cur=dummy;while(cur->next && cur->next->next){if(cur->next->val==cur->next->next->val){int num=cur->next->val;while(cur->next!=NULL&&cur->next->val==num){cur->next=cur->next->next;}}else{cur=cur->next;}          }return dummy->next;}
};

leetcode刷题链表相关推荐

  1. C#LeetCode刷题-链表

    链表篇 # 题名 刷题 通过率 难度 2 两数相加   29.0% 中等 19 删除链表的倒数第N个节点   29.4% 中等 21 合并两个有序链表 C#LeetCode刷题之#21-合并两个有序链 ...

  2. LeetCode刷题——链表OJ(历时三天,万字博客,十一道经典题,带你手撕链表)

    知之愈明,则行之愈笃:行之愈笃,则知之益明. 学完链表,我们不得刷刷题增进对链表的认识?今天博主选取十一道经典链表题,从刷题者的角度剖析重点和易错点,讲解最简单的方法,文章内附题目和题目链接,重点内容 ...

  3. LeetCode刷题记录15——21. Merge Two Sorted Lists(easy)

    LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) 目录 LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) ...

  4. LeetCode刷题记录3——237. Delete Node in a Linked List(easy)

    LeetCode刷题记录3--237. Delete Node in a Linked List(easy) 目录 LeetCode刷题记录3--237. Delete Node in a Linke ...

  5. LeetCode刷题之旅

    LeetCode刷题之旅 一.链表 1.链表逆序(leetcode 206.Reverse Linked List)esay 题目描述:已知链表头节点指针head,将链表逆序. 思路:从链表的头节点依 ...

  6. golang中的栈(LeetCode刷题)

    栈的模拟(LeetCode刷题用法) func main() {stack := make([]string, 0)stack = append(stack, "1" )stack ...

  7. C#LeetCode刷题-程序员面试金典

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#LeetCode刷题-程序员面试金典 | .Net中文网. C#LEETCODE刷题概述 概述 所有LeetCode程序员面试金典 ...

  8. C#LeetCode刷题-剑指Offer

    本文由 比特飞 原创发布,欢迎大家踊跃转载. 转载请注明本文地址:C#LeetCode刷题-剑指Offer | .Net中文网. C#LEETCODE刷题概述 概述 所有LeetCode剑指Offer ...

  9. C#LeetCode刷题-设计

    设计篇 # 题名 刷题 通过率 难度 146 LRU缓存机制 33.1% 困难 155 最小栈 C#LeetCode刷题之#155-最小栈(Min Stack) 44.9% 简单 173 二叉搜索树迭 ...

最新文章

  1. MySQL基础篇:单行函数
  2. C#线程系列讲座(1):BeginInvoke和EndInvoke方法
  3. 计算机游戏系统分析,计算机游戏引擎fly3D系统的实现方式及应用技巧
  4. Ubuntu断电重启后黑屏左上角光标闪烁,分辨率低解决办法
  5. std::tostring_枚举:如何正确使用name()和toString()方法
  6. Exynos4412 所用外存 —— eMMC
  7. RabbitMQ入门学习系列(二),单生产者消费者
  8. python向量化编程技巧_Python学习(六)向量化
  9. Netty工作笔记0044---scheduledTaskQueue
  10. Spring的xml文件配置方式实现AOP
  11. 记个SwitchButton笔记
  12. lvm硬盘管理及LVM扩容
  13. win11笔记本没有网络图标问题的解决历程
  14. 信息系统项目管理师学习笔记16-项目变更管理
  15. 超市会员管理系统 code
  16. 解决Win10更新后兼容性助手提示VMware虚拟机无法在Windows上运行的问题
  17. RESTful API设计简介
  18. 【​观察】六脉神剑第二式-读写分离之双箭齐发
  19. 春联大全·七字联(1)
  20. 目标函数和损失函数的区别

热门文章

  1. 【Android智能定位手表开发】- 文章目录
  2. Blender - Aircraft 飞机模型建模、渲染
  3. C++ 类与对象及重载、内联、引用等知识点【练习题】(含OJ题、选择题等),也包括一些需要注意的知识点
  4. 5种主要的软件架构模式
  5. qpython 3h怎么使用_气体检测仪怎么选
  6. laravel middleware
  7. 三维激光扫描仪VZ6000软件简易操作流程
  8. 2022年化工自动化控制仪表理论题库及答案
  9. “华为大法”对车企是“加持”还是“拖累”?
  10. 云原生社区 大佬博客