首页 > 其他分享 >反转链表

反转链表

时间:2024-07-08 23:33:22浏览次数:12  
标签:head curr 反转 next 链表 ListNode 节点

目录

L206 反转链表

题目描述

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例1:

img

示例2:

img

题解

方法一:迭代

假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。

我们考虑遍历链表,将每个节点的next指针改为指向前一个节点。但是链表是单向的,当遍历到某个节点时,我们已经没有前一个节点的引用了,所以需要使用一个prev引用来保存当前节点的前一个节点。

然后做以下迭代步骤:

  • 保存curr的next引用
  • 设置当前节点的next指向prev
  • 将prev指向当前节点
  • 将curr指向next
class Solution {
    public ListNode reverseList(ListNode head) {
		ListNode curr = head;
        ListNode prev = null;
        
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        
        return prev;
    }
}

复杂度分析

时间复杂度:O(N),遍历一次。

空间复杂度:O(1)

方法二:递归

假设链表为:

n1→…→n**k−1→n**kn**k+1→…→n**m→∅

若从节点 n**k+1 到 n**m 已经被反转,而我们正处于 n**k

n1→…→n**k−1→n**kn**k+1←…←n**m

我们希望 n**k+1 的下一个节点指向 n**k

所以,n**k.next.next=n**k

需要注意的是:

  • next指针的修改
  • 反转后的链表的链尾节点的next应该为null
  • 在递归过程中应该要将反转后的链表头节点返回
class Solution {
    public ListNode reverseList(ListNode head) {
		if (head == null || head.next == null) {
            return head;
        }

        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;

        return newHead;
    }
}

复杂度分析

时间复杂度:O(N)

空间复杂度:O(N),因为递归占用栈空间

L92 反转链表 II

题目描述

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

示例1:

img

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例2:

输入:head = [5], left = 1, right = 1
输出:[5]

题解

方法一:一遍扫描

将链表分成三段,反转中间的部分,然后将左中右重新相接。

下载

下载 (1)

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
    	ListNode dummy = new ListNode(0, head);
        
        // 0.整个链表分为左中右三段
        // 1.首先找到左链表的尾部
        ListNode node = dummy;
        for (int i = 1; i < left; i++) {
            node = node.next;
        }
        ListNode leftListTail = node;
        
        // 2.反转中间链表
        node = node.next;
        ListNode midListHead = node;
        ListNode prev = null;
        for (int i = left; i <= right; i++) {
			ListNode next = node.next;
            node.next = prev;
            prev = node;
            node = next;
        }
        
        // 3.重新相接
        leftListTail.next = prev;
        midListHead.next = node;
        
        return dummy.next;
    }
方法二:穿针引线

pre永远指向左链表的最后一个节点。

curr永远指向右链表的第一个节点。

每次迭代:

  • 先将 curr 的下一个节点记录为 next
  • 执行操作 ①:把 curr 的下一个节点指向 next 的下一个节点
  • 执行操作 ②:把 next 的下一个节点指向 pre 的下一个节点
  • 执行操作 ③:把 pre 的下一个节点指向 next

image.png

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 设置 dummyNode 是这一类问题的一般做法
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode pre = dummyNode;
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        ListNode cur = pre.next;
        ListNode next;
        for (int i = 0; i < right - left; i++) {
            next = cur.next;
            cur.next = next.next;
            next.next = pre.next;
            pre.next = next;
        }
        return dummyNode.next;
    }
}

L25 K个一组反转链表

题目描述

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例1

img

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例2

img

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

题解

方法一:模拟

思路就是先向后遍历k个节点,如果剩余元素个数少于k个,则直接返回;如果大于等于k个,就进行翻转。

反转完成之后,需要重新将它接回原链表。

class Solution {
    public ListNode reverseKGroup(ListNode list, int k) {
    	ListNode dummy = new ListNode(0, list);
        ListNode tail = dummy;
        
        while (true) {
            ListNode curr = tail;
            for (int i = 0; i < k; i++) {
                curr = curr.next;
                if (curr == null) {
					return dummy.next;
                }
            }
            
            ListNode nextKGroupHead = curr.next;
            ListNode currKGroupHead = tail.next;
            ListNode prev = nextKGroupHead;
            curr = tail.next;
          	while (curr != nextKGroupHead) {
                ListNode nxt = curr.next;
                curr.next = prev;
                prev = curr;
                curr = nxt;
            }
            tail.next = prev;
            tail = currKGroupHead;
        }
    }
}

标签:head,curr,反转,next,链表,ListNode,节点
From: https://www.cnblogs.com/zhaoqi94/p/18290871

相关文章

  • 【数据结构】—— 单链表(single linked list)
    文章目录1、单链表的定义优点和缺点单链表的构成2、单链表的创建初始化:3、单链表的接口实现打印尾插头插尾删头删查找在指定位置之前插入在指定位置之后插入删除指定位置的节点删除指定位置之后的节点销毁链表4、源代码1、单链表的定义单链表(SinglyLinkedList......
  • 代码随想录算法训联营第四天|LeetCode24. 两两交换链表中的节点 LeetCode19.删除链表
    系列文章目录代码随想录算法训练营第四天:代码随想录|LeetCode24.两两交换链表中的节点LeetCode19.删除链表的倒数第N个节点面试题02.07.链表相交LeetC142.环形链表文章目录系列文章目录前言一、LeetCode24.两两交换链表中的节点1、题目链接2、题解二、LeetCod......
  • 单链表在Python中的实现技巧详解
    概要链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据域和一个指向下一个节点的指针。链表的优点是插入和删除操作非常高效,特别是在需要频繁修改数据结构的情况下。本文将详细介绍如何在Python中创建单链表,并包含相应的示例代码,帮助全面掌握这一基础而重要......
  • 双向链表模拟
    LinkedList底层结构LinkedList底层实现了双向列表和双端队列的特点可以添加任意元素可重复,包括null线程不安全,为实现线程同步底层操作机制LinkedList底层维护了一个双向链表。LinkedList中维护了两个属性first和last分别指向首节点和尾节点每个节点对象(Node对象),里面又维......
  • 【手写数据库内核组件】01 解析树的结构,不同类型的数据结构组多层的链表树,抽象类型统
    不同类型的链表​专栏内容:postgresql使用入门基础手写数据库toadb并发编程个人主页:我的主页管理社区:开源数据库座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.文章目录不同类型的链表概述1.数据类型识别1.1TLV格式介绍1.2结构体分层定义1.3定义......
  • 环形链表II
    给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从0开始)。如果......
  • 【LeetCode 0024】【链表】交换单链表相邻两个节点
    SwapNodesinPairsGivena linkedlist,swapeverytwoadjacentnodesandreturnitshead.Youmustsolvetheproblemwithout modifyingthevaluesinthelist’snodes(i.e.,onlynodesthemselvesmaybechanged.)Example1:**Input:**head=[1,2,3......
  • 【LeetCode 0141】【链表】【双指针之快慢指针】判断给定单链表是否存在环
    LinkedListCycleGivenhead,theheadofalinkedlist,determineifthelinkedlisthasacycleinit.Thereisacycleinalinkedlistifthereissomenodeinthelistthatcanbereachedagainbycontinuouslyfollowingthe next pointer.Internal......
  • 手绘图系列 01 | 链表到底是什么?
    引言程序=数据结构+算法,在编写代码时,选择一个合适的数据结构是成功的一半。不过,问题是:解决同一个问题有很多种方法。对应到组织数据时,有很多数据结构都可以完成指定的工作。关键在于知道使用哪种数据结构是正确且最高效的。很长一段时间对我来说,链表一直是其中一个比......
  • 力扣第7题:整数反转 字符串函数综合运用(C++)
    给你一个32位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。如果反转后整数超过32位的有符号整数的范围 [−231, 231 −1] ,就返回0。假设环境不允许存储64位整数(有符号或无符号)。示例1:输入:x=123输出:321示例2:输入:x=-123输出:-321示例3:......