1. 用数组结构实现大小固定的队列和栈
// 使用一个index, index比数组下标大1
public static class ArrayStack {
private Integer[] arr;
private Integer index;
public ArrayStack(int initSize) {
if (initSize < 0) {
throw new IllegalArgumentException("The init size is less than 0");
}
arr = new Integer[initSize];
index = 0;
}
public Integer peek() {
if (index == 0) {
return null;
}
return arr[index - 1];
}
public void push(int obj) {
if (index == arr.length) {
throw new ArrayIndexOutOfBoundsException("The stack is full");
}
arr[index++] = obj;
}
public Integer pop() {
if (index == 0) {
throw new ArrayIndexOutOfBoundsException("The stack is empty");
}
return arr[--index];
}
}
// 使用end和start,end代表队列尾,start代表队列头
// 加数:加数后end向后移一位,若此时到底后回到开头
// 拿数:拿数后start向后移一位,若到底回到开头
// 用一个size变量约束end和start,size代表当前队列中有多少数
// 只要size不超过数组大小,end就按上面的逻辑
// 只要size不是0,start就按上面的逻辑
// 这样end和start没有直接联系,循环利用数组
public static class ArrayQueue {
private Integer[] arr;
private Integer size;
private Integer start;
private Integer end;
public ArrayQueue(int initSize) {
if (initSize < 0) {
throw new IllegalArgumentException("The init size is less than 0");
}
arr = new Integer[initSize];
size = 0;
start = 0;
end = 0;
}
public Integer peek() {
if (size == 0) {
return null;
}
return arr[start];
}
public void push(int obj) {
if (size == arr.length) {
throw new ArrayIndexOutOfBoundsException("The queue is full");
}
size++;
arr[end] = obj;
end = nextIndex(arr.length, end);
}
public Integer poll() {
if (size == 0) {
throw new ArrayIndexOutOfBoundsException("The queue is empty");
}
size--;
int tmp = start;
start = nextIndex(arr.length, start);
return arr[tmp];
}
public int nextIndex(int size, int index) {
return index == size - 1 ? 0 : index +1;
}
}
2. 设计有 getMin 功能的栈
【要求】
- pop、push、getMin操作的时间复杂度都是O(1)。
- 设计的栈类型可以使用现成的栈结构。
public static class GetMinClass1 { private Stack<Integer> stackData; private Stack<Integer> stackMin; public GetMinClass1(){ stackData = new Stack<Integer>(); stackMin = new Stack<Integer>(); } public void push(Integer num){ stackData.push(num); // 如果 Min 栈为空,同步压入 Min 栈 if (stackMin.isEmpty()) { stackMin.push(num); } else { // 小于 Min 栈栈顶,也压入 Min 栈 if (num <= getMin()) stackMin.push(num); } } public Integer pop(){ if (stackData.isEmpty()) { throw new RuntimeException("Stack is empty."); } else if (stackData.peek() == getMin()) { // 如果 Data 栈 和 Min 栈栈顶相同,都弹出 stackMin.pop(); } return stackData.pop(); } // 返回 Min 栈的栈顶 public Integer getMin() { if (stackMin.isEmpty()) { throw new RuntimeException("Stack is empty."); } return stackMin.peek(); } }
public static class GetMinClass2 {
private Stack<Integer> stackData;
private Stack<Integer> stackMin;
public GetMinClass2() {
stackData = new Stack<Integer>();
stackMin = new Stack<Integer>();
}
public void push(Integer obj) {
// Data 栈压入
stackData.push(obj);
if (stackMin.isEmpty()) {
// 如果 Min 栈为空,压入 Min 栈
stackMin.push(obj);
} else if (obj <= getMin()) {
// 小于 Min 栈栈顶,也压入 Min 栈
stackMin.push(obj);
} else {
// 大于 Min 栈栈顶,重复压入 Min 栈顶
stackMin.push(getMin());
}
}
public int pop() {
if (stackData.isEmpty()) {
throw new RuntimeException("Stack is empty.");
}
// Data 栈和 Min 栈 大小相同,同步弹出
stackMin.pop();
return stackData.pop();
}
// 返回 Min 栈的栈顶
public int getMin() {
if (stackMin.isEmpty()) {
throw new RuntimeException("Stack is empty.");
}
return stackMin.pop();
}
}
// 方法一压入时候占用空间少,但弹出时花费时间长
// 方法而压入时候占用空间多,但弹出时花费时间短
3. 如何仅用队列结构实现栈结构?如何仅用栈结构实现队列结构?
// 使用两个队列来回倒,每次倒的时候留队列尾部最后一个元素,然后pop()这个元素
public static class TwoQueuesStack {
private Queue<Integer> queue;
private Queue<Integer> help;
public TwoQueueStack() {
queue = new LinkedList<Integer>();
help = new LinkedList<Integer>();
}
// 添加元素时添加到 queue 队列队尾
public void push(int pushInt) {
queue.add(pushInt);
}
public int peek() {
if (queue.isEmpty()) {
throw new RuntimeException("Stack is empty!");
}
// queue 队列的元素进入 help 队列,只留一个
while (queue.size() != 1) {
help.add(queue.poll());
}
int res = queue.poll();
help.add(res);
swap();
return res;
}
public int pop() {
if (queue.isEmpty()) {
throw new RuntimeException("Stack is empty!");
}
// queue 队列的元素进入 help 队列,只留一个
while (queue.size() > 1) {
help.add(queue.poll());
}
int res = queue.poll();
swap();
return res;
}
private void swap() {
Queue<Integer> tmp = help;
help = queue;
queue = tmp;
}
}
// 一个push栈,一个pop栈
// 1. pop中如果不为空,push栈不能往pop栈倒
// 2. push栈往pop栈倒的时候,要一次将元素都倒过去
public static class TwoStacksQueue {
private Stack<Integer> stackPop;
private Stack<Integer> stackPush;
public TwoStacksQueue() {
stackPush = new Stack<Integer>();
stackPop = new Stack<Integer>();
}
public void push(int pushInt) {
stackPush.push(pushInt);
}
public int poll() {
if(stackPop.isEmpty() && stackPush.isEmpty()) {
throw new RuntimeException("Queue is empty.")
}
dao();
return stackPop.pop();
}
public int peek() {
if(stackPop.isEmpty() && stackPush.isEmpty()) {
throw new RuntimeException("Queue is empty.")
}
dao();
return stackPop.peek();
}
public void dao() {
if (stackPop.isEmpty()) {
while (!stackPush.isEmpty()) {
stackPop.push(stackPush.pop());
}
}
}
}
4. 猫狗队列
实现一种狗猫队列的结构,要求如下: 用户可以调用add方法将cat类或dog类的实例放入队列中; 用户可以调用pollAll方法,将队列中所有的实例按照进队列的先后顺序依次弹出; 用户可以调用pollDog方法,将队列中dog类的实例按照进队列的先后顺序依次弹出; 用户可以调用pollCat方法,将队列中cat类的实例按照进队列的先后顺序依次弹出; 用户可以调用isEmpty方法,检查队列中是否还有dog或cat的实例; 用户可以调用isDogEmpty方法,检查队列中是否有dog类的实例; 用户可以调用isCatEmpty方法,检查队列中是否有cat类的实例。
宠物、狗和猫的类如下:
public class Pet {
private String type;
public Pet(String type) {
this.type = type;
}
public String getPetType() {
return this.type;
}
}
public class Dog extends Pet {
public Dog() {
super("dog");
}
}
public class Cat extends Pet {
public Cat() {
super("cat");
}
}
public static class PetEnterQueue {
private Pet pet;
private long index;
public PetEnterQueue(Pet pet, long count) {
this.pet = pet;
this.index = count;
}
public Pet getPet() {
return this.pet;
}
public long getCount() {
return this.index;
}
public String getEnterPetType() {
return this.pet.getPetType();
}
}
public static class DogCatQueue {
private Queue<PetEnterQueue> dogQ;
private Queue<PetEnterQueue> catQ;
private long index;
public DogCatQueue() {
this.dogQ = new LinkedList<PetEnterQueue>();
this.catQ = new LinkedList<PetEnterQueue>();
this.index = 0;
}
public void add(Pet pet) {
if (pet.getPetType().equals("dog")) {
this.dogQ.add(new PetEnterQueue(pet, this.index++));
} else if (pet.getPetType().equals("cat")) {
this.catQ.add(new PetEnterQueue(pet, this.index++));
} else {
throw new RuntimeException("err, not dog or cat");
}
}
public Pet pollAll() {
if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) {
if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()) {
return this.dogQ.poll().getPet();
} else {
return this.catQ.poll().getPet();
}
} else if (!this.dogQ.isEmpty()) {
return this.dog.poll().getPet();
} else if (!this.catQ.isEmpty()) {
return this.catQ.poll().getPet();
} else {
throw new RuntimeException("err, queue is empty!");
}
}
public Dog pollDog() {
if (!this.isDogQueueEmpty()) {
return (Dog) this.dogQ.poll().getPet();
} else {
throw new RuntimeException("Dog queue is empty!");
}
}
public Cat pollCat() {
if (!this.isCatQueueEmpty()) {
return (Cat) this.catQ.poll().getPet();
} else
throw new RuntimeException("Cat queue is empty!");
}
public boolean isEmpty() {
return this.dogQ.isEmpty() && this.catQ.isEmpty();
}
public boolean isDogQueueEmpty() {
return this.dogQ.isEmpty();
}
public boolean isCatQueueEmpty() {
return this.catQ.isEmpty();
}
}
5. 转圈打印矩阵
【题目】 给定一个整型矩阵matrix,请按照转圈的方式打印它。
例如:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
打印结果为:1,2,3,4,8,12,16,15,14,13,9,5,6,7,11, 10
【要求】 额外空间复杂度为O(1)。
// 不要试图去模拟打印的轨迹
// 使用(row1, col1) (row2, col2) 左上角与右下角的坐标,确定一个矩阵然后打印这个矩阵的一圈
public static void spiralOrderPrint(int[][] matrix) {
int row1 = 0;
int col1 = 0;
int row2 = matrix.length - 1;
int col2 = matrix[0].length - 1;
while (row1 <= row2 && col1 <= col2) {
printEdge(matrix, row1++, col1++, row2--, col2--);
}
}
public static void printEdge(int[][] m, int row1, int col1, int row2, int col2) {
if (row1 == row2) {
for (int i = col1; i <= col2; i++) {
System.out.print(m[row1][i] + " ");
}
} else if (col1 == col2) {
for (int i = row1; i <= row2; i++) {
System.out.print(m[i][col1] + " ");
}
} else {
int curC = col1;
int curR = row1;
while (curC != col2) {
System.out.print(m[row1][curC] + " ");
curC++;
}
while (curR != row2) {
System.out.print(m[curR][col2] + " ");
curR++;
}
while (curC != col1) {
System.out.print(m[row2][curC] + " ");
curC--;
}
while (curR != row1) {
System.out.print(m[curR][col1] + " ");
curR--;
}
}
}
四个while如下图
6. “之”字形打印矩阵
【题目】 给定一个矩阵matrix,按照“之”字形的方式打印这个矩阵,
例如:
1 2 3 4
5 6 7 8
9 10 11 12
“之”字形打印的结果为:1,2,5,9,6,3,4,7,10,11,8,12
【要求】 额外空间复杂度为O(1)。
// 不要去研究下标如何变动
// 两个开始都指向(0,0) (r1,c1)向右移动,到头后向下移动 (r2,c2)向下移动,到头后向右移动
public static void printMatrixZigZag(int[][] matrix) {
int row1 = 0;
int col1 = 0;
int row2 = 0;
int col2 = 0;
int endR = matrix.length - 1;
int endC = matrix[0].length - 1;
boolean fromUp = false;
// row1越界就终止
while (row1 != endR + 1) {
printLevel(matrix, row1, col1, row2, col2, fromUp);
row1 = col1 == endC ? row1 + 1 : row1; // row1到行末后开始增加
col1 = col1 == endC ? col1 : col1 + 1;
col2 = row2 == endR ? col2 + 1 : col2;
row2 = row2 == endR ? row2 : row2 + 1;
fromUp = !fromUp;
}
System.out.println();
}
public static void printLevel(int[][] m, int row1, int col1, int row2, int col2, boolean fromUp) {
if (fromUp) {
while (row1 <= row2) {
System.out.print(m[row1++][col1--] + " ")
}
} else {
while (row2 != row1 - 1) {
System.out.print(m[row2--][col2++] + " ");
}
}
}
练习问题:
在调整row1,row2,col1,col2时,row1和col1是以endC和col1的比较结果作为依据,所以row1的调整应该在col1之前;row2和col2是以endR和row2的比较结果作为依据,所以col2的调整应该在row2前;否则如果依据先调整变化了,row1和col2的变化就不会准确。
7. 搜索二维矩阵
【题目】 给定一个有N*M的整型矩阵matrix和一个整数K,matrix的每一行和每一 列都是排好序的。实现一个函数,判断K是否在matrix中。 例如:
0 1 2 5
2 3 4 7
4 4 4 8
5 7 7 9
如果K为7,返回true;如果K为6,返回false。
【要求】 时间复杂度为O(N+M),额外空间复杂度为O(1)。
- 从右上角或左下角开始找……
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
if(matrix.length == 0 || matrix[0].length == 0 || matrix == null) {
return false;
}
int row = 0, col = matrix[0].length - 1;
while (row <= matrix.length - 1 && col >= 0) {
if (target == matrix[row][col]){
System.out.println(row+"--"+col);
return true;
} else if (target < matrix[row][col]){
System.out.println(row+"--"+col);
--col;
} else {
System.out.println(row+"--"+col);
++row;
}
}
return false;
}
}
练习问题:
在更改代码的时候条件连接符用的 || ,导致数组下标越界了。
8. 打印两个有序链表的公共部分
【题目】 给定两个有序链表的头指针head1和head2,打印两个链表的公共部分。
- 谁小往后移动一位指针,相同的话共同向后移动一位指针……
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode prehead = new ListNode(-1);
ListNode prev = prehead;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
prev.next = l1 == null ? l2 : l1;
return prehead.next;
}
}
9. 判断一个链表是否为回文结构
【题目】 给定一个链表的头节点head,请判断该链表是否为回文结构。 例如: 1->2->1,返回true。 1->2->2->1,返回true。15->6->15,返回true。 1->2->3,返回false。
进阶: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。
-
使用栈,栈的弹出顺序即为逆序。
-
快指针一次两步,慢指针一次一步,快指针走到终点时,慢指针走到中点。将后一半入栈,与前一半比较。
-
快指针一次两步,慢指针一次一步,快指针走到终点时,慢指针走到中点。将后一半逆序,从前往后和从后往前同时遍历进行比较,有一次不等则不是回文,判断完后还要把链表后半的顺序调整回来。
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
if (head.next == null) return true;
if (head.next.next == null) return head.val==head.next.val;
// 快慢指针向后移动,快指针到终点时,慢指针到中点
ListNode quick = head;
ListNode slow = head;
while (quick.next != null && quick.next.next != null) {
quick = quick.next.next;
slow = slow.next;
}
if (quick.next != null) {
quick = quick.next;
}
// 反转后半链表
slow = slow.next;
slow = reverseList(slow);
// 比较后半链表与前半是否相同
while (slow != null) {
if (slow.val != head.val) {
return false;
}
head = head.next;
slow = slow.next;
}
return true;
}
public ListNode reverseList(ListNode head) {
ListNode newHead = null;
while (head != null) {
ListNode nextTemp = head.next;
head.next = newHead;
newHead = head;
head = nextTemp;
}
return newHead;
}
}
10. 分隔链表
【题目】 给定一个单向链表的头节点head,节点的值类型是整型,再给定一个整数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot 的节点,中间部分都是值等于pivot 的节点,右部分都是值大于 pivot 的节点。除这个要求外,对调整后的节点顺序没有更多的要求。 例如:链表9->0->4->5->1,pivot=3。 调整后链表可以是1->0->4->9->5,也可以是0->1->9->5->4。总之,满 足左部分都是小于3的节点,中间部分都是等于3的节点(本例中这个部分为空),右部分都是大于3的节点即可。对某部分内部的节点顺序不做 要求。
- 生成数组存放Node结点,partition之后再连起来。
进阶: 在原问题的要求之上再增加如下两个要求。在左、中、右三个部分的内部也做顺序要求,要求每部分里的节点从左 到右的顺序与原链表中节点的先后次序一致。 例如:链表9->0->4->5->1,pivot=3。调整后的链表是0->1->9->4->5。 在满足原问题要求的同时,左部分节点从左到右为0、1。在原链表中也 是先出现0,后出现1;中间部分在本例中为空,不再讨论;右部分节点 从左到右为9、4、5。在原链表中也是先出现9,然后出现4,最后出现5。如果链表长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)。
- 如下图,遍历一遍链表分别找到第一个小于、等于、大于pivot的节点;然后在遍历一边,内存地址相同的直接跳过,不同的分类往small,equal,big后面挂;遍历完了再将三个部分重新连接起来。
- 如何处理三部分中某一部分没有的问题?链表的题少有算法特别难的,且往往是面试的头一道或头两道题,这就考察实打实的coding能力,需要多练。
class Solution {
public static ListNode listPartition2(ListNode head, int pivot) {
if (head == null) {
return head;
}
ListNode sH = null;
ListNode sT = null;
ListNode eH = null;
ListNode eT = null;
ListNode bH = null;
ListNode bT = null;
ListNode next = null;
while (head != null) {
next = head.next;
head.next = null;
if (head.val < pivot) {
if (sH == null) {
sH = head;
sT = sH;
} else {
sT.next = head;
sT = sT.next;
}
} else if (head.val > pivot) {
if (bH == null) {
bH = head;
bT = bH;
} else {
bT.next = head;
bT = bT.next;
}
} else {
if (eH == null) {
eH = head;
eT = eH;
} else {
eT.next = head;
eT = eT.next;
}
}
head = next;
}
if (sT != null) {
sT.next = eH;
eT = eT == null ? sT : eT;
}
if (eT != null) {
eT.next = bH;
}
return sH != null ? sH : eH != null ? eH : bH;
}
public static ListNode listPartition1(ListNode head, int pivot) {
if (head == null) {
return null;
}
ListNode node = head;
int i = 0;
while (node != null) {
i ++;
node = node.next;
}
ListNode[] arr = new ListNode[i];
node = head;
for (i=0; i<arr.length; i++) {
arr[i] = node;
node = node.next;
}
arrPartition(arr, pivot);
for (i = 1; i < arr.length; i++) {
arr[i-1].next = arr[i];
}
arr[i-1].next = null;
return arr[0];
}
public static void arrPartition(ListNode[] arr, int pivot) {
int small = -1;
int big = arr.length;
int index = 0;
while (index != big) {
if (arr[index].val < pivot) {
swap(arr, ++small, index++);
} else if (arr[index].val > pivot) {
swap(arr, --big, index);
} else {
index++;
}
}
}
}
11. 复制带随机指针的链表
【题目】 一种特殊的链表节点类描述如下:
public class Node {
public int value;
public Node next;
public Node rand;
public Node(int data) {
this.value = data;
}
}
Node类中的value是节点值,next指针和正常单链表中next指针的意义一 样,都指向下一个节点,rand指针是Node类中新增的指针,这个指针可 能指向链表中的任意一个节点,也可能指向null。 给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个函数完成这个链表中所有结构的复制,并返回复制的新链表的头节点。
- 如下图,第一遍遍历时,在map中存储原结点与复制结点的对应关系;第二遍遍历时,根据结点的next指针和rand指针和map拷贝;完成深度拷贝。
public static Node copyListWithRand1(Node head) {
HashMap<Node, Node> map = new HashMap<Node, Node>();
Node cur = head;
// 第一次遍历,创建存储对应关系的map
while (cur != null) {
map.put(cur, new Node(cur.value));
cur = cur.next;
}
Node X = head;
// 第二次遍历,完成深度拷贝
while (X != null) {
map.get(X).next = map.get(X.next);
map.get(X).rand = map.get(X.rand);
X = X.next;
}
return map.get(head);
}
进阶:不使用额外的数据结构,只用有限几个变量,且在时间复杂度为 O(N)内完成原问题要实现的函数。
- 如下图,原链表中每个结点后面跟一个自己的拷贝结点,遍历时就可以利用这种关系完成深度拷贝,深度拷贝后再将老链表与原链表分离。
// 好歹是做出来了,以后在优化
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
if (head.next == null) {
if (head.random == null) return new Node(head.val, null, null);
if (head.random == head) {
Node res = new Node(head.val, null, null);
res.random = res;
return res;
}
Node res = new Node(head.val, null, new Node(head.random.val, null, null));
return res;
}
// 1. 复制的结点挂在对应的原结点后面
Node cur1 = head;
while (cur1 != null) {
Node next = cur1.next;
cur1.next = new Node(cur1.val,next,null);
cur1 = cur1.next.next;
}
// 2. 利用 原结点->复制结点 的关系进行深拷贝
Node cur2 = head;
while (cur2 != null) {
// random 指针为 null 时候特殊处理
if (cur2.random == null) {
cur2.next.random = null;
} else {
cur2.next.random = cur2.random.next;
}
cur2 = cur2.next.next;
}
// 3. 分离老链表与新链表
Node cur3 = head;
Node prehead = head.next;
Node prev = prehead;
while (prev.next != null) {
Node next = prev.next;
cur3.next = next;
prev.next = next.next;
cur3 = cur3.next;
prev = prev.next;
}
cur3.next = null;
return prehead;
}
}
12. 判断链表有环
// 使用快慢指针,快指针一次走两步,慢指针一次走一步,快慢指针相遇时说明链表有环(会在两圈以内相遇)
// 相遇后快指针回到链表开头,变成一次走一步,再次相遇时快慢指针位于入环结点上(数学结论)
// 证明:环外长度L,环内长度R,第一次相遇时……
13. 两个单链表相交的一系列问题
【题目】 在本题中,单链表可能有环,也可能无环。给定两个单链表的头节点 head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数, 如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null 即可。 要求:如果链表1的长度为N,链表2的长度为M,时间复杂度请达到 O(N+M),额外空间复杂度请达O(1)。
// 先得到两个链表的入环结点(快慢指针法)
// 1. 入环结点都为空,两链表都无环
// 0) 判断两链表相交
// a.看两链表尾结点是否相同,不相同则不相交
// b.遍历两链表,得到两链表长度 m,n
// c.计算差值|m-n|
// d.长链表由|m-n|处开始遍历,短链表从头遍历,相遇结点即为相交的第一个结点
// 1) 两链表相交: 由于单链表只有一个 next 指针,相交只会出现“Y”形状,不会出现“X”形状
// 2) 两链表不相交:返回 null
// 2. 一个链表有环,一个链表无环
// 1) 一定不相交:可以画图验证,单链表只有一个 next 指针
// 3. 两个链表都有环
// 0) 三种情况如上图所示
// a.入环结点 loop1 == loop2 时,为第二种情况,以入环结点为终止可以复用单链表相交的代码
// b.入环结点 loop1 != loop2 时,loop1 继续向下走
// - 若 loop1 回到自身都没有和 loop2 相遇,说明为第一种情况,返回null
// - 若 loop1 和 loop2 相遇,说明为三种情况,loop1 与 loop2 都可以是相交的第一个结点
// 1) 两个链表各自成环
// 2) 两个链表入环前相交,共用一个环
// 3) 两个链表入环结点不同,共用一个环
14. 二分的小拓展
无序也可以二分
15. 反转单向和双向链表
【题目】 分别实现反转单向链表和反转双向链表的函数。
【要求】 如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度要求为O(1)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
}
头插法:维护一个以 prev 为头节点的新链表,不断的在这个新链表的头部插入节点来达到反转链表的目的。刚开始的时候,prev 为 null,代表反转后的新链表的最后一个节点的 next 指针。遍历链表进行头插的过程中使用 nextTemp 保存当前位置的下一个节点。
1650





