《剑指offer》算法题第三天
今日题目:
- 斐波那契数列
- 青蛙跳台阶问题(及其变种:变态跳台阶)
- 矩形覆盖
- 旋转数组的最小数字
- 矩阵中的路径
- 机器人的运动范围
细心的同学会发现,第1,2,3题其实对应的是《剑指》书上的同一道题目,即第10题斐波那契数列,这类问题属于递归问题,虽然思路比较简单,但却是属于那种不看答案想不出来,看了答案恍然大悟的题目,因此在平时同学们和博主都应该多练练这一类型的题目,培养这种递归的思维。有趣的是,博主在做题的时候发现这三道题目是可以用动态规划的思路来解决的,而且往往动态规划的所用的时间是要低于递归的。在后文中会以矩形覆盖为例子来说明。
第5,6两题是回溯法的题目,在leetcode上有不少这一类型的题,只要多做练习,这一类型的题目还算是比较容易上手的。本文只说明第6题。
3.矩行覆盖
题目描述:
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 思路:
以n=8为例,我们先把2*8矩形的覆盖方法记为f(8)。当用一个2*1的小矩形取覆盖大矩形的最左边时有两种选择:竖着放或横着放。如果选择竖着放,那么右边还剩下2*7的区域,也就是f(7);如果横着放在左上角,左下角必须也放置一个矩形,那么右边还剩下2*6的区域,也就是f(6)。所以我们有f(8)=f(7)+f(6)。从这边我们可以看出来,其实这就是一个斐波那契数列。
理清思路后,接下来我们分别用递归以及动态规划的方法来实现。
递归代码如下:
public class Solution {
public int RectCover(int target) {
if(target == 0) return 0;
if(target == 1) return 1;
if(target == 2) return 2;
return RectCover(target-1)+RectCover(target-2);
}
}
代码比较简单、清晰,但是效率非常的低,他的时间复杂度不难推出来是成指数的。在牛客网上的运行时间为447ms。
接下来我们看一下动态规划是如何解决的,代码如下:
public class Solution {
public int RectCover(int target) {
if(target == 0) return 0;
int[] dp = new int[target+1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= target; i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[target];
}
}
很明显,这段代码的时间复杂度仅为O(n),当然空间复杂度也为O(n),所以,你也可以这么做:
public class Solution {
public int RectCover(int target) {
if(target == 0) return 0;
int num1 = 1;
int num2 = 1;
int res = 1;
for(int i = 2; i <= target; i++){
res = num1 + num2;
num1 = num2;
num2 = res;
}
return res;
}
}
这样空间复杂度也就仅为常数啦。动态规划在同样的条件下运行时间仅为12ms。
4.旋转数组的最小数字
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
这题在leetcode上面是有原题的,当时博主在做的时候并没有太多的想法,直接从后往前遍历数组,如果某个数比它前面的数字要小的话,那么这个数就是最小的,时间复杂度为O(n)。代码如下:
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length ==0) return 0;
for(int i = array.length-1; i >0; i--){
if(array[i-1] > array[i])
return array[i];
}
return array[0];
}
}
但是在《剑指》上,这题有一个时间复杂度为O(logn)的思路:利用二分查找的思路来寻找最小数字,具体的过程阐述起来过于复杂,感兴趣的同学可以阅读书上第83页,这边只贴出代码:
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length ==0) return 0;
int s = 0;
int e = array.length - 1;
if(array[s] < array[e])//表示旋转了0个数字到数组后面
return array[s];
while(s != e){
if(e - s == 1)
return array[e];
int mid = (s+e)/2;
if(array[mid] == array[s] && array[mid] == array[e])//处理特殊情况
return orderFind(array,s,e);
if(array[mid] >= array[s])
s = mid;
else if(array[mid] <= array[e])
e = mid;
}
return array[s];
}
public int orderFind(int[] array,int start,int end){
int res = array[start];
for(int n:array){
res = (n < res)?n:res;
}
return res;
}
}
6. 机器人的运动范围
题目描述:
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子? 思路:
这是比较直接的回溯法的题目,首先使用一个数组来标记机器人已经走过的放歌,防止重复,然后使用回溯法让机器人运动,每次运动到一个方格都判断一下是否合法,如果合法,计数器加一接着往下走;否则返回0;
代码如下:
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
boolean[][] visited = new boolean[rows][cols];
return movingCount(threshold,visited,rows,cols,0,0);
} public int movingCount(int k,boolean[][] visited,int rows,int cols,
int row,int col)
{
if(row < 0 || row >= rows||
col < 0 || col >= cols || visited[row][col])
return 0;
visited[row][col] = true;
int sum = 0;
int row_tmp = row;
int col_tmp = col;
do{
sum += (row%10);
row /= 10;
}while(row > 0); do{
sum += (col%10);
col /= 10;
}while(col > 0);
row = row_tmp;
col = col_tmp;
if(sum > k)
return 0;
else{
return movingCount(k,visited,rows,cols,row+1,col)+
movingCount(k,visited,rows,cols,row-1,col)+
movingCount(k,visited,rows,cols,row,col+1)+
movingCount(k,visited,rows,cols,row,col-1)+1;
}
}
}
《剑指offer》算法题第三天的更多相关文章
- 剑指offer算法题
数组中只出现一次的数字(一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字): 解法在于位运算中的异或,直接异或可以得到这两个数的异或,按照最后的有效数字位可以 ...
- 剑指offer算法总结
剑指offer算法学习总结 节选剑指offer比较经典和巧妙的一些题目,以便复习使用.一部分题目给出了完整代码,一部分题目比较简单直接给出思路.但是不保证我说的思路都是正确的,个人对算法也不是特别在行 ...
- 剑指Offer——算法复杂度中的O(logN)底数是多少
剑指Offer--算法复杂度中的O(logN)底数是多少 前言 无论是计算机算法概论.还是数据结构书中,关于算法的时间复杂度很多都用包含O(logN)这样的描述,但是却没有明确说logN的底数究竟是多 ...
- 剑指 offer 第一题: 二维数组中的查找
打算写 图解剑指 offer 66 题 的系列文章,不知道大家有没有兴趣
- 剑指Offer编程题2——替换空格
剑指Offer编程题2——替换空格 题目描述 请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happ ...
- 剑指Offer编程题1——二维数组中的查找
剑指Offer编程题1---------------二维数组中的查找 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完 ...
- 剑指offer编程题66道题 36-66
36.两个链表的第一个公共节点 题目描述 输入两个链表,找出它们的第一个公共结点. 1.具有重合节点的两个链表是一个Y字性,用两个堆栈放这两个链表,从尾部开始遍历,直到遍历到最后一个重合节点. 这种算 ...
- 牛客网剑指offer刷题总结
二维数组中的查找: 题目描述:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 两 ...
- 剑指offer编程题Java实现——面试题12相关题大数的加法、减法、乘法问题的实现
用字符串或者数组表示大数是一种很简单有效的表示方式.在打印1到最大的n为数的问题上采用的是使用数组表示大数的方式.在相关题实现任意两个整数的加法.减法.乘法的实现中,采用字符串对大数进行表示,不过在具 ...
- 剑指offer刷题(Tree)
开篇 二刷剑指offer了,本来用Tyora记的笔记,发现字数到四万了就变得好卡o(╥﹏╥)o,刚好开始写博客,就转过来吧,记下来子自己看.不废话,开刷... JZ26. 树的子结构 输入两棵二叉树A ...
随机推荐
- [Python3] 039 语法调试
目录 语法调试 1. 调试技术 2. pdb 调试 插一个 gdb 3.Pycharm 调试 4. 单元测试 语法调试 1. 调试技术 调试流程 单元测试 → 集成测试 → 交测试部 分类: 静态调试 ...
- oracle数据区间
区是段下面的一个管理单位,一个区在物理上是一段连续的数据块. 一个数据文件有一个文件头,它用了若干个数据块,这个文件头里记录着区的分配与释放的信息.在这个文件中有些区是被使用的,有些区是空闲的. 什么 ...
- 2019年8月23日 星期五(韩天峰的swoole)
Swoole:面向生产环境的 PHP 异步网络通信引擎 使 PHP 开发人员可以编写高性能的异步并发 TCP.UDP.Unix Socket.HTTP,WebSocket 服务. Swoole 可以广 ...
- 服务器部署Java Web及微信开发调试
参考摘抄: 阿里云部署Java网站和微信开发调试心得技巧(上):https://www.imooc.com/article/20583 阿里云部署Java网站和微信开发调试心得技巧(下):https: ...
- 第六篇 ajax
加载异步数据 6-1 加载异步数据 XMLHttpRequest--传统的JavaScript方法实现Ajax功能 6-1-a <!DOCTYPE html PUBLIC "-//W3 ...
- js的作用主要这么几个
js的作用主要有这么几个表单验证:网页上,用户输入的信息需要进行验证,在客户端验证,可以减少对服务器端的压力.所以,你应该把握正则表达式方面的知识.网页特效:页面上很多特效是非常好的,能产生很好的用户 ...
- Js 将图片的绝对路径转换为base64编码
转.... 我们可以使用canvas.toDataURL的方法将图片的绝对路径转换为base64编码:在这我们引用的是淘宝首页一张图片如下: var img = "https://img. ...
- 2019.10.28sql注入工具
SQLMAP工具的使用 sql注入工具:明小子 啊D 萝卜头 穿山甲 sqlmap等等 开源自动化注入利用工具,支持12中数据库,在/plugins中可以看到支持的数据库种类 支持的注入类型:bool ...
- 模块之-os模块
模块之-os模块 >>> import os >>> os.getcwd() #获取当前工作目录 'C:\\Users\\Administrator' >&g ...
- c++ 数组 结构体
接下来的一点时间我将会记录下我看的c++的一些心得体会,人贵在坚持,希望我可以一直坚持下去!!Go Fighting! 一.c++复合数据类型: 数组类型的一些注意事项: sizeof的用法: 当 ...