Leetcode-206 反转链表

题目

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

 

示例 1:

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

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

 

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

 

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

我的思路

设置一个临时数组存储链表元素,再将临时数组中的链表元素倒序存放入一个新链表中

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head != null){    
            ListNode reverseList = new ListNode();
            ListNode tempNode = head;
            List<Integer> tempList = new ArrayList<Integer>();
            while(tempNode != null){
                tempList.add(tempNode.val);
                tempNode = tempNode.next;
            }
            reverseList.val = tempList.get(tempList.size()-1);
            reverseList.next = null;
            tempNode = reverseList;
            for(int i = tempList.size()-2; i >= 0; --i){
                ListNode temp = new ListNode();
                temp.val = tempList.get(i);
                temp.next = null;
                tempNode.next = temp;
                tempNode = temp;
            }
            return reverseList;
        }
        else{
            return head;
        }
    }
}

这个思路空间复杂度为O(n),下面参考了别人的更简洁的写法,主要是利用了链表之间的节点连接,连接一个结点就相当于将该节点的后续结点都连接了。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode ans = null;
        for (ListNode x = head; x != null; x = x.next) {
            //ans就是前一个结点,ans赋值后为当前结点,每次实例化节点后都连接好节点了
            ans = new ListNode(x.val,ans);
        }
        return ans;
    }
}

迭代法

将当前节点的next指针指向前一个节点,要注意保存好前一个节点的指针。还有要有一个当前节点的指针,用于迭代。临时指针,用于交换。使用while循环

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    //使用迭代法反转链表
    public ListNode reverseList(ListNode head) {
        //需要有一个pre指针,保存前一个结点
        ListNode preNode = null;
        //还需要一个当前节点的指针,方便迭代
        ListNode currNode = head;
        //临时节点,方便交换用的
        ListNode tempNode = null;
        while(currNode != null){
            tempNode = currNode.next;
            currNode.next = preNode;
            preNode = currNode;
            currNode = tempNode;
        }
        /**
            head = preNode;
            没有必要进行这一步,因为preNode本就为null,如果head为null,直接返回pre也是null
         */
        return preNode;
    }
}

递归法

先进入最后一层(调用递归函数),然后返回给前面的层进行连接(进行实际地处理反转)。要注意递归的结束条件(什么时候直接返回,不会进行实际处理反转),到达最后一层的条件为head.next为null,但是head为null也不能进入递归(即直接返回)。还有要注意当前层要做什么事(把当前层连接到反转好的链表中)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    //使用递归法反转链表
    public ListNode reverseList(ListNode head) {
        //递归用if语句判断终止条件(返回条件)
        if(head == null || head.next == null){
            //当到达最后一层时,返回的就是最后一个节点的指针
            return head;
        }
        //反转head后面的节点
        ListNode newHead = reverseList(head.next);//newHead为反转链表的头节点
        //处理当前head节点
        head.next.next = head;//将当前层head下一个节点的next指针连接到head作反转
        head.next = null;
        return newHead;
    }
}

 

学到和回忆了

  • 在处理链表等问题时,首先要判断链表是否为空
  • 在Java中,判断集合元素数量和添加元素的方法是size()和add()
  • 在Java中,ArrayList可以随机访问,但不能使用[]访问下标,而只能使用get()方法访问下标
  • 在Java中,泛型只能是包装类而不能是基本数据类型
  • 在Java中,必须要显示判断变量是否为null

参考

反转链表 - 反转链表 - 力扣(LeetCode) (leetcode-cn.com)

一步一步教你如何用递归思想反转链表 - 反转链表 - 力扣(LeetCode) (leetcode-cn.com)

posted @ 2022-03-23 21:48  心空之上  阅读(27)  评论(0)    收藏  举报