链表——刷题笔记

反转链表

递归方法套路:

  1. 明确递归函数的定义
    1.1 输入是什么?
    1.2 要做什么?
    1.3 输出是什么?
    利用这个定义推导最终结果,绝不要跳入递归的细节。
  2. 明确base case(跳出条件)
  3. 最后的处理

在这里插入图片描述

//递归
class Solution {
// 1. 明确递归函数的定义   
// 	1.1 输入是什么?   一个链表节点head
// 	1.2 要做什么?	将「以 head 为起点」的链表反转
//	1.3 输出是什么?	返回反转之后的头结点
    public ListNode reverseList(ListNode head) {
    	//2. 明确base case(跳出条件)
        if(head == null || head.next == null) return head;
        ListNode last = reverseList(head.next);	//last就是输出
        // 3. 最后的处理
        head.next.next = head;
        head.next = null;
        
        return last;
    }
}

//迭代
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null) return null;
        ListNode pre = null, cur = head, tmp = null;
        while(cur != null){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;            
        }
        return pre;
    }
}

反转链表II

在这里插入图片描述

class Solution {
    public ListNode successor = null;
    public ListNode reverseBetween(ListNode head, int m, int n) {
        if(head == null) return head;
        if(m == 1){
            return reverseN(head, n);
        }
        //向后遍历到反转的起点,调用reverseN()
        head.next = reverseBetween(head.next, m-1, n-1);
        return head;
    }

    //1.明确递归函数定义,reverseN(),反转链表的前n个元素,输出返回 反转后的节点
    public ListNode reverseN(ListNode head, int n){
        //2.明确base case,递归到最后的情况
        if(n == 1){
            successor = head.next;//找到后继节点
            return head;
        }
        ListNode last = reverseN(head.next, n-1);//反转长度为n-1,从head的下一个节点开始的链表
        //3.最后的处理,拼接,三部分:head,head下一个元素的反转链表(长度n-1),head的后继节点
        head.next.next = head;
        head.next = successor;

        return last;
    }
}

K 个一组翻转链表

在这里插入图片描述

class Solution {
    //1.明确递归函数的定义:
    //输入:一个链表的头节点,数字k
    //做什么:K个一组反转链表
    //输出:反转后的链表头节点
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null) return null;
        ListNode a = head, b = head;
        //base case :数目不够k个,不进行反转操作,直接返回a
        for(int i=0; i<k; i++){
            if(b == null) return a;
            b = b.next;
        }
        ListNode newHead = reverseK(a, b);//反转后新的头节点,1->2的话,现在就是2
        a.next = reverseKGroup(b, k);//a还是1,a后继节点继续递归反转
        return newHead;
    }
	//反转以a开头以
    public ListNode reverseK(ListNode a, ListNode b){
        if(a == null) return null;
        ListNode pre = null, cur = a, tmp = null;
        while(cur != b){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}

判断回文链表

在这里插入图片描述
O(n)方法

//很巧妙的思路,利用递归后续遍历链表,其实就是 栈 的思想
class Solution {
    public ListNode left = null;
    public boolean isPalindrome(ListNode head) {
        left = head;
        return digui(head);
    }

    public boolean digui(ListNode right){
        if(right == null) return true;
        //boolean res = digui(right.next) && (left.val == right.val);
        boolean res = digui(right.next);
        //这里就是后续遍历的代码,递归结束弹栈的时候,会从后向前一次遍历链表的值
        res = res&& (left.val == right.val);
        left = left.next;
        return res;
    }
}

O(1)方法

//关键思想是利用快慢指针,找到最中间的对称点,将对称点后面的链表进行反转,然后进行遍历比较即可
//这样就是O(1)了
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 left = head;
        ListNode right = reverse(slow);
        while(right != null){
            if(left.val != right.val) return false;
            else {
                left = left.next;
                right = right.next;
            }
        }
        return true;
    }

    public ListNode reverse(ListNode head){
        if(head == null) return head;
        ListNode pre = null, cur = head, tmp = null;
        while(cur != null){
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值