LeetCode 之反转链表(Reverse Linked List)
时间:2019-02-19
本文章向大家介绍LeetCode 之反转链表(Reverse Linked List),主要包括LeetCode 之反转链表(Reverse Linked List)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
个人博客:DoubleFJ の Blog
前言
反转链表也是常见的面试算法题了。
何为链表?
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
正文
我们先来看下题目描述:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
小时候都玩过玩具蛇吧,那种可以一节一节拼接的。
我们可以想象下现在面前就有这么一条“蛇”,我们试着把它重新组装一遍,我们简单地 边拆边装。
先把它尾巴拆了放一边,再接着拆它的倒数第二块同时把它安装到拆下来的尾巴那,以此下去……
到最后把“蛇头”也给装好,就完事了。
这道题的解题思路也就是这样,边拆边装。
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
贴出两种解决方案代码:
public class ReverseLinkedList {
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
/**
* 递归
*
* @param head
* @return
*/
public ListNode reverseList(ListNode head) {
ListNode reverseList = null;
return helper(head, reverseList);
}
private ListNode helper(ListNode head, ListNode reverseList) {
if (head == null) // 反转结束
return reverseList;
// 节点指针变换
ListNode tempNode = head.next;
head.next = reverseList;
return helper(tempNode, head);
}
/**
* 迭代
*
* @param head
* @return
*/
public ListNode reverseList1(ListNode head) {
ListNode newHead = null;
while (head != null) { // 遍历
ListNode next = head.next;
head.next = newHead;
newHead = head;
head = next;
}
return newHead;
}
}
两者都是先用一个空链表然后再进行一步步得组装。
就是指针指来指去,有点绕,借助实物理解起来会容易很多。
还有一个进阶版本的反转链表 II
,看题:
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
区别就是这里不是反转所有的结点了,只需要反转指定位置之间的结点了,重点就是确认反转的指针位置。然后反转的操作还是与上面一样。
代码如下:
public class ReverseLinkedListII {
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null)
return null;
// 新建一个节点并指向 head
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy;
// pre 为需要反转的前节点
for (int i = 0; i < m - 1; i++)
pre = pre.next;
// 需要反转的节点 双指针
ListNode start = pre.next;
ListNode then = start.next;
// 反转节点
for (int i = 0; i < n - m; i++) {
start.next = then.next;
then.next = pre.next;
pre.next = then;
then = start.next;
}
return dummy.next;
}
}
注释齐全,一目了然。
- Git -- Rebase
- Git -- 分支与合并 (命令行+可视化工具p4merge) Fast Forward 合并禁用 Fast Forward 合并自动合并解决合并的冲突
- 使用Angular CLI进行单元测试和E2E测试
- Git - 使用命令和P4Merge进行diff
- 使用Angular CLI进行Build (构建) 和 Serve
- 使用Angular CLI生成路由
- 使用Angular CLI从蓝本生成代码
- 使用Angular CLI生成 Angular 5项目
- Git基本命令 -- 创建Git项目
- Entity Framework Core 2.0 入门
- 用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传
- 用VSCode开发一个asp.net core 2.0+angular 5项目(4): Angular5全局错误处理
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(3)
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(2)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 搭建简易的物联网服务端和客户端-蓝牙控制(十六)
- java基础|CollectionUtils工具的基本使用
- LeetCode36|二叉树的右视图
- LeetCode35|完全二叉树的节点个数
- LeetCode34|数组中的第k个最大元素
- LeetCode33|寻找重复数
- LeetCode32|前k个高频元素
- LeetCode31|打印从1到最大的n位数
- LeetCode30|翻转单词顺序
- LeetCode28|最后一个单词的长度
- VS2015创建UWP报“vstemplate文件引用的向导类”错误
- 政采云趣味题
- LeetCode40|有序数组中的单一元素
- 搭建简易的物联网服务端和客户端-Cortana控制(十七)
- LeetCode39|找树左下角的值