递归666。
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
链表中节点的数目范围是 [0, 5000]
-5000 <= Node.val <= 5000
解法一 迭代 双指针方法
class Solution {
public ListNode reverseList(ListNode head) {
//定义一个前驱节点和当前节点
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode next = cur .next;
// 讲当前节点指向pre节点
cur .next = pre ;
// 将pre和head向后面移动
pre = cur ;
cur = next;
}
return pre;
}
}
解法二 递归
class Solution {
public ListNode reverseList(ListNode head) {
// 递归到最后一层次后的返回条件。
if (head == null || head.next == null) {
return head;
}
ListNode last = reverseList(head.next);
head.next.next = head;
head.next = null;
return last;
}
}
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummyNode = new ListNode(-1, head), pre = dummyNode;
for (int i = 1; i < left; i++) {
pre = pre.next;
}
ListNode cur = pre.next;
//头插法
for (int i = 0; i < right - left; i++) {
ListNode next = cur.next;
cur.next = cur.next.next;
next.next = pre.next;
pre.next = next;
}
return dummyNode.next;
}
}
25. K 个一组翻转链表
**解法一 头插法 **
和 92题有点像。得在循环中找出end节点之后,再用头插法。一组反转之后,更新 pre和cur的值,继续下一组。
时间复杂度为O(n) ,空间复杂度为O(1)
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (k == 1) {
return head;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode pre = dummy, cur = head;
while (true) {
ListNode end = cur;
for (int i = 1; i < k; i++) {
end = end.next;
if (end == null) {
//剩下的节点不足K的倍数,直接返回.
return dummy.next;
}
}
//头插法
for (; pre.next != end;) {
ListNode next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
//pre 和 cur移动到下一组.
pre = cur;
cur = cur.next;
if (cur == null) {
//链表长度刚刚好是K的倍数。cur为NULL,直接返回.
return dummy.next;
}
}
}
}
**解法二 递归 **
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
if (head == null) {
return null;
}
ListNode end = head;
for (int i = 1; i < k; i++) {
end = end.next;
//长度不够说明不需要反转
if (end == null) {
return head;
}
}
//因为end经过reverse后 end.next会变成前一个节点,所以先把下一组链表的头节点存一下。
ListNode nextHead = end.next;
//反转当前组
ListNode reverse = reverse(head, end);
//反转后面所有的节点,并返回头节点
ListNode listNode = reverseKGroup(nextHead, k);
//当前的头节点,经过reverse变成尾节点。他指向的是NULL,所以要指向下一组反转后返回的头节点
head.next = listNode;
return reverse;
}
public ListNode reverse(ListNode head, ListNode end) {
ListNode cur = head;
ListNode pre = end.next;
while (pre != end) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return end;
}
}
234. 回文链表
解法一 递归
在递归函数后面加操作代码,就可以在递归到最后一层返回的时候,从最后面往前拿数据,
定义一个实例变量end,和 递归的head节点 对比就可以出结果了,结束前 将end更新为next节点。
class Solution {
ListNode end;
public boolean isPalindrome(ListNode head) {
if (end == null) {
end = head;
}
if (head == null) {
return true;
}
Boolean flag = isPalindrome(head.next) && (head.val == end.val);
end = end.next;
return flag;
}
}
解法二 快慢指针 + 反转
快慢指针 找出对称的头节点。 在反转后面的。最后比较。
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
slow = slow.next;
}
//反转
ListNode end = reverse(slow);
//遍历比较
while (end != null) {
if (end.val != head.val) {
return false;
}
end = end.next;
head = head.next;
}
return true;
}
public ListNode reverse(ListNode head) {
ListNode pre = null;
while (head != null) {
ListNode next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
}
头插法 快慢指针 递归(NB)