一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
前言
笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。
系列文章收录《算法》专栏中。
问题描述
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
示例 1:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
示例 2:
输入:head = [5], left = 1, right = 1
输出:[5]
提示:
- 链表中节点数目为 n
- 1 <= n <= 500
- -500 <= Node.val <= 500
- 1 <= left <= right <= n
进阶: 你可以使用一趟扫描完成反转吗?
剖析
需要把从right开始到left为止的位置的元素进行调换,因为调换的过程中涉及到依次取右边的元素到左边来,但是链表不适合随机定位,所以笔者的想法是先遍历一遍放入数组,放完后再从左边开始进行调换。每次迭代前一个节点nodeBefore,把右边的元素作为nodeBefore的next节点。
其他需要注意的地方就是:left可能为最左边元素,我们可以使用创建一个-1位置的节点hair,最后返回hair的next就是头节点了,最后的nodeBefore节点需要和后面的节点衔接上。
代码
package com.study.algorithm.linklist;
import java.util.ArrayList;
import java.util.List;
/**
* https://leetcode-cn.com/problems/reverse-linked-list-ii/
* 反转链表 II
*/
public class ReverseBetween {
public static class ListNode {
int val;
ListNode next;
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public static ListNode reverseBetween(ListNode head, int left, int right) {
if (left == right) {
return head;
}
ListNode hair = new ListNode(-1);
hair.next = head;
ListNode current = head;
List<ListNode> nodeList = new ArrayList<>();
while (current != null) {
nodeList.add(current);
current = current.next;
}
ListNode nodeBefore;
if ((left - 2) < 0) {
nodeBefore = hair;
} else {
nodeBefore = nodeList.get(left - 2);
}
int needSwapIndex = right - 1;
for (int i = (left - 1); i < right; i++) {
nodeBefore.next = nodeList.get(needSwapIndex);
nodeBefore = nodeList.get(needSwapIndex);
needSwapIndex--;
}
if (right == nodeList.size()) {
nodeBefore.next = null;
} else {
nodeBefore.next = nodeList.get(right);
}
return hair.next;
}
}