说了你可能不信leetcode刷题局部链表反转D92存在bug,你看了就知道了
一、题目描述
> 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
二、思路分析
- 之前我们已经分析过了通过递归的方式解决此问题 。 递归将问题逐层细化已达到整体问题的解决
- 而今天我们将从另外一个角度去分析次问题--迭代。所谓迭代就是通过一次循环遍历解决反转问题。而递归不同的是他将是从左至右的方式解决问题
- 在范围内的链表节点先将他指向一个默认前置节点
preNode
。然后将当前节点指针后移在重复next指针指向preNode
。就可以解决问题
- 这样我们仅仅借助于一个
preNode
就可以完成节点2的反转。不过这里节点已的next指针还是指向节点2的。这一步我们会在最后处理首尾问题。
- 最终将会是如下指向问题,对于节点3、节点4也是同样的操作。
- 当指定范围内数据全部扫描完成之后内部指针结构如上。图中1、2、4、5被特殊标注出来因为这四个分别是外边界和内边界的节点。我们需要特殊将这些边界进行连接 。 1指向4 、 2指向5就完成了最终的反转
- 相信通过上面的动画模拟,你应该可以轻松的理解迭代处理的方式。但是在我们实际处理中边界我们需要特殊存储处理。下面我们就通过代码层面来实现效果
三、AC 代码
bug
- 按照上面的逻辑,我尝试实现了下
//外边界左侧节点
private static ListNode firstNode ;
//外边界右侧节点
private static ListNode lastNode ;
public ListNode reverseBetween(ListNode head, int left, int right) {
//preNode 作为接受反转节点
ListNode preNode=null;
//用于指向当前操作节点 , 也是内部右侧节点
ListNode currentNode = head;
//存储下一节点,方便赋值
ListNode nextNode=null;
//内部左侧节点
ListNode leftNode=head;
int index =1 ;
while (currentNode != null) {
nextNode = currentNode.next;
if (index == left-1) {
//捕获外部边界节点
firstNode = currentNode;
}
if (index >= left && index <= right) {
//指针修复
currentNode.next = preNode;
preNode = currentNode;
}
currentNode = nextNode;
if (index == right) {
//捕获外部边界节点
lastNode = nextNode;
break;
}
index++;
}
//因为是指定范围但是有可能是全部链表这时候外部边界都是null
if (firstNode != null) {
leftNode = firstNode.next;
firstNode.next = preNode;
}
if (lastNode != null) {
leftNode.next = lastNode;
return head;
} else {
return preNode;
}
}
- 上面这段代码本地运行是成功的。而且在leetcode官网上执行[3,5] ,left=1 , right=1 单独执行输出结果也是[3,5] 时没有问题的。但是当提交执行全部测试用例的时候确保在【3,5】 1 ,1这个测试用例无法通过。我认为是leetcode官网执行测试代码的一个bug
添加头结点
- 在我们上面代码中虽然leetcode没有通过但是那是leetcode的bug导致的,在里面我们不难发现有很多if else操作。这样的代码很难看至少在代码洁癖面前是不能容忍的。
- 为什么会有那么的判断,主要是因为我们的外部边界和内部边界可能会出现重合。所以我们在原有的链表中在头部再添加一个默认节点。这样做是为了避免外边界空的情况。
- 同样是left=2,right=4的情况,我们从红色头结点开始获取到left=2之前的节点和right=4的节点 。 即node1是我们之前说的firstNode。node5是lastNode。
- leftNode=node2;rightNode=node4 。然后我们在将内部链表进行反转。反转的方法就是按照我们上面的逻辑借助另外一个空节点作为preNode。
- 因为node1,和node5已经被我们记录下来了。下面我们只需要将内部外部指针进行关联就可以了
firstNode.next = rightNode;
leftNode.next = lastNode;
- 最终将头结点后面部分返回就可以了
private static ListNode firstNode ;
private static ListNode lastNode ;
public ListNode reverseBetween2(ListNode head, int left, int right) {
ListNode visualNode = new ListNode(-1, head);
firstNode = visualNode;
for (int i = 1;i < left; i++) {
firstNode = firstNode.next;
}
ListNode rightNode = firstNode;
for (int i = 0; i < right - left + 1; i++) {
rightNode = rightNode.next;
}
ListNode leftNode = firstNode.next;
lastNode = rightNode.next;
rightNode.next = null;
ListNode wpre = null;
ListNode wcur = leftNode;
while (wcur != null) {
ListNode next = wcur.next;
wcur.next = wpre;
wpre = wcur;
wcur = next;
}
firstNode.next = rightNode;
leftNode.next = lastNode;
return visualNode.next;
}
- 多执行几次看看最终的效果
- 速度依旧是那么快,在内存使用上平均值是65%以上。和我们递归的方式进行对比不难发现。迭代的方式在时间和空间上都是最优的。
四、总结
- 迭代和递归是解决链表常用的两种方式。迭代的优点就是不断的循环下去
- 递归最大的问题就是容易导致死循环,在书写的时候需要特殊注意递归的结束条件
说了你可能不信leetcode刷题局部链表反转D92存在bug,你看了就知道了的更多相关文章
- LeetCode刷题总结-链表
LeetCode刷题总结-链表 一.链表 链表分为单向链表.单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作. 单向链表 单向链表也叫单链表,是链表中最简单的 ...
- leetcode刷题记录——链表
使用java实现链表 单向链表 双向链表 单向循环链表 双向循环链表 题目记录 160.相交链表 例如以下示例中 A 和 B 两个链表相交于 c1: A: a1 → a2 c1 → c2 → c3 B ...
- Leetcode刷题之链表增加头结点的前缀节点
链表之增加头结点的前缀节点 在许多链表题中往往需要在题目给的头结点之前增加一个前缀节点 通常在删除链表和头结点需要交换时需要用到这一操作 因为增加这个节点就避免了对删除头结点这种特殊情况的特殊处理 而 ...
- leetCode刷题(使用链表做加法)
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = ...
- leetcode刷题七<整数反转>
给出一个 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 : 输入: 输出: 示例 : 输入: - 输出: - 示例 : 输入: 输出: 假设我们的环境只能存储得下 32 位的有符号整 ...
- LeetCode刷题笔记-递归-反转二叉树
题目描述: 翻转一棵二叉树. 解题思路: 1.对于二叉树,立马递归 2.先处理 根节点,不需改动 3.处根的左子树和右子树需要交换位置 4.递归处理左子树和右子树.步骤见1-3步 Java代码实现: ...
- Leetcode刷题——007.整数反转
上代码: #include <cmath> class Solution { public: int reverse(int x) { ; long long tx=llabs(x); ) ...
- Leetcode刷题之链表中箭头转移和内容转移
链表中箭头转移和内容转移 链表中特别注意xxx.next=xxx 和xxx=xxx的区别 xxx.next=xxx表示将指针(箭头)转移 xxx=xxx表示将内容转移 Leetcode206翻转链表 ...
- LeetCode刷题专栏第一篇--思维导图&时间安排
昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...
随机推荐
- python3 base64
import base64s='hello world'bytes_by_s=s.encode() #将字符串编码-->字节码,b64_encode_bytes=base64.b64encode ...
- 1、MyBatis教程之环境准备和简介
1.环境准备 jdk 8 + MySQL 5.7.19 maven-3.6.1 IDEA 学习前需要掌握: JDBC MySQL Java 基础 Maven Junit Idea快捷键 一键格式化代碼 ...
- 用jar命令打包war远程部署
最近在看jboss的相关漏洞,用jmx-console进行war远程部署的时候碰到一个jsp转war的问题,研究了半天,记录一下免得搞忘了. 一开始网上是说的直接把jsp文件压缩成zip,再把后缀名改 ...
- 通俗地理解面向服务的架构(SOA)以及微服务之间的关系
SOA是一种软件的应用架构方法,它基于面向对象,但又不是面向对象,整体上是面向服务的架构.SOA由精确的服务定义.松散的构件服务组成,以及业务流程调用等多个方面形成的一整套架构方法. 这话是不是听起来 ...
- Apache SkyWalking 告警配置指南
Apache SkyWalking Apache SkyWalking是分布式系统的应用程序性能监视工具(Application Performance Management,APM),专为微服务.云 ...
- 【Python学习笔记】-虚拟环境virtualenv
在开发python应用程序的时候,系统安装的python3只有一个版本:3.4.所有的第三方的包都回被pip安装到python3的site-packages目录下. 如果我们要要同时开发多个应用程序, ...
- 轻松理解 Java 静态代理/动态代理
目录 什么是代理模式 定义 代理模式的主要角色 优点 缺点 静态代理 动态代理 JDK原生动态代理 例子 分析 小结 CGLIB动态代理 例子 分析 final类型 其他方案 尾声 理解Java动态代 ...
- 解决SQLPLUS无法使用上下箭头
1 问题描述 SQLPLUS中使用上下箭头无法获取历史命令,如下图所示: 按上下箭头会显示^[[A/^[[B. 2 解决方案 需要安装rlwrap,可以的话可以用包管理器安装,笔者环境CentOS,这 ...
- Spring 学习笔记(三):Spring Bean
1 Bean配置 Spring可以看做是一个管理Bean的工厂,开发者需要将Bean配置在XML或者Properties配置文件中.实际开发中常使用XML的格式,其中<bean>中的属性或 ...
- Kubernetes删除一直处于Terminating状态的namespace
问题现象: 删除namespace,一直处于Terminating,并且用--force --grace-period=0 也删除不了 develop Terminating 4d9h Error f ...