输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}
}
相关问题,92,83,86,328,2,445
class Solution {
ListNode successor = null; // 后驱节点
// 反转以 head 为起点的 n 个节点,返回新的头结点
ListNode reverseN(ListNode head, int n) {
if (n == 1) {
// 记录第 n + 1 个节点
successor = head.next;
return head;
}
// 以 head.next 为起点,需要反转前 n - 1 个节点
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
// 让反转之后的 head 节点和后面的节点连起来
head.next = successor;
return last;
}
public ListNode reverseBetween(ListNode head, int m, int n) {
if (m == 1) {
return reverseN(head, n);
}
// 前进到反转的起点触发 base case
head.next = reverseBetween(head.next, m - 1, n - 1);
return head;
}
}
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode current = head;
if (head == null) {
return null;
}
while (current != null && current.next != null) {
if (current.next.val == current.val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
}
class Solution {
public ListNode partition(ListNode head, int x) {
if (head == null || head.next == null) {
return head;
}
// 构造两个链表,然后合并
ListNode left = new ListNode(-1);
ListNode right = new ListNode(-1);
ListNode leftHead = left;
ListNode rightHead = right;
while (head != null) {
if (head.val < x) {
left.next = head;
left = left.next;
} else {
right.next = head;
right = right.next;
}
head = head.next;
}
left.next = rightHead.next;
right.next = null;
return leftHead.next;
}
}
设立链表的虚拟头结点
删除链表中等于给定值 val 的所有节点。
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
//创建一个虚拟头结点(防止要删除的节点就是头节点)
ListNode dummyNode=new ListNode(val-1);
//虚拟头结点指向当前节点。这样原来的节点就有了头节点
dummyNode.next=head;
ListNode cur=dummyNode;
//确保当前结点后还有结点
while(cur.next!=null){
if(cur.next.val==val){
cur.next=cur.next.next;
}else{
cur=cur.next;
}
}
//最终返回虚拟头节点的next
return dummyNode.next;
}
}
相关问题82,21
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) {
return head;
}
//虚拟头结点
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode prev = dummy;
ListNode slow = dummy.next;// 慢指针
ListNode fast = dummy.next.next;// 快指针
while (fast != null) {
if (slow.val == fast.val) {// 找到相同的点
fast = fast.next;// fast向后移继续找有没有相同的
} else {
if (slow.next != fast) {// 如果慢节点的下一个节点不是快指针
// 说明这中间都是相同的,删除相同的点
ListNode temp = fast;
fast = fast.next;
slow = temp;
prev.next = slow;
} else {
//否则说明还没有重复,继续
fast = fast.next;
slow = slow.next;
prev = prev.next;
}
}
}
if (slow.next != null) {
// 此时快指针已经指到末尾了,如果慢指针没有到末尾,
// 则说明慢指针后面的全部都是重复元素,则全部删除
prev.next = null;
}
return dummy.next;
}
}
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
给定 1->2->3->4, 你应该返回 2->1->4->3.
一对节点的交换
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode p = dummyHead;
while (p.next != null && p.next.next != null) {
ListNode node1 = p.next;
ListNode node2 = node1.next;
ListNode next = node2.next;
node2.next = node1;
node1.next = next;
p.next = node2;
p = node1;
}
return dummyHead.next;
}
}
相关问题25,148
class Solution {
// 归并排序
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode fast = head.next, slow = head;
// 快指针和慢指针找到中间点
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// 中间点
ListNode tmp = slow.next;
slow.next = null;
// 左右递归
ListNode left = sortList(head);
ListNode right = sortList(tmp);
ListNode h = new ListNode(0);
ListNode res = h;
// 排序
while (left != null && right != null) {
if (left.val < right.val) {
h.next = left;
left = left.next;
} else {
h.next = right;
right = right.next;
}
h = h.next;
}
h.next = left != null ? left : right;
return res.next;
}
}
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
不能像之前的问题一样,因为无法拿到当前节点的上一个节点,只能操作当前节点的指针,所以讲当前节点的下一个节点的值复制给当前节点,然后删除掉下一个节点
class Solution {
public void deleteNode(ListNode node) {
if (node == null) {
return;
}
if (node.next == null) {
node = null;
}
node.val = node.next.val;
ListNode delNode = node.next;
node.next = node.next.next;
return;
}
}
双指针技术
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
- 先遍历一遍链表计算长度,在遍历一遍删除倒数第n个节点O(n)
- 只遍历一遍的方法是设置两个指针,间距是n,从头开始遍历,第二个指针到达末尾时候就找到了倒数第n个
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode p = dummyHead;
ListNode q = dummyHead;
for (int i = 0; i < n + 1; i++) {
if (q != null) {
q = q.next;
}
}
while (q != null) {
p = p.next;
q = q.next;
}
ListNode delNode = p.next;
p.next = delNode.next;
return dummyHead.next;
}
}
相关问题61,143,234
class Solution {
// 先将链表闭合成环
// 找到相应的位置断开这个环,确定新的链表头和链表尾
public ListNode rotateRight(ListNode head, int k) {
if (head == null) {
return null;
}
if (head.next == null) {
return head;
}
int n;// n是链表长度
ListNode oldTail = head;// 找到末尾节点
for (n = 1; oldTail.next != null; n++) {
oldTail = oldTail.next;
}
// 将链表闭合成环
oldTail.next = head;
// 新的末尾节点
ListNode newTail = head;
// 新的链表尾就在头的前面,位于位置 n-k-1(我们这里假设 k < n)
// 如果 k >= n时,k 可以被写成 k = (k // n) * n + k % n 两者加和的形式,
// 其中前面的部分不影响最终的结果,因此只需要考虑 k%n 的部分,这个值一定比 n 小。
// 新的尾部,第 (n - k % n - 1) 个节点
// 新的链表头是第 (n - k % n) 个节点
for (int i = 0; i < n - k % n - 1; i++) {
newTail = newTail.next;
}
ListNode newHead = newTail.next;// 新的头节点
newTail.next = null;// 断开环
return newHead;
}
}
class Solution {
// 第一步,将链表平均分成两半
// 第二步,将第二个链表逆序
// 第三步,依次连接两个链表
public void reorderList(ListNode head) {
if (head == null || head.next == null || head.next.next == null) {
return;
}
// 找中点,链表分成两个
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode newHead = slow.next;
slow.next = null;// 防止成环
// 第二个链表倒置
newHead = reverseList(newHead);
// 链表节点依次连接
while (newHead != null) {
ListNode temp = newHead.next;
newHead.next = head.next;
head.next = newHead;
head = newHead.next;
newHead = temp;
}
}
private ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
ListNode tail = head;
head = head.next;
tail.next = null;
while (head != null) {
ListNode temp = head.next;
head.next = tail;
tail = head;
head = temp;
}
return tail;
}
}
class Solution {
public boolean isPalindrome(ListNode head) {
// 边界条件:空链表或只有一个节点的链表
if (head == null || head.next == null) {
return true;
}
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode slow = dummyNode;
ListNode fast = dummyNode;
// 找到中间点
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// fast指针置于下半段链表的起点
fast = slow.next;
// 断开前后两个链表
slow.next = null;
// slow指针置于前半段链表的起点
slow = dummyNode.next;
// 反转后半段链表
ListNode pre = null; // 保存指针前一节点的信息,用于反转
while (fast != null) {
ListNode nextTemp = fast.next;
fast.next = pre;
pre = fast;
fast = nextTemp;
}
// 前后半链表逐一比较,当链表长度为奇数时前半段链表长度比后半段多1,所以以后半段为准
while (pre != null) {
if (slow.val != pre.val) {
return false;
}
slow = slow.next;
pre = pre.next;
}
return true;
}
}