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

LeetCode 面试经典 150_链表_K 个一组翻转链表(61_25_C++_困难)(四指针法;头插法)

LeetCode 面试经典 150_链表_K 个一组翻转链表(61_25_C++_困难)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 思路一(四指针法):
        • 思路二(头插法):
      • 代码实现
        • 代码实现(思路一(四指针法)):
        • 代码实现(思路二(头插法)):
        • 以思路二进行代码调试

题目描述:

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

输入输出样例:

示例 1:
请添加图片描述

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:
请添加图片描述

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

提示:
链表中的节点数目为 n
1 <= k <= n <= 5000
0 <= Node.val <= 1000

题解:

解题思路:

思路一(四指针法):

1、通过题目分析,在每次翻转前需要进行个数的判断,若满足再将k个结点翻转,将翻转后的答案进行连接。
我们发现我们在进行翻转的时候需要保存k个结点的首和尾(kHead和kTail),并且还需要保存kHead之前的一个结点(ansTail)和kTail之后的一个结点(next_kHead),方便将翻转后的链表进行连接和剩余结点的处理,因此我们需要四个指针(kHead、kTail、ansTail、next_kHead)。

具体实现思路请看下图:
请添加图片描述
2、复杂度分析:
① 时间复杂度:O(n),n 代表链表中元素的个数,只遍历了一遍列表。
② 空间复杂度:O(1),使用常数个内存空间(只对源节点的next指向进行更改)。

思路二(头插法):

1、通过题目分析,在每次翻转前需要进行个数的判断,若满足再将k个结点翻转,将翻转后的答案进行连接。
我们在翻转时可将要 翻转的 k 结点采用头插法进行翻转。在每次进行翻转后更新下一次插入的头结点即可。

2、复杂度分析:
① 时间复杂度:O(n),n 代表链表中元素的个数,只遍历了一遍列表。
② 空间复杂度:O(1),使用常数个内存空间(只对源节点的next指向进行更改)。

代码实现

代码实现(思路一(四指针法)):
//判断剩余长度是否>=k,不够则返回nullptr,够则返回k个长度链表的尾结点 
ListNode *judgeLen_k(ListNode *kHead,int k){while(k-1){if(kHead==nullptr){return nullptr;}kHead=kHead->next;--k;}return kHead; 
} //翻转固定个数的链表,返回翻转后的头结点 
ListNode *reverseList_k(ListNode *kHead,int k){ListNode *pre=nullptr,*r=kHead,*tmp=kHead;while(k){r=r->next;tmp->next=pre;pre=tmp;tmp=r;--k;}return pre;
} //K 个一组翻转链表
ListNode* reverseKGroup(ListNode* head, int k) {ListNode *dummyHead=new ListNode(0); //存储答案的尾结点 ListNode *ansTail=dummyHead;//交换前,k个结点的头ListNode *kHead=head;//交换前,k个结点的末尾,不够k个则为nullptr ListNode *kTail=judgeLen_k(kHead,k);//保存下一个区间的头ListNode *next_kHead=nullptr;while(kTail!=nullptr){//保存下一个区间的头next_kHead=kTail->next;//翻转k个结点//可以和下行代码合并 ansTail->next=reverseList_k(kHead,k)reverseList_k(kHead,k);//将k个结点翻转后的链表,连接到答案列表 ansTail->next=kTail;kHead->next=next_kHead;  //可最后进行一次连接//更新答案链表的尾结点ansTail=kHead;//更新交换前,k个结点的头 kHead=next_kHead; //判断之后的结点是否够k个 kTail=judgeLen_k(next_kHead,k);} ListNode *ansHead=dummyHead->next;delete dummyHead;return ansHead;         
} 
代码实现(思路二(头插法)):
class Solution2 {
private:// 判断是否满足 k 个,返回下一个 k 个元素的开始位置ListNode *judge_K(ListNode *curNode, int k) {// 遍历 k-1 次,检查是否能找到 k 个节点while(k-1) {// 如果当前节点为空,则返回 nullptr,表示剩余节点不足 k 个if(curNode == nullptr) {return nullptr;}// 否则继续移动到下一个节点curNode = curNode->next;k--;  // 剩余的 k 值减 1}// 返回当前节点,表示已经找到 k 个节点return curNode;}public:ListNode* reverseKGroup(ListNode* head, int k) {// 如果链表中节点数量小于 k,直接返回原链表,不进行反转if(judge_K(head, k) == nullptr) {return head;}// 创建一个哑节点,方便处理链表的头节点ListNode *dummyHead = new ListNode(-1);// dummyHead 指向链表的头部ListNode *curNode = head;ListNode *curHead = dummyHead;  // curHead 是当前操作的节点的前一个节点ListNode *nextNode;// 开始反转链表的每个 k 个节点while(judge_K(curNode, k) != nullptr) {// k_tail 是当前反转部分的尾节点ListNode *k_tail = curNode;// 反转 k 个节点for(int i = 0; i < k; i++) {// 保存当前节点的下一个节点nextNode = curNode->next;// 将当前节点插入到 curHead 后面curNode->next = curHead->next;curHead->next = curNode;// 当前节点指向下一个节点,继续反转curNode = nextNode;}// 更新 curHead 为当前反转部分的尾节点curHead = k_tail;}// 最后更新 curHead 的 next 指向剩下部分的节点curHead->next = nextNode;// 返回反转后的链表头部,跳过哑节点curHead = dummyHead->next;// 删除哑节点,释放内存delete dummyHead;return curHead;}
};
以思路二进行代码调试
#include<iostream>
#include<vector>
using namespace std;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){}
}; //尾插法创建单链表
ListNode *createList(vector<int> arr){ListNode *head=nullptr,*tail=nullptr;for(const auto &val:arr){if(head==nullptr){head=tail=new ListNode(val);}else{tail->next=new ListNode(val);tail=tail->next;}}return head;
} class Solution2 {
private:// 判断是否满足 k 个,返回下一个 k 个元素的开始位置ListNode *judge_K(ListNode *curNode, int k) {// 遍历 k-1 次,检查是否能找到 k 个节点while(k-1) {// 如果当前节点为空,则返回 nullptr,表示剩余节点不足 k 个if(curNode == nullptr) {return nullptr;}// 否则继续移动到下一个节点curNode = curNode->next;k--;  // 剩余的 k 值减 1}// 返回当前节点,表示已经找到 k 个节点return curNode;}public:ListNode* reverseKGroup(ListNode* head, int k) {// 如果链表中节点数量小于 k,直接返回原链表,不进行反转if(judge_K(head, k) == nullptr) {return head;}// 创建一个哑节点,方便处理链表的头节点ListNode *dummyHead = new ListNode(-1);// dummyHead 指向链表的头部ListNode *curNode = head;ListNode *curHead = dummyHead;  // curHead 是当前操作的节点的前一个节点ListNode *nextNode;// 开始反转链表的每个 k 个节点while(judge_K(curNode, k) != nullptr) {// k_tail 是当前反转部分的尾节点ListNode *k_tail = curNode;// 反转 k 个节点for(int i = 0; i < k; i++) {// 保存当前节点的下一个节点nextNode = curNode->next;// 将当前节点插入到 curHead 后面curNode->next = curHead->next;curHead->next = curNode;// 当前节点指向下一个节点,继续反转curNode = nextNode;}// 更新 curHead 为当前反转部分的尾节点curHead = k_tail;}// 最后更新 curHead 的 next 指向剩下部分的节点curHead->next = nextNode;// 返回反转后的链表头部,跳过哑节点curHead = dummyHead->next;// 删除哑节点,释放内存delete dummyHead;return curHead;}
};int main(){vector<int> a={1,2,3,4,5};int k=2;Solution2 s;ListNode *head=createList(a);ListNode *test=s.reverseKGroup(head,k); while(test!=nullptr){cout<<test->val<<"->";test=test->next;}cout<<"null"; return 0;
}

LeetCode 面试经典 150_链表_K 个一组翻转链表(61_25)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

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

相关文章:

  • 做一个简单网站多少钱建设银行网站买手机
  • Ubuntu 22.04上安装Vivado2023.1(离线方式)
  • 使用 OpenAI SDK 调用阿里云 Qwen 模型:从基础到提示词工程实战
  • HTTPS 高频考点
  • 安徽网站建设 网新线上推广100种方式
  • 东莞专业做网站优化用vs2010做网站登入
  • 若依框架学习第二天:功能改造与问题攻坚实战 (2)
  • 为什么要学深度学习?——从“传统编程”到“数据驱动”的思维跃迁(附AI落地案例)
  • 简述网站建设优坏的评价标准wordpress 手机访问不了
  • 浙江网站改版设计公司网站策划书结尾
  • 网站建设 招标公告域名注册的网站
  • 【OC】UIKit常用组件适配iOS 26
  • 自适应微网站开发舟山网站设计
  • 南京高端网站开发朝城做网站公司
  • 26.UE-游戏逆向-绘制骨骼编号
  • 可做产品预售的网站九江有限公司
  • 设计模式-状态模式(State)
  • 强化学习推荐系统:不同的探索策略——贪心探索策略(4.1)
  • Git学习-1
  • 如何运营一个行业网站dede建设网站
  • 找公司网站建设3网站有哪些后台
  • 15.如何利用ArcGIS提取出线要素数据所经过的格网
  • 数据结构<C++>——数组
  • vidhub v1.3.13 |聚合主流网盘,自动刮削整理影视资源,有网盘会员的可入,或者使用不限速网盘
  • 专业网站制作地址杭州网站怎么制作
  • 免费素材网站排行榜征求网站建设
  • 汉口网站制作公司营销网站模板下载
  • 将有序数组转换为二叉搜索树解题思路
  • c语言实现栈【由浅入深-数据结构】
  • 教做家常菜的视频网站wordpress 搭建个人博客