一.简介
挑选了几道常考的反转链表题,链表是通过指针将一组零散的内存串联在一起,反转充分了利用指针来操作。(不限语言,本文是 Java 示例)
二.示例
2.1 反转链表
反转一个单链表,例如把 1->2->3->null 反转 3->2->1->null 形式,指针反转,不仅仅是值的变化。
迭代
迭代的形式,按照一般思路先有一个指针指向前驱结点,每次都在移位前驱结点,这样把指针反转过来。
public void reverseList(ListNode head){ ListNode reList = null; //前驱 ListNode prev = null; //当前 ListNode curr = head; while (curr != null){ //指向下一个结点 ListNode next = curr.getNext(); if(next == null){ reList = curr; } //当前结点指向前驱结点,例如 1-> null curr.setNext(prev); //前驱结点被赋值 1-> null prev = curr; // 2-> 3 如此进行迭代 curr = next; } return reList;}
复制代码
递归
public ListNode reverseList(ListNode head) { return reverseList2(null,head); } //跟迭代类似,运用前驱结点,每次递归,把提前存储在内存中next ,这样累加前驱结点地址 ListNode reverseList2(ListNode prev,ListNode curr){ if(curr == null) return prev; ListNode next = curr.next; curr.next = prev; return reverseList2(curr,next); }
复制代码
2.2 两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表,你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
迭代
因为从第一个结点开始反转,这样引入哨兵,不参与计算,站位好处理第一个结点,解决邻居依赖问题。
public ListNode swapPairs(ListNode head) { ListNode prev = new ListNode(0); prev.next = head; //前驱结点 ListNode p1 = prev; ListNode p2 = null; while(p1.next != null && p1.next.next != null){ p2 = p1.next;//p2 等于 下一个结点 1->2->3->4 p1.next = p2.next;//这两步骤把第二结点,赋值到 0 -> 2 //1->3->4 跳过2结点,因为要反转,把2结点放到第一位 p2.next = p2.next.next; //0->2->1->3->4 第一组反转完毕 p1.next.next = p2; //赋值p1 因为要进入下一组 p1 = p2; } return prev.next; }
复制代码
递归
public ListNode swapPairs(ListNode h) { if (h == null || h.next == null) { return h; } ListNode newHead = h.next; //这个递归是要把 3 -> 4,反转 4-> 3 ,然后返回上层再处理第一组1->2的反转 h.next = swapPairs(newHead.next); newHead.next = h; return newHead;}
复制代码
2.3 k 个一组反转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例
给你这个链表:1->2->3->4->5。
当 k = 2 时,应当返回: 2->1->4->3->5。
当 k = 3 时,应当返回: 3->2->1->4->5。
结点列表每 k 个就反转,相当于把 2.2 两辆反转变形了。
因为从第一个结点开始反转,这样引入哨兵,不参与计算,站位好处理第一个结点,解决邻居依赖问题,这个难度比较大,得需要借助图形更加深理解。
public void reverseKGroup(int k){ ListNode hair = new ListNode(0); //头结点 ListNode head2 = head; hair.setNext(head2); ListNode pre = hair; while (head2 != null) { ListNode tail = pre; // 查看剩余部分长度是否大于等于 k for (int i = 0; i < k; ++i) { tail = tail.getNext(); if (tail == null) { break; } } ListNode nex = tail.getNext(); //反转,k个结点 ListNode[] reverse = myReverse(head2, tail); //已经反转完毕的,一组结点 head2 = reverse[0]; //一组结点的后继结点 tail = reverse[1]; // 把子链表重新接回原链表 pre.setNext(head2); tail.setNext(nex); //这个是处理下一组的结点 pre = tail; head2 = tail.getNext(); } return hair.getNext();}/** * 反转 */private ListNode[] myReverse(ListNode curr,ListNode tail){ ListNode prev = tail.next; ListNode p = curr; //反转完毕,地址相等的判定 while (prev != tail) { ListNode nex = p.next; p.next = prev; prev = p; p = nex; } return new ListNode[]{tail, curr};}
复制代码
参考
https://leetcode-cn.com/problems/reverse-linked-list/
https://leetcode-cn.com/problems/swap-nodes-in-pairs/
https://leetcode-cn.com/problems/reverse-nodes-in-k-group/?utmsource=LCUS&utmmedium=ipredirect&utmcampaign=transfer2china
评论