Android算法学习——打表法的概念
引言
打表法的概念:
打表是一种用空间换时间的技巧,一般指将所有可能需要用到的结果事先计算出来,这样后续可以直接通过查表获取。打表常见的用法有以下几种:
- 在程序中一次性计算出所有需要用到的结果,之后的查询直接取这些结果。
- 在程序B中分一次或多次计算出所有需要用到的结果,手工把结果写在程序A的数组中,然后在程序A中就可以直接使用这些结果。
- 对一些感觉不会做的题目,先用暴力程序计算小范围数据的结果,然后找规律,或许就能发现一些“蛛丝马迹”。
本篇文章主要介绍第三种,当遇到一头雾水的题目,毫无章法可言,并且输入为简单整数,输出为简单整数。通过尝试多个数找到规律,直接写答案。
苹果装袋问题
题目:给定两种规格的袋子:6 和 8,小明准备买 NNN 个苹果,问至少需要几个袋子,袋子必须严格装满,否则返回 -1。
Eg : 1,2,3 都是不能装满,返回 -1。
思路历程:
- 第一感觉很像零钱换硬币的问题,用最少的硬币数量凑出钱数 NNN,贪心的过程,每次以 aaa 枚最大面额去尝试,不断减小 aaa 直至满足条件。
- 此题我们也这样去尝试,优先都用 8 号袋子装,剩下的用 6 号袋子装,刚好装满则返回 count8+count6count8 + count6count8+count6 ,如果装不满,就继续 count8count8count8 的数量减小。
- 于是写出如下代码 V1.0V1.0V1.0 版本:
/** * 思想历程:首先尝试一下暴力解 * 1.优先装 8 这个袋子,剩下的装入 6 袋子中,严格装满。 * 2.从最多的 n / 8 个袋子一直尝试,直到找到答案返回,否则返回 -1 */ public static int minBags(int n) { if (n < 6) return -1; int count = 0; int bag8 = n / 8; for (int i = bag8; i >= 0; i--) { int mod = n - i * 8; if (mod % 6 == 0) { //有效方案 count = i + mod / 6; return count; } } return -1; }
继续优化:
- 通过题意,奇数肯定不满足条件,过滤一下。
- 当装完 8 号袋子后剩余苹果为 modmodmod , 当 mod>24mod > 24mod>24 直接返回 - 1
原因: 6 与 8 的最大公约数为 24,超过 24 后,25 % 6 = 1 = 25 % 8,26 % 6 = 2 = 26 % 6
既然是求最少袋子数量,模数一样,那肯定选择 8 号袋子,这里有贪心的思想。
- 于是写出如下优化后的代码 V2.0V2.0V2.0:
/** * 思想历程:首先尝试一下暴力解 * 1.优先装 8 这个袋子,剩下的装入 6 袋子中,严格装满。 * 2.从最多的 n / 8 个袋子一直尝试,直到找到答案返回,否则返回 -1 */ public static int minBags(int n) { if (n < 6) return -1; int count = 0; int bag8 = n / 8; for (int i = bag8; i >= 0; i--) { int mod = n - i * 8; if (mod % 6 == 0) { //有效方案 count = i + mod / 6; return count; } } return -1; }
打表法代码如下 V3.0V3.0V3.0:
/*** 打表法:通过观察暴力递归的结果:* 从18开始:每8个数为一组,奇数为-1,偶数为满足 : (n - 18)/8 + 3* 于是可以写出如下代码*/public static int minBags2(int n) {if ((n & 1) != 0 || n < 6) return -1;//直接列举if (n < 18) {return (n == 6 || n == 8) ? 1 : (n == 12 || n == 14 || n == 16) ? 2 : -1;}//超过18,直接写答案return (n - 18) / 8 + 3;}
好家伙,这代码是给人看的么,之前在 LeetCode 里看到类似解析,一顿雾水,佩服的五体投地,咋想出来的,有规律?
打表法场景三:
对一些感觉不会做的题目,先用暴力程序计算小范围数据的结果,然后找规律,或许就能发现一些“蛛丝马迹”。
于是,打印出暴力方法从 1−N1-N1−N 的解如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ytqc8O6d-1656770058362)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0454cc8b1c2143d799ea6c8907463f69~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
- 前 17 个数没规律,直接输出,从18以后,每 8 个数一组,第一组为 3,第二组为 4,第三组为 5…
- 所以大于18 有如下结论: (n−18)/8+3(n - 18) / 8 + 3(n−18)/8+3
小羊吃草(博弈问题)
题目:有 A
, B
两只羊,有 N
堆草,规定每次只能吃 4
的次方数量堆草,既 1
,4
,16
,64
…,判断是先手吃到最后的草堆,还是后手吃到,假定两只羊都绝顶聪明。规定:不能不吃。至少吃 1 。返回: 先手
or 后手
。
思路历程:
- 博弈问题常规解法就是理解好递归函数。
- 因为双方都是绝顶聪明,函数入口表示
先手
,有n
份草,我要如何吃才能赢。 - 重点理解:母过程的
先手
,对应在子过程中就是后手
。
/** * 思路:博弈问题,都是绝顶聪明。 * 1.入口函数为先手,表示先吃。 */
public static String winner(int n) { //调用该函数的时候当前对象用于表示先手,n = 0了,则表明之前的后手把草吃完了, //导致我无草可吃,表示后手赢 // 0, 1, 2, 3, 4, // 后 先 后 先 先 if (n < 5) { return (n == 0 || n == 2) ? "后手" : "先手"; } //当n>=5时候 int base = 1;//表示当前先手决定吃的草数量 while (base <= n) { //当前一共 n 份草,先手吃了 base 份, n - base 是留给后手的草 //母过程先手,在子过程中就是后手,即及过程如果返回 后手,则表明当前的决定能赢 if (winner(n - base).equals("后手")) { return "先手"; } //防止 base * 4 越界 if (base > n / 4) break; base *= 4; } //上面过程都不能让先手赢 return "后手";
}
还是打印小范围内的结果看看规律:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xHbcUS7q-1656770058363)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c9f94f5c3a934deb820bd0c33a5caf9e~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)]
可以观察到到输入参数 n
模上 5
等于 2
,0` 时候都是`后手
赢,否则先手
赢。
/** * 观察暴力递归:发现,n % 5 == 0 || n % 5 == 2 时候是后手赢,其他情况都是先手赢 */
public static String winner2(int n){ if (n % 5 == 0 || n % 5 == 2) return "后手"; return "先手";
}
累加和问题
题目:定义一种数:可以表示成若干 (数量 > 1) 连续正数和的数,返回 true 否则返回 false。
eg: 5 = 2 + 3,12 = 3 + 4 + 5,1 不满足,因为要求数量大于1,2 = 1+1也不满足,因为不是连续递增的。
给定一个参数 N
,返回这个是是否可以表示成若干连续正数和的数字
思路历程:
- 暴力尝试,两层 for 循环,遍历区间累加和,满足则 返回 fasle,否则继续。
代码如下:
/*** 暴力尝试,从 i - n 不停的尝试,找到了就返回 - 1*/
public static boolean isSum(int n) {if (n <= 2) return false;for (int i = 1; i <= n / 2; i++) {//因为会少两个数,第一个数字的取值范围为 1-n/2int sum = i;for (int j = i + 1; j < n ; j++) {sum += j;if (sum == n) return true;if (sum > n) break;}}return false;
}
打表观察结果:
/** * 打表法:通过观察当 n >=3 后 * 有:4,8,16,32,64...为 false,其它都为 true */
public static boolean isSum1(int n){ if (n <= 2) return false; //判断一个数是否是2的次方:这个是的二进制中只有一个 1 //eg: 16 = 001000 则 n & (n - 1) = 00100 & 000111 = 0,则为2的次方 //eg: 6 = 00110 则 n & (n - 1) = 00110 & 00011 != 0 return (n & (n - 1)) != 0;
}
结语
暴力方法是很多算法的前提,有了暴力算法后,我们可以用它做对数器,判断我们优化后的代码是否是正确的,同时也可以通过输入和输出,找出一点规律,于是就有了打表法规则三。
如果直接看代码,肯定会一头雾水,好的代码逻辑一定是一步步优化出来的。
Android相关源码解读
“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。
主要内含微信 MMKV 源码、AsyncTask 源码、Volley 源码、Retrofit源码、OkHttp 源码等等。
Android BAT高级开发面试题及答案解析
面试前夕,刷题冲刺
面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。
关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:
>这份完整版的学习资料已经上传CSDN ,朋友们如果需要可扫描下方二维码免费获取]。
改变人生,没有什么捷径可言,这条路需要自己亲自去走一走,只有深入思考,不断反思总结,保持学习的热情,一步一步构建自己完整的知识体系,才是最终的制胜之道,也是程序员应该承担的使命。
Android算法学习——打表法的概念相关推荐
- 多边形填充算法-有序边表法(扫描线算法) 计算机图形学
1.算法的基本思想(扫描线连贯性原理): 对于一个给定的多边形,用一组水平(垂直)的扫描线进行扫描,对每一条扫描线均可求出与多边形边的交点,这些交点将扫描线分割成落在多边形内部的线段和落在多边形外部的 ...
- 多边形填充算法-有序边表法(扫描线算法)
1.算法的基本思想(扫描线连贯性原理): 对于一个给定的多边形,用一组水平(垂直)的扫描线进行扫描,对每一条扫描线均可求出与多边形边的交点,这些交点将扫描线分割成落在多边形内部的线段和落在多边形外部的 ...
- dijkstra迪杰斯特拉算法(邻接表法)
算法简易过程: 迪杰斯特拉算法(朴素) O(n^2) G={V,E} V:点集合 E:边集合 初始化时 令 S={某源点ear}, T=V-S= {其余顶点},T中顶点对应的距离(ear, Vi)值若 ...
- 软件测试学习——判定表法
判定表法 1.定义: 等价类,边界值分析法一般是对单一输入进行测试用例分析的方法.判定表是对其的一种补充,对于多种输入之间存在的组合关系并且对应执行不同动作,进行测试用例的分析的方法. 2.相关名称: ...
- 探索初级算法学习笔记-快速排序法
快速排序法学习笔记 #include<stdio.h>void swap(int *a,int *b) {int t;t=*a;*a=*b;*b=t; }void quickSort(in ...
- ICP算法学习记录(包括基础概念,计算推导)
首先,ICP,全称叫做(Iterative Closest Point,迭代最近点),在slam中用来做点云匹配,点云匹配就是将同一个物体,在不同视角下的两组或多组点云,通过旋转加平移让他们匹配起来. ...
- 【算法学习】欧几里得算法详解(包括扩展、同余方程)
欧几里得算法详解(包括扩展.同余方程) 1.普通欧几里得算法(求最大公约数) 2.扩展欧几里得算法(求解a*x+b*y=c中(x,y)) 3.同余方程 1.普通欧几里得算法(求最大公约数) 欧几里得算 ...
- 数据结构与算法学习--跳表
跳表 Skip List是一种随机化的数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间).基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机 ...
- VS 2019 MFC CRC16校验算法例程总结(计算法/查表法以及CRC16校验表自动生成)
工程需要,根据网上例程对CRC16校验方法进行了总结.CRC16为通讯领域常用的校验算法,其原理想必大家都很清楚.下面为相关的总结和封装类代码.被例程将CRC16校验的方法分为及算法和 ...
最新文章
- 程序的编译和链接过程
- mysql和mybatis面试题_2020年,MyBatis常见面试题总结
- X11: Linux跨网络运行XWindow程序
- SAP Spartacus开启SSR服务器端渲染之后,和默认客户端渲染的差异比较
- DeepMind 的马尔可夫决策过程(MDP)课堂笔记
- camera中文版软件 ip_ip camera网络摄像机
- 现代软件工程 作业 最后一周总结
- SharePoint自动化系列——通过PowerShell创建SharePoint Lists
- 无线OSS-高精度整数加法
- 计算机类教材的选题策划,电子计算机类科技期刊的选题策划.doc
- k8s 二进制高可用集群部署
- 怎样夸学计算机的人,学学古人是怎样夸人有才的
- L. Ray in the tube
- 有什么合适个体商户及小微企业的入门级进销存管理软件?
- 高漫数位板1060PRO 8192级的驱动下载与安装
- 写论文 参考文献引用 谷歌学术 规范格式 一键生成
- 树美滑块验证——滑块识别、获取和提交参数一条龙分析和调用
- 极域电子教室学生机房管理助手(好好上课)教程
- 表单环境外访问Xrm.Page.context对象
- 网络受限_受限人工神经网络对幸福的追求