算法修炼之路——【链表】Leetcode24 两两交换链表中的节点
题目描述
给定一单链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是简单的改变节点内部的值,而是需要实际的进行节点交换。
示例:
输入:head = [1, 2, 3, 4]
输出:head = [2, 1, 4, 3]
解题思路
我们通过示例可以简单了解到,需要两两进行位置互换,但是互换的动作需要涉及到前置节点与后置节点。这里为方便理解,我们先单独给出四个节点:
图1
见图1所示,我们在T1时刻交换[1, 2]两个节点,T2时刻交换[3, 4]。
这里易看出,此问题可以解为:
- 两两交换
- 迭代两两交换
对于问题1:
我们将总体链表的两两交换位置分别为若干相同的问题1,解法则有:
/*
head = [1, 2, 3, 4]
first, focus [1, 2]
*/
ListNode currHead; // and currHead.next = left leftP.next = rightP.next; // 1->2->3 changed to 1->3
right.next = leftP; // 1->3 changed to 2->1->3
currHead.next = rightP; //upgrate head of piece of this pair
这里涉及到的额外节点信息是两个节点组的前置节点,即currHead;当我们交换[3, 4]时则有:
/*
head = [2, 1, 3, 4]
secod, focus [3, 4] leftP point to 3, rightP 4.
*/
// currHead.next = leftP, here, currHead = ListNode(1) // exchange node 3 and 4
leftP.next = rightP.next;
rightP.next = leftP;
currHead.next = rightP;
对于问题2:
截止到这里,我们已经探索到了问题1的解法,接下来需要做的就是将填补问题1间的缝隙,即将他们融合为一个整体,这里我们容易理解,在交换[3, 4]的时候,需要用到交换[1,2]后的靠后节点(这里为ListNode(1)),则可以理解我们在两两交换时,统一的需要用到currHead, 即两个节点[a, b]中 靠前节点a的前置节点,并需要在[a, b]交换位置后为下一对即将交换的节点更新它们所需的currHead。则我们可以将前两部分代码融合为:
ListNode leftP = head;
ListNode rightP = head.next; ListNode currHead = dummyHead; //for head node // iteration
leftP.next = rightP.next;
rightP.next = leftP;
currHead.next = rightP; //update pos of currHead
currHead = leftP;
步骤罗列
我们已经对问题的解答有了核心的理解,这里将步骤进行进一步梳理:
- 初始化两个指针,一左一右;且为统一规则,采取哨兵机制;
- 迭代:节点交换,并更新下一对节点的靠前前置节点;
- 迭代终止条件为两指针均不为空;终止后返回哨兵节点的下一节点。
解题代码
public static ListNode solutionWithTwoP(ListNode head) {
if (head == null || head.next == null) {
return head;
} //1. init pointers and dummyHead
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode leftP = head;
ListNode rightP = head.next; ListNode currHead = dummyHead; //2. iteration
while (leftP != null && rightP != null) {
// exchange
leftP.next = rightP.next;
rightP.next = leftP;
currHead.next = rightP; //update pos of currHead
currHead = leftP; //move forward
leftP = leftP.next;
rightP = leftP == null? null : leftP.next; //attention here
} return dummyHead.next;
}
复杂度分析
时间复杂度:我们对数据仅进行了一次遍历,所以时间复杂度为O(N);
空间复杂度:我们没有借助额外的容器,所以空间复杂度为常量级O(1)。
GitHub源码
完整可运行文件请访问GitHub。
算法修炼之路——【链表】Leetcode24 两两交换链表中的节点的更多相关文章
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- [Swift]LeetCode24. 两两交换链表中的节点 | Swap Nodes in Pairs
Given a linked list, swap every two adjacent nodes and return its head. Example: Given 1->2->3 ...
- LeetCode初级算法--链表02:合并两个有序链表
LeetCode初级算法--链表02:合并两个有序链表 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...
- python经典面试算法题1.3:如何计算两个单链表所代表的数之和
本题目摘自<Python程序员面试算法宝典>,我会每天做一道这本书上的题目,并分享出来,统一放在我博客内,收集在一个分类中. 1.2 如何实现链表的逆序 [华为笔试题] 难度系数:⭐⭐⭐ ...
- 算法练习之合并两个有序链表, 删除排序数组中的重复项,移除元素,实现strStr(),搜索插入位置,无重复字符的最长子串
最近在学习java,但是对于数据操作那部分还是不熟悉 因此决定找几个简单的算法写,用php和java分别实现 1.合并两个有序链表 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两 ...
- Leetcode24.Swap Nodes in Pairs两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 示例: 给定 1->2->3->4, 你应该返回 2->1->4->3. 说明: 你的算法只能使用常数的 ...
- LeetCode24 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 示例: 给定 1->2->3->4, 你应该返回 2->1->4->3. 说明: 你的算法只能使用常数的 ...
- Leetcode算法系列(链表)之两数相加
Leetcode算法系列(链表)之两数相加 难度:中等给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果,我们将 ...
- [PHP] 算法-合并两个有序链表为一个有序链表的PHP实现
合并两个有序的链表为一个有序的链表: 类似归并排序中合并两个数组的部分 1.遍历链表1和链表2,比较链表1和2中的元素大小 2.如果链表1结点大于链表2的结点,该结点放入第三方链表 3.链表1往下走一 ...
随机推荐
- Zookeeper的使用场景和集群配置
Zookeeper的介绍 ZK在分布式系统的应用 Zookeeper搭建 集群角色介绍 ZK的常用命令 一.Zookeeper的介绍 官方:ZooKeeper是一个分布式的,开放源码的分布式应用程序协 ...
- 《前端之路》--- 重温 Egg.js
目录 <前端之路>--- 重温 Egg.js 一.基础功能 > 日志系统包含了 四大层面的 日志对象, 分别是 App Logger.App CoreLogger.Context L ...
- 一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)
偏移量(offset dimension) 偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小有其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距). 以下4个属性可以获取 ...
- JavaScript实现栈结构(Stack)
JavaScript实现栈结构(Stack) 一.前言 1.1.什么是数据结构? 数据结构就是在计算机中,存储和组织数据的方式. 例如:图书管理,怎样摆放图书才能既能放很多书,也方便取? 主要需要考虑 ...
- Java中如何更优雅的处理空值
经常看到项目中存在到处空值判断的情况,这些判断,会让人觉得摸不着头绪,它的出现很有可能和当前的业务逻辑并没有关系.但它会让你很头疼.有时候,更可怕的是系统因为这些空值的情况,会抛出空指针异常,导致业务 ...
- 零基础JavaScript编码(一)
任务目的 JavaScript初体验 初步明白JavaScript的简单基本语法,如变量.函数 初步了解JavaScript的事件是什么 初步了解JavaScript中的DOM是什么 任务描述 参考以 ...
- Django开发框架知识点
一.什么是web服务器(了解) 当我们在浏览器输入URL后,浏览器会先请求DNS服务器,获得请求站点的 IP 地址.然后发送一个HTTP Request(请求)给拥有该 IP 的主机,接着就会接收到服 ...
- Markdown语法说明及常用软件推荐(附链接)
Markdown语法同样支持HTML标签 以下所有字符均为英文字符 标题 标题级别由#决定,一个为一级 样例 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ...
- 将root用户权限赋予普通用户
将root用户权限赋予普通用户 普通用户想要拥有root用户的权限,必须修改/etc/sudoers文件 ,还必须使用visudo命令修改.一是因为这个命令能防止多个用户同时修改这个文件,二是能进行有 ...
- go学习第四天、条件和循环
循环 Go语言仅支持循环关键字 for for i := 0; i<5; i++ 示例 while 条件循环 while(n<5) n := 0 for n < 5 { n++ fm ...