一、题目描述

找出数组中重复的数字

> 在一个长度为 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,你看了就知道了的更多相关文章

  1. LeetCode刷题总结-链表

    LeetCode刷题总结-链表 一.链表     链表分为单向链表.单向循环链表和双向链表,一下以单向链表为例实现单向链表的节点实现和单链表的基本操作. 单向链表 单向链表也叫单链表,是链表中最简单的 ...

  2. leetcode刷题记录——链表

    使用java实现链表 单向链表 双向链表 单向循环链表 双向循环链表 题目记录 160.相交链表 例如以下示例中 A 和 B 两个链表相交于 c1: A: a1 → a2 c1 → c2 → c3 B ...

  3. Leetcode刷题之链表增加头结点的前缀节点

    链表之增加头结点的前缀节点 在许多链表题中往往需要在题目给的头结点之前增加一个前缀节点 通常在删除链表和头结点需要交换时需要用到这一操作 因为增加这个节点就避免了对删除头结点这种特殊情况的特殊处理 而 ...

  4. leetCode刷题(使用链表做加法)

    Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = ...

  5. leetcode刷题七<整数反转>

    给出一个 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 : 输入: 输出: 示例 : 输入: - 输出: - 示例 : 输入: 输出: 假设我们的环境只能存储得下 32 位的有符号整 ...

  6. LeetCode刷题笔记-递归-反转二叉树

    题目描述: 翻转一棵二叉树. 解题思路: 1.对于二叉树,立马递归 2.先处理 根节点,不需改动 3.处根的左子树和右子树需要交换位置 4.递归处理左子树和右子树.步骤见1-3步 Java代码实现: ...

  7. Leetcode刷题——007.整数反转

    上代码: #include <cmath> class Solution { public: int reverse(int x) { ; long long tx=llabs(x); ) ...

  8. Leetcode刷题之链表中箭头转移和内容转移

    链表中箭头转移和内容转移 链表中特别注意xxx.next=xxx 和xxx=xxx的区别 xxx.next=xxx表示将指针(箭头)转移 xxx=xxx表示将内容转移 Leetcode206翻转链表 ...

  9. LeetCode刷题专栏第一篇--思维导图&时间安排

    昨天是元宵节,过完元宵节相当于这个年正式过完了.不知道大家有没有投入继续投入紧张的学习工作中.年前我想开一个Leetcode刷题专栏,于是发了一个投票想了解大家的需求征集意见.投票于2019年2月1日 ...

随机推荐

  1. IDEA中通过正则表达式批量替换空白行

    快捷键Ctrl+r 填入^\s*\n,勾选Regex,Replace all

  2. Nacos概述及安装

    Nacos是什么? 在Spring Cloud中我们使用eureka.consul等做为服务注册中心,使用Spring Cloud Config做为配置中心.而Spring Cloud中,也可以使用n ...

  3. Echarts4.x雷达图如何展示一维数据?

    最近做的项目其中一个功能是画雷达图,鼠标滑过雷达图的拐点,展示该维相关数据,并且需要显示雷达图的刻度. 但是我发现单纯的雷达图似乎没办法展示一维数据. 我总结了一下,关于画雷达图,我遇到的难点有三个: ...

  4. Java中的equals()和hashCode() - 超详细篇

    前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的equals()和hashCode() - 详细篇>,希望对大家有帮助,谢谢 文章纯属原创,个人总结难免有差错,如果有,麻烦在评论 ...

  5. 可视化运行Python的神器Jupyter Notebook

    目录 简介 Jupyter Notebook 启动notebook server notebook document 的结构 code cells markdown cells raw cells 以 ...

  6. 201871030110-何飞 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    201871030110-何飞 实验三 结对项目-<D{0-1}KP 实例数据集算法实验平台>项目报告 项目 内容 课程班级博客链接 班级博客 这个作业要求链接 作业要求 我的课程学习目标 ...

  7. Kafka和Stream架构的使用

    Kafka的单节点运行 启动服务 Kafka 使用 ZooKeeper 如果你还没有 ZooKeeper 服务器,你需要先启动一个 ZooKeeper 服务器. 您可以通过与 kafka 打包在一起的 ...

  8. Spring Boot 整合Junit和redis

    14. Spring Boot整合-Junit 目标:在Spring Boot项目中使用Junit进行单元测试UserService的方法 分析: 添加启动器依赖spring-boot-starter ...

  9. Spring(六)SpringMVC的数据响应

    SpringMVC的请求和响应 SpringMVC的数据响应 01-SpringMVC的数据响应-数据响应方式(理解) 1)    页面跳转 直接返回字符串 通过ModelAndView对象返回 2) ...

  10. mysql 遇到的问题

    1) 客户端(Navicat)远程登录操作再遇问题1142-create command denied to user×××的解决GRANT SELECT,INSERT,UPDATE,DELETE,C ...