剑指offer(61-67)题解

剑指offer(61-67)题解

  • 61题解--序列化二叉树
  • 62题解--二叉搜索树的第K个结点
  • 63题解--数据流中的中位数
  • 64题解--滑动窗口的最大值
  • 65题解--矩阵中的路径
  • 66题解--机器人的运动范围
  • 67题解--剪绳子

61题解–序列化二叉树

题目描述

请实现两个函数,分别用来序列化和反序列化二叉树 二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。

二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

例如,我们可以把一个只有根节点为1的二叉树序列化为"1,",然后通过自己的函数来解析回这个二叉树

思路解析

这里其实方法有很多,你可以选择中序,前序,后序,层序遍历来保存当前树的结构 这里我选择的是通过前序遍历将节点存进来,并且在这个过程中,空节点也是要存进来的,否则还是不能序列化。举下面这个例子:

源代码

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
 String Serialize(TreeNode root) {
        if(root == null)
            return "";
        StringBuilder sb = new StringBuilder();
        Serialize2(root, sb);
        return sb.toString();
    }
     
    void Serialize2(TreeNode root, StringBuilder sb) {
        if(root == null) {
            sb.append("#,");
            return;
        }
        sb.append(root.val);
        sb.append(',');
        Serialize2(root.left, sb);
        Serialize2(root.right, sb);
    }
     
    int index = -1;
     
    TreeNode Deserialize(String str) {
        if(str.length() == 0)
            return null;
        String[] strs = str.split(",");
        return Deserialize2(strs);
    }  
     
    TreeNode Deserialize2(String[] strs) {
        index++;
        if(!strs[index].equals("#")) {
            TreeNode root = new TreeNode(0);     
            root.val = Integer.parseInt(strs[index]);
            root.left = Deserialize2(strs);
            root.right = Deserialize2(strs);
            return root;
        }
        return null;
    }
}

62题解–二叉搜索树的第K个结点

题目描述

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

思路解析

还是之前二叉排序树的中序序列是一个升序序列,所以我们完全可以将该二叉树的中序序列遍历出来,之后直接取出来即可。

源代码

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}
*/
import java.util.ArrayList;
public class Solution {
  ArrayList<TreeNode>list=new ArrayList<TreeNode>();
	public void Print(TreeNode pRoot)
    {
		if(pRoot.left!=null)
			Print(pRoot.left);
        list.add(pRoot);
        if(pRoot.right!=null)
        	Print(pRoot.right);
    }
	
	TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot==null)
			return null;
        Print(pRoot);
        if(k>list.size()||k==0)
        	return null;
        return list.get(k-1);
    }
}

63题解–数据流中的中位数

题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

思路解析

这里只要稍微注意一下,他是每次添加就计算一次中位值,所以必须每次添加完就进行排序操作,其他的计算中位数,大家都会的。

源代码

import java.util.ArrayList;
import java.util.Collections;
public class Solution {
    ArrayList<Integer>list=new ArrayList<Integer>();
	public  void Insert(Integer num) 
	{
	    list.add(num);
	    Collections.sort(list);
    }

    public Double GetMedian() 
    {
    	double num=0.0;
    	if(list.size()%2!=0)
    	{
    		num=list.get(list.size()/2);
    	}
    	else 
    	{
    		num+=list.get(list.size()/2);
    		num+=list.get(list.size()/2-1);
    		num/=2;
    	}
    	return num;
    }
}

64题解–滑动窗口的最大值

题目描述

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。 窗口大于数组长度的时候,返回空

思路解析

与上面一题一样的道理,每次操作完记得计算结果。

源代码

import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    public int max(int []num) 
	{
		Arrays.sort(num);
		return num[num.length-1];
	}
	 public ArrayList<Integer> maxInWindows(int [] num, int size)
	 {
	      ArrayList<Integer>list=new ArrayList<Integer>();
	      if(size>num.length)
	    	  return list;
         if(size==0)
	    	  return list;
	      for(int i=0;i<num.length-size+1;i++)
	    	  list.add(max(Arrays.copyOfRange(num, i, i+size)));
	      return list;
	 }
}

65题解–矩阵中的路径

题目描述

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如

矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

思路解析

这题本质上也是一道搜索的题目,和迷宫类似,只要有搜索的模板,然后判断是否越界以及把字符判断的条件加上就行了

源代码

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                boolean[] flag = new boolean[matrix.length];
                if(hasPath(matrix, rows, cols, str, i, j, flag, 0)) return true;
            }
        }
        return false;
    }

    public boolean hasPath(char[] matrix, int rows, int cols, char[] str, int i, int j, boolean[] flag, int k){
        int index = i * cols + j;
        if(i < 0 || j < 0 || i >= rows || j >= cols || flag[index] == true || matrix[index] != str[k]) return false;
        if(k == str.length - 1) return true;
        flag[index] = true;
        if(hasPath(matrix, rows, cols, str, i - 1, j, flag, k + 1)
        ||hasPath(matrix, rows, cols, str, i + 1, j, flag, k + 1)
        ||hasPath(matrix, rows, cols, str, i, j - 1, flag, k + 1)
        ||hasPath(matrix, rows, cols, str, i, j + 1, flag, k + 1)) return true;
        
        return false;
    }


}

66题解–机器人的运动范围

题目描述

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

思路解析

这题本质就是一条搜索,搜索过程中不断判断是否越界,是否符合我们需要的条件。

源代码

public class Solution {
    public int movingCount(int threshold, int rows, int cols) {
        if (rows <= 0 || cols <= 0 || threshold < 0)
            return 0;

        boolean[][] isVisited = new boolean[rows][cols];
        int count = movingCountCore(threshold, rows, cols, 0, 0, isVisited);
        return count;
    }

    private int movingCountCore(int threshold,int rows,int cols,
                                int row,int col, boolean[][] isVisited) {
        //是否上下左右越界以及位求和是不是满足我们的条件以及是否访问过了
        if (row < 0 || col < 0 || row >= rows || col >= cols || isVisited[row][col]
                || cal(row) + cal(col) > threshold)
            return 0;
        //满足条件,将它标记为已经访问过
        isVisited[row][col] = true;
        return 1 + movingCountCore(threshold, rows, cols, row - 1, col, isVisited)
                + movingCountCore(threshold, rows, cols, row + 1, col, isVisited)
                + movingCountCore(threshold, rows, cols, row, col - 1, isVisited)
                + movingCountCore(threshold, rows, cols, row, col + 1, isVisited);
    }

    private int cal(int num) {
        int sum = 0;
        while (num > 0) {
            sum += num % 10;
            num /= 10;
        }
        return sum;
    }
}

67题解–剪绳子

题目描述

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。 输入描述: 输入一个数n,意义见题面。(2 <= n <= 60) 输出描述: 输出答案。 示例1 输入 复制 8 输出 复制 18

思路解析

这里我想到的肯定是剪成每段相等,那样乘积应该是最大的吗,但是又不可能每次都出现相等的情况。 如果我们按照如下的策略来剪绳子,则得到的各个段绳子的长度的乘积将最大:当n>=5时,我们尽可能多的剪长度为3的绳子;当剩下的绳子长度为4时,把绳子剪成两段长度为2的绳子。

源代码

public class Solution {
   public int cutRope(int target){
        int a = 0;
        int c = 0;
        int maxValue = 2;
         
        if (target == 2){
            return 1;
        }
        if (target == 3) {
           return 2;
       }
        if (target % 3 == 0){
            maxValue = (int)Math.pow(3,target / 3);
        } else{
            a = target - 2;
            c = a % 3;
             
            maxValue = maxValue * (int)Math.pow(3,a / 3);
            if(0 != c){
                maxValue = maxValue *c;
            }
        }
         
        return maxValue;
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 蓝桥杯 k好数 java版

    如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数。求L位K进制数中K好数的数目。例如K = 4,L = 2的时候,所有...

    萌萌哒的瓤瓤
  • 剑指offer(41-50)题解

    既然有了通项公式,那么其实我们也能推出这样一个结论,sum如果在n区间长的连续区间内满足,那么这个n区间长的区间是唯一的,不会存在第二个n长的连续区间满足,...

    萌萌哒的瓤瓤
  • 2015年javaB组1-4题解析与理解

    X老板脾气古怪,他们公司的电话分机号都是3位数,老板规定,所有号码必须是降序排列,且不能有重复的数位。比如:

    萌萌哒的瓤瓤
  • BZOJ3624: [Apio2008]免费道路(最小生成树)

    这棵树上有一些0边是必须要选的,我们先把他们找出来,如果数量$\geqslant k$显然无解

    attack
  • 1019 数字黑洞 (20 分)

    给定任一个各位数字不完全相同的 4 位正整数,如果我们先把 4 个数字按非递增排序,再按非递减排序,然后用第 1 个数字减第 2 个数字,将得到一个新的数字。一...

    可爱见见
  • LWC 61:738. Monotone Increasing Digits

    LWC 61:738. Monotone Increasing Digits 传送门:738. Monotone Increasing Digits Probl...

    用户1147447
  • 欧拉计划 Problem7

    题目: 第10001个素数 列出前6个素数,它们分别是2、3、5、7、11和13。我们可以看出,第6个素数是13。

    用户4492257
  • C语言基础 - 输出1-100万之间的素数

    gwk_iOS
  • 湖南大学程序设计竞赛新生赛(重现赛)

    题目链接—点我开启传送门哦! A.题意:就是求任意两个斐波那契数列的最大公约数!

    用户7727433
  • LeetCode 12. Integer to Roman

    ShenduCC

扫码关注云+社区

领取腾讯云代金券