快乐刷题(四)

链表中环的入口节点(中等)

可以使用快慢指针法或者遍历一遍通过哈希表判断是否出现过重复。
下面先实现快慢指针法:
快慢指针相遇后,慢指针和头指针分别向前移动,直至慢指针和头指针相遇,返回慢指针即入口节点

package org.meituan.leetcode;

/**
 * @projectName: codebetter
 * @package: org.meituan.leetcode
 * @className: DetectCycle
 * @author: fangjiayueyuan
 * @description: TODO
 * @date: 2023/5/4 下午10:10
 * @version: 1.0
 */
public class DetectCycle {
    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(3);
        ListNode listNode2 = new ListNode(2);
        ListNode listNode3 = new ListNode(0);
        ListNode listNode4 = new ListNode(-4);
//        ListNode listNode5 = new ListNode(2);

        listNode1.next=listNode2;
        listNode2.next=listNode3;
        listNode3.next=listNode4;
        listNode4.next=listNode1;

        ListNode output = new SolutionDetectCycle().detectCycle(listNode1);
        System.out.println(output.val);


    }
}

class SolutionDetectCycle {
    public ListNode detectCycle(ListNode head) {
        if(head== null) return null;
        ListNode fastNode = head;
        ListNode slowNode = head;
        ListNode startNode = head;

        while(fastNode!=null){
            if(fastNode.next != null && fastNode.next.next!=null){
                fastNode = fastNode.next.next;
            }else{
                return null;
            }
            if(slowNode.next != null){
                slowNode = slowNode.next;
            }else{
                return null;
            }
            if(fastNode==slowNode){
                break;
            }
        }

        while(startNode!=slowNode){
            startNode =  startNode.next;
            slowNode = slowNode.next;
        }

//        if(fastNode==null)return null;
//        if(fastNode==slowNode){
//            return slowNode.next;
//        }
        return slowNode;
    }
}

反转链表

采用循环和递归两种方式进行解题

循环

  • 循环的重点在于保存当前节点的下一个节点,为了防止多次使用.next把问题搞复杂,最好每个涉及到的节点都使用一个变量来维护,更加清晰。每次反转之后,pre节点的指针也需要向后移动。
  • 还有一处需要注意,if(head == null || head.next == null)要把head == null 写在前面,判断的时候会按照顺序来判断
package org.meituan.leetcode;

import java.util.List;

/**
 * @projectName: codebetter
 * @package: org.meituan.leetcode
 * @className: ReverseList
 * @author: fangjiayueyuan
 * @description: TODO
 * @date: 2023/5/4 下午3:54
 * @version: 1.0
 */
public class ReverseList {
    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(4);
        ListNode listNode2 = new ListNode(5);
        ListNode listNode3 = new ListNode(1);
        ListNode listNode4 = new ListNode(9);
        listNode1.next=listNode2;
        listNode2.next=listNode3;
        listNode3.next=listNode4;

        ListNode output = new SolutionReverseList().reverseList(listNode1);
        while(output != null){
            System.out.println(output.val);
            output= output.next;
        }

    }
}

class SolutionReverseList {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode node = head;
        ListNode nodePre = null;
        ListNode nodeNext = null;
        ListNode nodeLast = null;
        while(node != null){
            if(node.next == null){
                nodeLast = node;
            }
            nodeNext = node.next; //实现反转之前,先保存好下一个节点,防止链表断掉
            node.next = nodePre; // 实现反转

            nodePre = node;
            node = nodeNext;

        }
        return nodeLast;
    }
}

递归

递归的思考思路:
1、找出递归公式,有点类似于数学中的归纳法,所有的递归问题都可以用递推公式来表示。有了这个递推公式,我们就可以很轻松地将它改为递归代码;递归只能考虑当前层和下一层的关系,不能继续往下深入,继续深入就容易陷入思想的怪圈;
2、找到终止条件。
人脑几乎无法把递和归一步步想清楚(不是只有我想不清楚),一步步做递归是计算机擅长的事情,我们只需要把迭代条件和终止条件想明白告诉计算机即可!(参考
关于递归,这两个视频也很有用:
1)https://www.bilibili.com/video/BV1UD4y1Y769/
2)https://www.bilibili.com/video/BV18M411z7bb/

回归到题目本身,递归公式F(node) = F(node.next)+{递归之后的操作},假设一个链表为1->2->3,如果2<-3已经反转完成了F函数,下一步是需要把node.next的next指向node实现反转即1<-2,并让node.next指向null,否则链表将会成环即1->2且1<-2。
实现代码如下:

package org.meituan.leetcode;

import java.util.List;

/**
 * @projectName: codebetter
 * @package: org.meituan.leetcode
 * @className: ReverseList
 * @author: fangjiayueyuan
 * @description: TODO
 * @date: 2023/5/4 下午3:54
 * @version: 1.0
 */
public class ReverseList {
    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(4);
        ListNode listNode2 = new ListNode(5);
        ListNode listNode3 = new ListNode(1);
        ListNode listNode4 = new ListNode(9);
        listNode1.next=listNode2;
        listNode2.next=listNode3;
        listNode3.next=listNode4;

        ListNode output = new SolutionReverseList().reverseList(listNode1);
        while(output != null){
            System.out.println(output.val);
            output= output.next;
        }

    }
}

class SolutionReverseList {
    public ListNode reverseList(ListNode head) {
        if(head.next == null || head==null){
            return head;
        }
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}

合并两个排序的链表

分别采用循环、递归两种方法进行解题

循环

1、双指针:分别指向两个链表的节点
2、构造头指针:要构造两个头指针,一个标识新的链表的头节点的位置,一个新的链表中每个节点的位置。(不构造两个节点,想破头也没想出来解法。)

package org.meituan.leetcode;

/**
 * @projectName: codebetter
 * @package: org.meituan.leetcode
 * @className: MergeTwoLists
 * @author: fangjiayueyuan
 * @description: TODO
 * @date: 2023/5/4 下午5:18
 * @version: 1.0
 */
public class MergeTwoLists {
    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(3);
        ListNode listNode3 = new ListNode(5);
        ListNode listNode4 = new ListNode(7);
        listNode1.next=listNode2;
        listNode2.next=listNode3;
        listNode3.next=listNode4;

        ListNode listNode5 = new ListNode(1);
        ListNode listNode6 = new ListNode(3);
        ListNode listNode7 = new ListNode(5);
        ListNode listNode8 = new ListNode(7);
        listNode5.next=listNode6;
        listNode6.next=listNode7;
        listNode7.next=listNode8;

        ListNode output = new SolutionMergeTwoLists().mergeTwoLists(listNode1,listNode5);
        while(output != null){
            System.out.println(output.val);
            output= output.next;
        }

    }
}

class SolutionMergeTwoLists {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null)return l2;
        if(l2 == null) return l1;
        ListNode head = new ListNode(0);
        ListNode cur = head;

        while(l1 != null && l2 != null){
            if(l1.val<l2.val){
                cur.next = l1;
                l1 = l1.next;
            }else{
                cur.next=l2;
                l2 = l2.next;

            }
            cur = cur.next;
        }

        if(l1!=null){
            cur.next=l1;
        }
        else{
            cur.next=l2;

        }
        return head.next;
    }
}

递归

1、递推公式:
F(n)为合并两个链表,F(n)=初始状态+F(n-1),F(n-1)即拆解子问题,因为题目要求是按照递增的顺序,由于两条链表的头节点哪个更小是不确定的,由于初始状态不同,F(n-1)也不同。
l1更小时,F(n)为l1+F(n-1),F(n-1)即l1.next = mergeTwoLists(l1.next,l2);
否则:F(n)为l2+F(n-1),F(n-1)即l2.next = mergeTwoLists(l1,l2.next);

2、终止条件:终止条件一般为边界条件,即链表为空。链表为空,则合并后返回另一个链表头结点即可。
代码如下:

package org.meituan.leetcode;

/**
 * @projectName: codebetter
 * @package: org.meituan.leetcode
 * @className: MergeTwoLists
 * @author: fangjiayueyuan
 * @description: TODO
 * @date: 2023/5/4 下午5:18
 * @version: 1.0
 */
public class MergeTwoLists {
    public static void main(String[] args) {
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(3);
        ListNode listNode3 = new ListNode(5);
        ListNode listNode4 = new ListNode(7);
        listNode1.next=listNode2;
        listNode2.next=listNode3;
        listNode3.next=listNode4;

        ListNode listNode5 = new ListNode(1);
        ListNode listNode6 = new ListNode(3);
        ListNode listNode7 = new ListNode(5);
        ListNode listNode8 = new ListNode(7);
        listNode5.next=listNode6;
        listNode6.next=listNode7;
        listNode7.next=listNode8;

        ListNode output = new SolutionMergeTwoLists().mergeTwoLists(listNode1,listNode5);
        while(output != null){
            System.out.println(output.val);
            output= output.next;
        }

    }
}

class SolutionMergeTwoLists {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null)return l2;
        if(l2 == null) return l1;

        if(min(l1,l2)==l1){
            l1.next =  mergeTwoLists(l1.next,l2);
            return l1;
        }else {
            l2.next = mergeTwoLists(l1,l2.next);
            return l2;
        }
    }
    ListNode min(ListNode l1, ListNode l2){
        // 返回两个节点中节点值较小的节点
        if(l1.val<l2.val){
            return l1;
        }else{
            return l2;
        }
    }
}

树的子结构(中等)

1、
前置题目推荐:相同的树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSameTree(TreeNode A, TreeNode B) {
        if(A==null && B==null){
            return true; // 如果两条树相同则一定相同
        }
        if(A==null || B==null){
            return false; // 如果两条树只有一条为空则一定不同
        }
        return A.val==B.val && isSameTree(A.left,B.left) && isSameTree(A.right,B.right);

    }
}

前置题目2:另一棵树的子树

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root==null && subRoot==null){
            return true;
        }
        if(root==null && subRoot!=null){
            return false;
        }
        if(root!=null && subRoot==null){
            return true;
        }
        if(isSame(root,subRoot)){
            return true;
        }
        return isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
    }
    public boolean isSame(TreeNode root1,TreeNode root2){
        if(root1==null && root2==null){
            return true;
        }
        if(root1==null || root2==null){
            return false;
        }
        return root1.val==root2.val && isSame(root1.left,root2.left) && isSame(root1.right,root2.right);
    }
   
}

二叉树的镜像

采用递归的思路来解二叉树的问题
1、递归公式:
寻找子问题,把二叉树镜像就是分别把二叉树的左孩子镜像、二叉树的右孩子镜像;
子问题解决后,还需要把根节点的右孩子指向左孩子镜像,根节点的左孩子指向右孩子镜像即可。
2、终止条件:二叉树为空,返回空;二叉树只有根节点,返回根节点。

class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root==null)return null;
        TreeNode left = mirrorTree(root.left);
        TreeNode right = mirrorTree(root.right);
        root.left = right;
        root.right = left;
        return root;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值