力扣题目地址:https://leetcode-cn.com/problems/reverse-linked-list/
首先看题目:反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
先不管什么进阶,不管黑猫白猫,只要能抓到耗子就是好猫。我们就是用最笨的方法也得把这道题给解决喽。
解决思路:
首先明白我们要干啥,反转链表。最简单的方法是啥?就是把链表遍历一遍,取出所有的值,然后再反着给他拼回去不就行了。
实践代码:
首先加入题目中给的 ListNode 类
package com.gyx.util;
/**
* 节点类
* @author GeYuxuan 2020/02/29 17:09
*/
public class ListNode {
/**
* 节点值
*/
int val;
/**
* 下一个节点引用
*/
ListNode next;
/**
* 构造函数,初始化设置val值
* @param x
*/
ListNode(int x){
val = x;
}
}
然后我们开始我们的解题之旅:
- 取出所有链表节点值。
- 放入一个List中存储。
- 反向循环拼接链表节点。
代码实现如下:
/**
* 反转链表 - 不用脑子的解法
* @param head
* @author GeYuxuan 2020-03-02 22:08:57
* @return com.gyx.util.ListNode
*/
public ListNode reverseList(ListNode head) {
List<Integer> list = new ArrayList<>();
ListNode pre = new ListNode(0);
ListNode cur = pre;
while (head != null){
//1.2.两步一起,取值然后放入list
list.add(head.val);
//移动指针引用,指向下一个节点
head = head.next;
}
//反向循环拼接链表
for (int i = 0 ;i < list.size(); i++){
cur.next = new ListNode(list.get(list.size()-i));
cur = cur.next;
}
return pre.next;
}
然后我们测试一下:
package com.gyx.util;
/**
* description
* @author GeYuxuan 2020/02/29 17:35
*/
public class Test {
public static void main(String[] args) {
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
Solution solution = new Solution();
ListNode result = solution.reverseList(head);
while (result != null){
System.out.println(result.val);
result = result.next;
}
}
}
打印结果: 5 4 3 2 1
ok,这就是我们最笨的解法了。这种解法太笨了,有点暴力破解的意思。
所以现在我们来看看进阶的迭代解法。
迭代的意思就是不断循环调用相同的代码,但是每一次的初始值使用上一次的结果。
其实我们昨天两数相加的题目里面也用到了迭代,在链表中循环取值并打印出来,这就算一个简单的迭代了。
我们现在来考虑反转链表迭代的思路:
- 需要保存下一个节点,保证能循环当前链表。
- 将当前节点的next节点换成上一个节点。(反转)
- 移动pre指针将当前节点变成下一个节点的下一个节点。
- 将保存的下一个节点赋给当前节点,迭代下一个链表节点。
/**
* 反转链表 - 迭代
* @param head
* @author GeYuxuan 2020-03-02 22:08:57
* @return com.gyx.util.ListNode
*/
public ListNode reverseList1(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while(cur != null){
//1.保存下一个节点
ListNode nextNode = cur.next;
//2.修改当前节点的next节点 为 上一个节点
cur.next = pre;
//3.移动pre指针,保证当前节点是下一个节点的下一个节点
pre = cur;
//移动指针,移向下一个元素
cur = nextNode;
}
return pre;
}
其实迭代的解题方法我也说的不是很清楚怎么完成反转的。这周周末会补上一张自己画的gif动图,这样不仅可以帮助大家,也可以帮助我自己更好的理解迭代算法。
递归算法就更不用说了,感觉脑子不够用了,这周周末一起补上详解;一定得啃下它。
未完待续:
- 迭代算法gif动图。
- 递归算法详解。
不忘初心,砥砺前行。