leetcode 链表题目 206. 反转链表 92. 反转链表 II 25. K 个一组翻转链表

递归666。

206. 反转链表

给你单链表的头节点 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;
    }
}

在这里插入图片描述

92. 反转链表 II
在这里插入图片描述

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)

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值