大家好,本篇是个人的第4篇文章。
承接第3篇文章《开启算法之路,还原题目,用debug调试搞懂每一道题》,本篇文章继续分享关于链表的算法题目。
本篇文章共有5道题目
一,反转链表(经典题目) 1.1.1 题目分析反转链表是经典的题目,题中信息描述很清晰,给定一个单链表,将其反转。
先说说有什么思路呢?从题中给的案例输出结果看,是不是只需要将输入的链表的指针改成相反方向,就可以得到要输出的结果。
就好比如下图所示:
但是问题来了,我们是单链表,是没办法将下个节点直接指向该节点的上个节点。
因此就需要定义一个辅助指针,用来指向该节点的上个节点,这样就能完成,如下图所示。
那按照我们上面分析也就是将cur指针指向pre节点就可以了。
注意:此处有坑
当我们将当前节点【cur】指向上一个节点【pre】的时候,如何将指针向下移动呢?
此时的节点【cur】已经指向了上一个节点【pre】了,所以我们还需要一个临时变量去保存当前节点的下个节点,具体为什么这么做,我们在下面代码演示的时候debug看下过程。
接着我们上面的步骤,将指针向下移动,如图所示。
移动指针后,再将当前节点的next指针指向上一个节点。
最后当前节点没有下个节点的时候,就结束遍历,如图所示。
1.1.2 代码分析按照套路,先初始化节点对象。
class ListNode { int val; ListNode next; ListNode() { } ListNode(int val) { this.val = val; } ListNode(int val, ListNode next) { this.val = val; this.next = next; } @Override public String toString() { return "ListNode{" + "val=" + val + '}'; } }创建单链表结构。
// 创建单链表 ListNode l1 = new ListNode(1); ListNode l2 = new ListNode(2); ListNode l3 = new ListNode(3); ListNode l4 = new ListNode(4); ListNode l5 = new ListNode(5); NodeFun nodeFun = new NodeFun(); nodeFun.add(l1); nodeFun.add(l2); nodeFun.add(l3); nodeFun.add(l4); // 返回创建的链表 ListNode node = nodeFun.add(l5);反转链表的代码。
public ListNode reverseListIteration(ListNode head) { // 定义上节点辅助指针 ListNode pre = null; // 定义当前节点辅助指针 ListNode cur = head; // 循环当前节点不为空 while (null != cur) { // 临时变量保存当前节点的下个节点 ListNode temp = cur.next; // 当前节点的next指向上节点 cur.next = pre; // 上节点向下移动 pre = cur; // 当前节点指向下个节点 cur = cur.next; } return pre; } 1.1.3 debug调试节点初始化完成了,按照分析我们定义了2个节点,如上图第一次遍历【pre】节点是null,【cur】从第一个节点开始。
下一步debug调试我们先不急,回顾之前说的一个问题,为什么要将当前节点的下一个节点用临时变量保存,那我们直接看debug调试。
第一次遍历的时候,修改完指针后当前节点已经指向上一个节点了,再看上述题目分析的图解。
这就是为啥要先把当前节点的下个节点缓存起来。
上图debug我们看出,【cur】当前节点的指针已经指向null,下一步就是移动指针指向下一个节点。
我们再接着进行debug调试,按照上述分析,第二步循环就是将节点【2】指向上一个节点【1】,如下图所示。