1、重建二叉树

根据二叉树的前序遍历和中序遍历的结果,重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

preorder = [3,9,20,15,7]、inorder = [9,3,15,20,7]

1.1 分析

前序遍历的第一个值为根节点的值使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。

1.2 代码实现

static class TreeNode{int value;TreeNode left;TreeNode right;public TreeNode(int value) {this.value=value;}
}
private Map<Integer, Integer> indexForInOrders = new HashMap<>();
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {for (int i = 0; i < in.length; i++)indexForInOrders.put(in[i], i);//将前缀序列放入Map中,便于后面依据值得到它的indexreturn reConstructBinaryTree(pre, 0, pre.length - 1, 0);
}
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) {if (preL > preR)return null;TreeNode root = new TreeNode(pre[preL]);int inIndex = indexForInOrders.get(root.value);int leftTreeSize = inIndex - inL;root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL);root.right = reConstructBinaryTree(pre, preL + leftTreeSize+ 1, preR, inL + leftTreeSize + 1);return root;
}

2.斐波那契数列

求斐波那契数列的第 n 项,n <= 39。

2.1 分析

如果使用递归求解,会重复计算一些子问题。例如,计算 f(10) 需要计算 f(9) 和f(8),计算 f(9) 需要计算 f(8) 和 f(7),可以看到 f(8) 被重复计算了。

2.2 代码实现

2.2.1 递归

递归是将一个问题划分成多个子问题求解

public static int process(int i) {if(i==0||i==1)return i;return process(i-1)+process(i-2);
}

2.2.2 动态规划

动态规划也是将一个问题划分成多个子问题求解,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。

public static int process1(int n) {if (n <= 1)return n;int[] fib = new int[n + 1];//0~n,第n+1个即fib[n]存的是最终的结果fib[1] = 1;for (int i = 2; i <= n; i++)fib[i] = fib[i - 1] + fib[i - 2];return fib[n];
}

2.2.3 改进1

考虑到第 i 项只与第 i-1 和第 i-2 项有关,因此只需要存储前两项的值就能求解第 i项,从而将空间复杂度由 O(N) 降低为 O(1)

public int process2(int n) {if (n <= 1)return n;int pre2 = 0, pre1 = 1;int fib = 0;for (int i = 2; i <= n; i++) {fib = pre2 + pre1;pre2 = pre1;pre1 = fib;} return fib;
}

2.2.4 改进2

由于待求解的 n 小于 40,因此可以将前 40 项的结果先进行计算,之后就能以O(1) 时间复杂度得到第 n 项的值了。

public class Solution {private int[] fib = new int[40];public Solution() {fib[1] = 1;fib[2] = 2;for (int i = 2; i < fib.length; i++)fib[i] = fib[i - 1] + fib[i - 2];} public int Fibonacci(int n) {return fib[n];}
}

3.跳台阶

一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

3.1 分析

总共有n级台阶,f(n)中跳法。如果第一次跳1级,那么f(n)=f(n-1);若跳2级,则f(n)=f(n-2)。总:f(n)=f(n-1)+f(n-2)——斐波那契数列

3.2 代码实现

public int JumpFloor(int n) {if (n <= 2)return n;int pre2 = 1, pre1 = 2;int result = 1;for (int i = 2; i < n; i++) {result = pre2 + pre1;pre2 = pre1;pre1 = result;} return result;
}

4.矩形覆盖

我们可以用 2*1 的小矩形横着或者竖着去覆盖更大的矩形。

请问用 n 个 2*1 的小矩形无重叠地覆盖一个 2*n 的大矩形,总共有多少种方法?

4.1 分析

将2*n这个大矩形,看成一个n个矩形线性排列,然后一次可以用一个小1*1的矩形覆盖(即:2*1的矩形竖着),也可以用2*1的矩形覆盖(2*1的矩形横着)。这就和跳台阶一样。如图所示:

4.2 代码实现

public int RectCover(int n) {if (n <= 2)return n;int pre2 = 1, pre1 = 2;int result = 0;for (int i = 3; i <= n; i++) {result = pre2 + pre1;pre2 = pre1;pre1 = result;} return result;
}

5.变态跳台阶

一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级... 它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

5.1 分析(原博)

用f(n)表示青蛙跳上n阶台阶的跳法数,设定f(0) = 1;

当n = 1 时,只有一种跳的方式,一阶跳,f(1) = f(0) =1;

当n = 2 时,有两种跳的方式,一阶跳和两阶跳,f(2) = f(1) + f(0) = 2;

当n = 3 时,有三种跳的方式,第一次跳出一阶后,后面还有f(3-1)中跳法; 第一次跳出二阶后,后面还有f(3-2)中跳法;第一次跳出三阶后,后面还有f(3-3)中跳法,f(3) = f(2) + f(1) + f(0) = 4;

当n = n 时,第一次跳出一阶后,后面还有f(n-1)中跳法; 第一次跳出二阶后,后面还有f(n-2)中跳法......第一次跳出n阶后,后面还有 f(n-n)中跳法,即:

f(n) = f(n-1) + f(n-2) + f(n-3) + ... + f(n-n) = f(0) + f(1) + f(2) + ... + f(n-1)

又因为 f(n-1) = f(0) + f(2) + f(3) + ... + f(n-2)

两式相减得:f(n) = 2 * f(n-1)    ( n >= 2)

|  0,n = 0

f(n)   =       |  1, n = 1

|  2 * f(n-1) , n >= 2

5.2 代码实现

public static int JumpFloor1(int target) if(target<=1)return target;int result=1;for (int i = 2; i <= target; i++)result+=result;return result;
}

6.旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转

输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。

例如数组 {3, 4, 5, 1, 2} 为 {1, 2, 3, 4, 5} 的一个旋转,该数组的最小值为 1。

6.1 分析

在一个有序数组中查找一个元素可以用二分查找,二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度都为 O(logN)

本题可以修改二分查找算法进行求解:

  • 当 nums[m] <= nums[h] 的情况下,说明解在 [l, m] 之间,此时令 h = m;
  • 否则解在 [m + 1, h] 之间,令 l = m + 1。

6.2 代码实现

public class minNumber {public static void main(String[] args) {int [] arr= {3,4,5,1,2};System.out.print(findMinNumber(arr));}public static int findMinNumber(int[] arr) {if(arr.length==0||arr==null)return -1;int l=0;int h=arr.length-1;while(l<h) {int m=(l+h)/2;if(arr[m]<=arr[h])h=m;elsel=m+1;}return arr[l];}
}

6.3 允许重复元素

如果数组元素允许重复的话,那么就会出现一个特殊的情况:nums[l] == nums[m]== nums[h],那么此时无法确定解在哪个区间,需要切换到顺序查找。例如对于数组 {1,1,1,0,1},l、m 和 h 指向的数都为 1,此时无法知道最小数字 0 在哪个区间。

public static int findMinNumber(int[] arr) {if(arr.length==0||arr==null)return -1;int l=0;int h=arr.length-1;while(l<h) {int m=(l+h)/2;if (arr[l] == arr[m] && arr[m] == arr[h])return process(arr, l, h);else if(arr[m]<=arr[h])h=m;elsel=m+1;}       return arr[l];
}public static int process(int[] nums,int l,int h) {for (int i = l; i < h; i++)if (nums[i] > nums[i + 1])//出现前大于后的情况,后者肯定为最小return nums[i + 1];return nums[l]
}

7.矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径

路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。

例如下面的矩阵包含了一条 bfce 路径:

7.1 分析(原博)

这是一个可以用回溯法解决的典型问题。

首先,遍历这个矩阵matrix,我们很容易就能找到与字符串str中第一个字符相同的矩阵元素ch。

然后遍历ch的上下左右四个字符,如果有和字符串str中下一个字符相同的,就把那个字符当作下一个字符(下一次遍历的起点),如果没有,就需要回退到上一个字符,然后重新遍历

为了避免路径重叠,需要一个辅助矩阵来记录路径情况。

当矩阵坐标为(row,col)的格子和路径字符串中下标为pathLength的字符一样时,从4个相邻的格子(row,col-1)、(row-1,col)、(row,col+1)以及(row+1,col)中去定位路径字符串中下标为pathLength+1的字符。

如果4个相邻的格子都没有匹配字符串中下标为pathLength+1的字符,表明当前路径字符串中下标为pathLength的字符在矩阵中的定位不正确,我们需要回到前一个字符串(pathLength-1),然后重新定位

一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到格式的位置(此时str[pathLength] == '\0')。

7.2 代码实现(原博)

public class StringPathInMatrix {public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {if (matrix == null || rows < 1 || cols < 1 || str == null) {return false;}boolean[] isVisited = new boolean[rows * cols];for (boolean v : isVisited) {v = false;}int pathLength = 0;for (int row = 0; row < rows; row++) {for (int col = 0; col < cols; col++) {if (hasPathCore(matrix, rows, cols, row, col, str, pathLength, isVisited))return true;}}return false;}private boolean hasPathCore(char[] matrix, int rows, int cols, int row, int col, char[] str, int pathLength,boolean[] isVisited) {if (row < 0 || col < 0 || row >= rows || col >= cols || isVisited[row * cols + col] == true|| str[pathLength] != matrix[row * cols + col])return false;if (pathLength == str.length - 1)return true;boolean hasPath = false;isVisited[row * cols + col] = true;hasPath = hasPathCore(matrix, rows, cols, row - 1, col, str, pathLength + 1, isVisited)|| hasPathCore(matrix, rows, cols, row + 1, col, str, pathLength + 1, isVisited)|| hasPathCore(matrix, rows, cols, row, col - 1, str, pathLength + 1, isVisited)|| hasPathCore(matrix, rows, cols, row, col + 1, str, pathLength + 1, isVisited);if (!hasPath) {isVisited[row * cols + col] = false; }return hasPath;}

算法练习day20——190411(重建二叉树、斐波那契数列、跳台阶、矩形覆盖、变态跳台阶、旋转数组的最小数字、矩阵中的路径)相关推荐

  1. Python 算法之递归与尾递归,斐波那契数列以及汉诺塔的实现

    文章目录 递归概念 递归要素 递归与迭代的区别 示例一:阶乘 示例二:斐波那契数列 示例三:汉诺塔问题 尾递归 Python 中尾递归的解决方案 递归概念 递归:程序调用自身的编程技巧称为递归( re ...

  2. c语言斐波那契数列前20项和,,c语言利用数组求斐波那契数列的前20项

    推荐回答 一.斐波那契数列指的是这样一个数列1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711 ...

  3. 剑指 Offer 10- I. 斐波那契数列/剑指 Offer 10- II. 青蛙跳台阶问题

    2020-07-02 1.题目描述 写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少 ...

  4. 求解斐波那契数列(Fibonacci Numbers)算法居然有9种,你知道哪几种吗?

    By LongLuo 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为&q ...

  5. 斐波那契数列两种算法实现(循环,递归)

    首先是最简单的递归算法,相信很多初学者第一次接触递归这种算法都是从写一个斐波那契数列开始的. 这里除了递归算法之外我还会介绍循环算法 首先是最基础的递归算法 #include <stdio.h& ...

  6. 斐波那契数列的迭代算法和递归算法

    斐波那契数列 斐波那契数列(Fibonacci sequence),又称"黄金分割数列",因数学家莱昂纳多·斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入, ...

  7. C 语言实现斐波那契数列,解决递归实现缺陷(算法)

    何为斐波那契数列 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为&quo ...

  8. 《剑指offer》c++版本 10. 斐波那契数列

    如题: 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). 这道题基本上学过算法的人都直到,斐波那契数列即,即1,1,2,3,5....... 用数 ...

  9. 波菲那契数列公式_斐波那契数列为什么那么重要,所有关于数学的书几乎都会提到?...

    一句话先回答问题:因为斐波那契数列在数学和生活以及自然界中都非常有用. 下面我就尽我所能,讲述一下斐波那契数列. 一.起源和定义 斐波那契数列最早被提出是印度数学家Gopala,他在研究箱子包装物件长 ...

  10. 浅谈斐波那契数列——从递推到矩阵乘法

    说在前面 相信大家都已经知道这个中外著名的费波纳切数列了吧,关于费波那契数列有很多有趣的性质,但我们这里不讲,在这里我们只是利用斐波那契数列来引出另一个神奇的东西,矩阵乘法,递推在这里是起一个对比与铺 ...

最新文章

  1. 替换字符串空格 - Java - StringBuffer
  2. node jsonwebtoken
  3. swift. 扩展类添加属性_Swift中用到extension的一些基本的扩展功能讲解
  4. 彻底搞清楚浏览器渲染过程
  5. 扫雷游戏网页版_做游戏,单人行动可行吗(3.让我试试扫雷)
  6. C++ 贪吃蛇小游戏
  7. 浅谈配网供电可靠性及管理措施
  8. linux实现多台服务器文件同步
  9. UE4之A点绕B点旋转
  10. python自带的解释器和编辑器叫什么_(四)python自带解释器(LDIE)的使用
  11. gif透明背景动画_ppt模板3D卡通GIF动画PPT素材,多种多样的日常动作
  12. 会声会影2018,带你体验不一样的光影世界!
  13. TiDB 源码阅读系列文章(二十)Table Partition
  14. git提交代码的两种方法步骤
  15. 蛋白质配体复合物-分子动力学模拟Gromacs
  16. python爬取京东商品图片_爬取京东和天猫下载商品图片
  17. 样本不平衡问题分析与部分解决办法
  18. Java I/O---概述
  19. 软件企业认定的标准要求
  20. 如何通过企业微信、飞书、钉钉消息通知接收双因子认证动态密码?

热门文章

  1. etcd集群部署与遇到的坑
  2. Java8:Lambda表达式增强版Comparator和排序
  3. [一道搜狗输入法的面试题]C++转换构造函数和类型转换函数
  4. 西游东去 (~~创意?创新?恶搞?不置可否,不过有点意思)
  5. 前端趋势榜:上周最有意思、又实用的 10 大 Web 项目 - 210924
  6. JAVA8 Stream方法使用详解Filter、map等用法(一)
  7. 轻量级日志采集系统Loki+grafana搭建
  8. /etc/resolv.conf root用户下不能修改
  9. Spark on K8S 的现状与挑战
  10. JavaFX场景切换代码示例