剑指offer(16-18)题解

简介: 剑指offer(16-18)题解

16题解–合并两个排序的链表


题目描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

思路解析

这题逻辑其实本质上就是归并排序,就是元素的存取以及边界的判断条件有不同。

这里先贴上别人对于归并排序的一张模拟图:


20200805120137459.gif

其次就是懂得list.next=null与list=null的区别,list.next=null,说明当前list中还是有值的,所以我们会出现漏值的情况,list=null就说明当前list已经为空了值已经全部取出来了。

最后就是懂得在list==null的情况下我们在做list=list.next的运算时会报空指针异常,这个相信都能理解,所以我们必须加上条件判断语句避免报错。


源代码


import java.util.ArrayList;
import java.util.List;
public class Solution {
/*    public class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}*/
   public ListNode Merge(ListNode list1,ListNode list2) {
        List<ListNode>list3=new ArrayList<ListNode>();
       if(list1==null)
          return list2;
        if(list2==null)
          return list1;
        if(list1==null&&list2==null)
          return null;
        //这里如果写list.next!=null会出现元素没有取干净的情况
        while(list1!=null||list2!=null)
        {
            if(list1.val<list2.val)
            {
              list3.add(new ListNode(list1.val));
              //这里主要配合上面我们写的list!=null想对应的,如果不进行判断就会报空指针异常
              if(list1.next!=null)
                list1=list1.next;
              //这里主要是与下面我们检查链表是否还有剩余元素,如果这已经是该链表的最后一个元素
              //那么我们就需要将这个链表置为空,否则我们在下面重新遍历剩余链表元素时,这个剩余
              //元素会被再次计入,导致重复
              else 
              {
                list1=null;
                break;
              }
            }
            else 
            {
              list3.add(new ListNode(list2.val));
              if(list2.next!=null)
                list2=list2.next;
              else 
              {
                list2=null;
                break;
              }
            }
        }
         while(list1!=null)
        {
          list3.add(new ListNode(list1.val));
          if(list1.next!=null)
            list1=list1.next;
          //如果next为空就说明已经是最后一个元素了,并且我们上面已经添加过该元素了,所以直接跳出循环即可
          else 
            break;
        }
        while(list2!=null)
        {
          list3.add(new ListNode(list2.val));
          if(list2.next!=null)
            list2=list2.next;
          else 
            break;
        }
        //重新将我们的链表串起来
        for(int i=0;i<list3.size()-1;i++)
          list3.get(i).next=list3.get(i+1);
        return list3.get(0);
    }
}


17题解–树的子结构


题目描述

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路解析

这题博主主要是看了题解之后写的

首先我们要注意一个概念就是子树和子结构这两个概念

举个例子来说明:


20200805141751578.png


这就代表我们只需要保证root2是root1的一个部分就够。

接下来是大体思路:


我们首先要创建一个函数用来帮助我们判断root1的当前节点下是否存在root2这样一个子结构。

我们递归去检查root1的左孩子与root2的左孩子是否也符合同理右孩子

在这个检查过程中只要出现一个值不对应,就直接说明不存在,直接返回。

如果出现root2为空的情况就说明已经递归比较到最后发现root2空了说明所有的元素都已经比较匹配了所以说明存在这样一个子结构。

但是如果出现root1比root2先空的情况就说明不存在这样一个子结构。


主函数我们从root1的根节点开始与root2进行比较,如果匹配成功那么久返回为TRUE,如果匹配不成功,那么我们就递归用根节点的左右孩子去匹配,一直匹配到最后,再将flag返回即可。


源代码


/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
    boolean flag=false;
    if(root1==null||root2==null)
      return false;
    //匹配子结构
    if(root1.val==root2.val)
      flag=hasroot(root1, root2);
    //递归匹配左孩子与子结构
    if(!flag) 
            flag=HasSubtree(root1.left, root2);
        //递归匹配右孩子与子结构
    if(!flag) 
            flag=HasSubtree(root1.right, root2);
    return flag;
    }
  public boolean hasroot(TreeNode root1,TreeNode root2)
  {
      //root2先空说明已经全部匹配出来,说明存在该子结构
    if(root2==null)
      return true;
      //root1先空就说明还未匹配出子结构,但是root1已经没有元素了,说明root2剩下的元素都不存在
      //所以不存在该子结构
    if(root1==null)
      return false;
        if(root1.val!=root2.val)
            return false;
        //递归减产两者对应的左右孩子节点
    return hasroot(root1.left, root2.left)&&hasroot(root1.right, root2.right);
  }
}


18题解–二叉树的镜像


题目描述

操作给定的二叉树,将其变换为源二叉树的镜像。

输入描述:

二叉树的镜像定义:源二叉树


20200805100554916.png


思路解析

主要思想就是递归调用稍微注意一下终止条件root=null,否则root为null还在执行交换的动作会报空指针异常。

源代码


public class Solution {
  public void Mirror(TreeNode root) {
    if(root==null)
            return;
    TreeNode node=root.left;
    root.left=root.right;
    root.right=node;
    Mirror(root.left);
    Mirror(root.right);
    }
}
相关文章
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的自适应学习算法研究与应用
在深度学习领域,传统的静态模型在处理动态环境和非平稳数据时面临挑战。本文探讨了自适应学习算法在深度学习中的重要性及其应用。通过分析自适应学习算法在模型参数、损失函数和数据分布上的应用,展示了其在提升模型鲁棒性和泛化能力方面的潜力。具体讨论了几种代表性的自适应学习方法,并探索了它们在现实世界中的应用案例,从而展示了其在处理复杂问题和动态数据中的效果。
932 27
|
机器学习/深度学习 人工智能 自然语言处理
让非算法同学也能了解 ChatGPT 等相关大模型
让非算法同学也能了解 ChatGPT 等相关大模型
291 3
让非算法同学也能了解 ChatGPT 等相关大模型
|
设计模式 敏捷开发 监控
深入探究软件自动化测试的策略与实践深入理解PHP中的命名空间
【5月更文挑战第27天】 在软件开发周期中,确保代码质量是至关重要的一环。随着敏捷开发和持续集成的普及,自动化测试成为提升效率和保障软件质量的重要手段。本文将详细探讨自动化测试策略的制定、工具选择以及在实际项目中的执行过程。我们将从自动化测试的基本原则出发,分析不同类型和级别的自动化测试案例,并结合具体实例,讨论如何优化测试流程,减少冗余,提高测试覆盖率和准确性。通过阅读本文,读者将获得一套实用的自动化测试实施框架,以支持其在快速迭代的开发环境中维护高水平的软件品质。 【5月更文挑战第27天】在本文中,我们将探讨PHP中的命名空间(namespace)的概念、用途和实现方式。通过详细解释命名
|
SQL Kubernetes 调度
DataphinV3.14 Flink SQL任务支持基于Session集群调试,模拟生产代码逻辑的调试效果
实时研发一直以来的都是通过local-debug的方式来调试开发中的Flink SQL任务,该方式有如下不足: 1. 支持的采样数据有限,且非是流式数据的调试。 2. 手动上传构造数据的方式较为繁琐,局限性较大。 为便于Flink SQL任务的调试,DataphinV3.14版本支持Flink SQL任务基于Session集群调试,期望做到像离线即席查询般方便地获取实时任务的输出结果,方便用户对线上的真实数据进行代码逻辑上的调试。
317 2
|
存储 前端开发 应用服务中间件
区分WEB服务器与数据服务器
WEB服务器和数据服务器是两个不同的概念噢,它们分别承担着不同的任务和功能。
723 0
区分WEB服务器与数据服务器
|
缓存 供应链 调度
系统从初期到支撑亿级流量,都经历了哪些架构上的演变?
随着互联网的发展,互联网企业的业务也在不断的飞速发展,进而导致系统的架构也在不断的发生着变化。总体来说,系统的架构大致经历了:单体应用架构—>垂直应用架构—>分布式架构—>SOA架构—>微服务架构的演变。当然,很多互联网企业的系统架构已经向Service Mesh(服务化网格)演变。今天,我们就一起来聊聊关于系统架构的演变这个话题。
381 0
系统从初期到支撑亿级流量,都经历了哪些架构上的演变?
|
SQL 安全 关系型数据库
MySQL数据库(24):用户权限管理
MySQL数据库(24):用户权限管理
176 0
|
Kotlin
《Kotlin极简教程》第3章 Kotlin语言基础 配图
螢幕快照 2017-06-11 02.17.49.png 螢幕快照 2017-06-11 02.54.03.png
1046 0
|
4天前
|
存储 JavaScript 前端开发
JavaScript基础
本节讲解JavaScript基础核心知识:涵盖值类型与引用类型区别、typeof检测类型及局限性、===与==差异及应用场景、内置函数与对象、原型链五规则、属性查找机制、instanceof原理,以及this指向和箭头函数中this的绑定时机。重点突出类型判断、原型继承与this机制,助力深入理解JS面向对象机制。(238字)