题目描述
给定一个非空链表的头节点,从该链表的中间节点开始返回。如果中间节点有两个,则返回第二个中间节点。
示例1:
1—>2—>3—>4—>5—>null,中间节点为3,所以返回3—>4—>5—>null。
示例2:
1—>2—>3—>4—>5—>6—>null,中间节点为3、4,根据要求返回第二个中间节点,所以返回4—>5—>6—>null
解题思路
题目本身比较简单,可以借助其他有下标的数据结构来完成,也可以通过先遍历一次求出链表的长度,再遍历一次求出结果。
解法1:
借助有下标的数据结构
/**
* 借助数组
* 因为链表的问题就在与不能通过下标定位到某个节点,所以我们可以借助数组来完成,ArrayList本质就是一个动态数组
*
* @param head
* @return
*/
public ListNode middleNode(ListNode head) {
List<ListNode> nodeList = new ArrayList<>();
while (head != null) {
nodeList.add(head);
head = head.next;
}
return nodeList.get(nodeList.size() / 2);
}
解法2:
借助栈实现,同数组道理一样
public ListNode middleNode(ListNode head) {
Stack<ListNode> stack = new Stack<>();
ListNode c = head;
//先把所有节点依次入栈
while (c != null) {
stack.push(c);
c = c.next;
}
int size = stack.size();
int mid = size / 2;
ListNode res = null;
//依次从栈中弹出
for (int i = 0; i < mid; i++) {
res = stack.pop();
}
//如果是节点的长度是偶数,则直接返回,如果是奇数,则要多弹一个。
if ((size & 1) == 0) {
return res;
}
return stack.pop();
}
解法3:
不借助额外空间,两次遍历
/**
* O(1)的空间复杂度实现
* 数组的方式,需要额外的开辟一个与节点大小一样的空间,那么我们也可以采取遍历两次的方式,省去额外的空间代价
*
* @param head
* @return
*/
public ListNode middleNode(ListNode head) {
ListNode res = head;
int size = 0;
while (head != null) {
size++;
head = head.next;
}
int index = 0;
while (index < (size / 2)) {
res = res.next;
index++;
}
return res;
}
解法4:
快慢指针
/**
* 快慢指针
* 慢指针每次走一步,快指针每次走两步,因此快指针走完时,慢指针刚好走了一半,即是我们想要的结果
*
* @param head
* @return
*/
public ListNode middleNode(ListNode head) {
ListNode slowNode = head;
ListNode fastNode = head;
while (fastNode != null && fastNode.next != null) {
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
return slowNode;
}