对 leetCode 一个算法的分析学习,支持对单链表内指定区间的反转实现。
206. 反转链表
92. 反转链表 II;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
/**
* 对leetCode一个算法的分析学习
* 题目:单链表的反转
*
* @author hudk
* @date 2020/5/27 20:20
*/
public class Solution {
/**
* 单链表结点
*/
public static class ListNode {
int val;
public ListNode next;
public ListNode(int x) {
val = x;
}
@Override
public String toString() {
return String.valueOf(val);
}
}
/**
* leetCode 题目:反转单链表1
*
* 示例:
* 输入: 1->2->3->4->5->NULL
* 输出: 5->4->3->2->1->NULL
* 进阶:
* 你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/reverse-linked-list
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
* @param head
* @return
*/
/**
* 方法一
* 这个方法是本人解答方案,相对使用了比较多的空间
* 空间复杂度:O(n)
* 时间复杂度:O(n)
*
* @param head
* @return
*/
public static ListNode myReverseList(ListNode head) {
//当链表长度为零时,直接返回null
if (head == null) {
return null;
}
//引用指向头结点
ListNode h = head;
//遍历整个链表,统计链表长度 i
int i = 1;
while (h.next != null) {
i++;
h = h.next;
}
//创建一个和链表长度一样的数组,并将链表的元素按照原顺序逐个放入数组中
ListNode[] ln = new ListNode[i];
for (int j = 0; j < i; j++) {
ln[j] = head;
head = head.next;
}
//再从数组的尾部开始遍历,逐个该表链表元素的next指针指向前一个元素。
for (int x = i - 1; x > 0; x--) {
ln[x].next = ln[x - 1];
}
//将原来的头结点(现在转置后的尾结点next引用置空)
ln[0].next = null;
//返回转置后新的头结点
return ln[i - 1];
}
/**
* 方法二
* 这个方法是leetCode上的算法大神解答的方案
* 利用递归的巧妙与优雅实现
*
* 作者:labuladong
* 链接:https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/bu-bu-chai-jie-ru-he-di-gui-di-fan-zhuan-lian-biao/
* 来源:力扣(LeetCode)
* 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*
* @param head
* @return
*/
public static ListNode revers(ListNode head) {
if (head.next == null) {
return head;
}
ListNode last = revers(head.next);
head.next.next = head;
head.next = null;
return last;
}
/**
* 方法三
* 这个方法是官方解答的方案
* 利用了迭代的思想,同样简洁且高效
* 空间复杂度:O(1)
* 时间复杂度:O(n)
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/reverse-linked-list
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*
* @param head
* @return
*/
public static ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
ListNode nextTemp = null;
while (curr != null) {
nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
/**
* leetCode 题目:反转单链表2
* 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
*
* 说明:
* 1 ≤ m ≤ n ≤ 链表长度。
*
* 示例:
* 输入: 1->2->3->4->5->NULL, m = 2, n = 4
* 输出: 1->4->3->2->5->NULL
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
/**
* 方法一 begin*******************************************************************
* <p>
* 递归实现单链表的指定区间反转
* 这个算法的实现,淋漓尽致的体现了递归的优雅与简洁。
* 适用于链表长度比较短的场景,或对性能要求不高的场景
* <p>
* 作者:labuladong
* 链接:https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/bu-bu-chai-jie-ru-he-di-gui-di-fan-zhuan-lian-biao/
* 来源:力扣(LeetCode)
* 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*
* @param head
* @param m
* @param n
* @return
*/
public static ListNode reverseBetween(ListNode head, int m, int n) {
if(head == null){
return null;
}
// base case
if (m == 1) {
//单链表的前n个结点反转
return reverseN(head, n);
}
// 前进到反转的起点触发 base case
head.next = reverseBetween(head.next, m - 1, n - 1);
return head;
}
/**
* 递归实现单链表的前n个结点反转
*/
static ListNode successor = null; // 后驱节点
// 反转以 head 为起点的 n 个节点,返回新的头结点
public static ListNode reverseN(ListNode head, int n) {
if(head == null){
return null;
}
if (n == 1) {
// 记录第 n + 1 个节点
successor = head.next;
return head;
}
// 以 head.next 为起点,需要反转前 n - 1 个节点
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
// 让反转之后的 head 节点和后面的节点连起来
head.next = successor;
return last;
}
/**方法一end*******************************************************************/
/**
* 方法二
* 这是本人的解答方案,使用了迭代的思路,并将各种情况逐一考虑,分别处理。
* 代码量比较多,但自我感觉逻辑看起来更加清晰一些。
*
* @param head 链表头结点
* @param m 翻转区间开始位置
* @param n 翻转区间结束位置
* @return
*/
public static ListNode myReverseBetween(ListNode head, int m, int n) {
if(m <= 0){
m = 1;
}
int size = size(head);
if(n > size){
n = size;
}
//如果传入为空,直接返回空
if (head == null) {
return null;
}
//如果m = n,说明转置后等于没转置,所以不做处理直接返回原链表
if (m == n) {
return head;
}
//1、当m等于1时,倒序之后,第一个结点一定会和第n+1个结点相连
//2、并且第n个结点,会成为新链表的头结点
if (m == 1) {
ListNode perv = null;
ListNode crr = head;
ListNode nodeOne = null;
int i = 1;
while (crr != null) {
ListNode next = crr.next;
if (i == 1) {
//暂时记住第一个结点,后面它将会与第n+1个结点相连
nodeOne = crr;
nodeOne.next = null;
//为迭代做准备,从第2个结点开始迭代地做“翻转”动作,故将第1个结点当做下次循环时的“前置结点”
perv = crr;
}
//从第二个结点开始,一直到第n个结点,逐一"翻转"他们的next
if (i > m && i < n) {
crr.next = perv;
perv = crr;
}
//第n个结点
if (i == n) {
//第一个结点的的next引用指向了第n+1个结点
nodeOne.next = crr.next;
//翻转第n个结点的next
crr.next = perv;
//第n个结点,会成为新链表的头结点
head = crr;
//由于后面得结点不需要做处理了,故跳出循环即可
break;
}
//迭代
crr = next;
i++;
}
}
//1、如果m>1,第m-1个结点会与第n个结点相连,第m个结点会与第n+1个结点相连
//2、然后,第m+1个到第n个结点的next依次“翻转”
//3、头结点不变
if (m > 1) {
ListNode perv = null;
ListNode crr = head;
ListNode nodeMp = null;//第m个结点的前一个结点
ListNode nodeM = null;//第m个结点
int i = 1;
while (crr != null) {
ListNode next = crr.next;
if (i == m - 1) {
//暂时记住第m-1个结点,后面它将会与第n个结点相连
nodeMp = crr;
nodeMp.next = null;
}
if (i == m) {
//暂时记住第m个结点,后面它将会与第n+1个结点相连
nodeM = crr;
nodeM.next = null;
//为迭代做准备,从m+1个结点开始迭代地做“翻转”动作,故将第m个结点当做下次循环时的“前置结点”
perv = crr;
}
//第m+1个到第n个结点的next依次“翻转”
if (i > m && i < n) {
crr.next = perv;
perv = crr;
}
if (i == n) {
//第m个结点的next引用指向了第n+1个结点
nodeM.next = crr.next;
//翻转第n个结点的next
crr.next = perv;
//第m-1个结点的next引用指向了第n个结点
nodeMp.next = crr;
//由于后面得结点不需要做处理了,故跳出循环即可
break;
}
//迭代
crr = next;
i++;
}
}
return head;
}
/**方法二end*******************************************************************/
/**
* 测试用例
* @param args
*/
public static void main(String[] args) {
//生成一个长度为10的单链表
ListNode head = createRandomSingleLinkList(10);
//打印初始链表
printLinkList(head);
//反转测试
ListNode head1 = myReverseList(head);
printLinkList(head1);
//迭代方式反转测试
ListNode head2 = reverseList(head1);
printLinkList(head2);
//递归方式反转测试
ListNode head3 = revers(head2);
printLinkList(head3);
//迭代方式反转指定区间测试
ListNode head4 = myReverseBetween(head3,2,8);
printLinkList(head4);
//递归方式反转指定区间测试
ListNode head5 = reverseBetween(head4,4,5);
printLinkList(head5);
}
/**
* 生成一个指定长度的链表
* @param size
* @return
*/
public static ListNode createRandomSingleLinkList(int size){
if(size == 0){
return null;
}
ListNode head = new ListNode(1);
ListNode crr= head;
for(int i=1; i<size; i++){
ListNode node = new ListNode(i+1);
crr.next = node;
crr = node;
}
return head;
}
/**
* 生成 0 - 100 范围内的随机正式
* @return
*/
public static int randomInt(){
return (int)Math.floor(Math.random()*100);
}
/**
* 打印链表
* @param head
*/
public static void printLinkList(ListNode head){
List<ListNode> nodes = new ArrayList<>();
if(head == null){
System.out.println(nodes);
return;
}
nodes.add(head);
while (head.next != null){
nodes.add(head.next);
head = head.next;
}
System.out.println(nodes);
}
/**
* 计算单链表长度
* @param head
* @return
*/
public static int size(ListNode head){
if(head == null){
return 0;
}
int i = 1;
while (head.next != null){
head = head.next;
i++;
}
return i;
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于