从尾到头打印链表
反转链表专题
No.1 问题描述
输入一个链表,从尾到头的顺序返回一个ArrayList
解题思路
1.使用递归法
//1.解法一
public ArrayList<Integer> printListReverse(ListNode listnode){
ArrayList<Integer> arrayList = new ArrayList<Integer>();
if(listnode != null){
arrayList.addAll(printListReverse(listnode.next));
arrayList.add(listnode.val);
}
return arrayList;
}
//分析:时间复杂度为O(n),相当于将每个元素均遍历了一遍
//空间复杂度为O(n^2),创建的列表的合计元素个数1+2+3+4+n-1
//拓展内容:ArrayList中的addAll(Collection<? extends E> c) 方法 按照指定collection容器返回元素的
//顺序将所有的元素添加到列表的尾部
2.使用栈(推荐解法)
//Java实现
public ArrayList<Integer> printListReverse(ListNode listnode){
ArrayDeque<Integer> stack = ArrayDeque<Integer>();
while(listnode != null){
stack.addFirst(listnode.val);
listnode = listnode.next;
}
ArrayList<Integer> arrayList = new ArrayList<Integer>();
while(stack.pollFirst())
arrayList.add(stack.pollFirst())
return arrayList;
}
//Java中推荐使用ArrayDeque来实现一个栈
//当压栈时,调用addFirst()方法; 出栈时调用pollFirst()方法
//分析:时间复杂度O(n),空间复杂度也是O(n)
#基于Python的实现
class Solution:
def printListReverse(self,listnode):
if not listnode:
return []
result = []
while listnode:
result.insert(0,listnode.val)
listnode = listnode.next
return result;
#Python中推荐使用list列表来实现堆栈
#空间复杂度为O(n),时间复杂度为O(n^2)
其实在Java的实现中实际的空间复杂度为O(2n),Python中的空间复杂度为O(n);但是Python中
当向列表的头部插入元素时,时间复杂度为O(n),总共为O(n^2),所以可以看出Java实现中是以多出
O(n)的空间复杂度换取时间复杂度的降低
3.使用头插法
创建单链表的方法有两种,分别是头插法和尾插法
头插法就是按节点的逆序方法逐渐将节点插入到链表的头部,尾插法就是按照节点的顺序逐渐将节点插入
到链表的尾部;头插法创建的链表是逆序的,这也正符合本题中的要求
头插法的算法描述:从一个空表开始,重复读入数据,生成新节点,将读入数据存放到新结点的数据域中
然后将新结点插入到当前链表的表头节点之后
尾插法是从一个空表开始,重复读入数据,生成新节点,将读入数据存放到新节点的数据域中,然后将
新节点插入到当前的末尾节点之后
//Java使用头插法构建逆序链表
public ArrayList<Integer> printListReverse(ListNode listnode){
ListNode head = new ListNode(-1);
while(listNode != null){
ListNode newNode = listnode.next;
listnode.next = head.next
head.next = listnode;
listnode = newNode;
}
//构建ArrayList
ArrayList<Integer> arrayList = new ArrayList<Integer>();
head = head.next;
while(head!=null){
arrayList.add(head.val);
head = head.next;
}
return arrayList;
}
//分析:时间复杂度为O(n),空间复杂度也是O(n)
No.2 问题描述
反转一个链表、反转一个链表的前N个元素、反转一个链表的部分元素
//递归实现单链表的反转 代码实现
//输入一个节点head,将以head为起点的链表反转,并返回反转之后的头节点
public ListNode reverse(ListNode head){
if(head == null) return head;
if(head.next == null) return head; //链表只有一个节点时,反转也只是它自己
ListNode last = reverse(head.next);
head.next.next = head;
head.next = null;
return last;
}
//递归实现反转一个链表的一部分
private ListNode successor = null; //后驱节点
public ListNode reverseN(ListNode head, int n){
if(n==1){
successor = head.next;
return head;
}
ListNode last = reverseN(head.next,n-1);
//让反转之后的节点和后面的节点连接起来
head.next.next = head;
head.next = successor;
return last;
}
public ListNode reverseBetween(ListNode head,int m,int n){
if(m == 1){
return reverseN(head,n);
}
//将反转后的头结点赋值成当前节点的下个节点
head.next = reverseBetween(head.next,m-1,n-1);
return head;
}