数字与数学基础问题

关卡名

数字与数学基础问题

我会了✔️

内容

1.数字里统计的处理技巧

✔️

2.必须熟练掌握溢的处理方法

✔️

3.掌握进制的处理方法

✔️

1. 数字统计专题 

统计一下特定场景下的符号,或者数字个数等是一类非常常见的问题 。如果按照正常方式强行统计,可能会非常复杂,所以掌握一些技巧是非常必要的。

1.1 符号统计

LeetCode1822 给定一个数组,求所有元素的乘积的符号,如果最终答案是负的返回-1,如果最终答案是正的返回1,如果答案是0返回0。
仔细分析一下这道题目,如果将所有数都乘起来,再判断正负,工作量真不少,而且还可能溢出。我们发现,一个数如果是 -100 和 -1,对符号位的贡献是完全一样的,所以只需要看有多少个负数,就能够判断最后乘积的符号了。

public int arraySign(int[] nums) {                           int prod = 1;                       for(int i = 0; i < nums.length; ++i) {     if(nums[i] == 0) {               return 0;//一切归零}else if(nums[i] < 0) {//交替就够了,很好的处理技巧prod = -prod;}}return prod;       
}

1.2 阶乘0的个数

很多数学相关算法的关键在于找到怎么通过最简洁的方式来解决问题,而不是硬算。例如:面试题16.05:设计一个算法,算出 n 阶乘有多少个尾随零。
这个题如果硬算,一定会超时,其实我们可以统计有多少个 0,实际上是统计 2 和 5 一起出现多少对,不过因为 2 出现的次数一定大于 5 出现的次数,因此我们只需要检查 5 出现的次数就好了,那么在统计过程中,我们只需要统计 5、10、15、 25、 ... 5^n 这样 5 的整数倍项就好了,最后累加起来,就是多少个 0。代码就是:

public int trailingZeroes(int n) {int cnt = 0;for (long num = 5; n / num > 0; num *= 5) {cnt += n / num;}return cnt;
}

数学不仅与算法难以区分 ,很多算法问题还与位运算密不可分,有些题目真不好说是该归类到数学中呢,还是位运算中。我们干脆就放在一起来看。

2 溢出问题 

溢出问题是一个极其重要的问题,只要涉及到输出一个数字,都可能遇到,典型的题目有三个:数字反转,将字符串转成数字和回文数。 不过溢出问题一般不会单独考察,甚至面试官都不会提醒你,但他就像捕捉猎物一样盯着你,看你会不会想到有溢出的问题。

2.1 整数反转

LeetCode7 给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,就返回 0。假设环境不允许存储 64 位整数(有符号或无符号)。

输入:x = 123 输出:321

输入:x = -123 输出:-321

输入:x = 120 输出:21

输入:x = 0 输出:0

这个题的关键有两点,一个是如何进行数字反转,另一个是如何判断溢出。反转好说,那为什么会有溢出问题呢?例如1147483649这个数字,它是小于最大的32位整数2147483647的,但是将这个数字反转过来后就变成了9463847411,这就比最大的32位整数还要大了,这样的数字是没法存到int里面的,所以就溢出了。
首先想一下,怎么去反转一个整数。用栈?或者把整数变成字符串再反转字符串?都可以但都不好。我们只要一边左移一边处理末尾数字就可以了。以12345为例,先拿到5,再拿到4,之后是3,2,1,然后就可以反向拼接出一个数字了。那如何获得末尾数字呢?好办,循环取模运算即可。例如:

1.将12345 % 10 得到5,之后将12345 / 10=1234

2.将1234 % 10 得到4,再将1234 / 10=123

3.将123 % 10 得到3,再将123 / 10=12

4.将12 % 10 得到2,再将12 / 10=1

5.将1 % 10 得到1,再将1 / 10=0

画成图就是:

 

这样的话,是不是将循环的判断条件设为x>0就可以了呢?不行!因为忽略了负数的问题,应该是while(x!=0)。去掉符号,剩下的数字,无论正数还是负数,按照上面不断的/10这样的操作,最后都会变成0,所以判断终止条件就是!=0。有了取模和除法操作,就可以轻松解决第一个问题,如何反转。
接下来看如何解决溢出的问题。我们知道32位最大整数是MAX=2147483647,如果一个整数num>MAX,那么应该有以下规律:
nums/10 > MAX/10=214748364,也就是如果底数第二位大于4了,不管最后一位是什么都已经溢出了,如下:

所以我们要从到最大数的1/10时,就要开始判断,也即:

  • 如果 num>214748364 那后面就不用再判断了,肯定溢出了。
  • 如果num= 214748364,这对应到上图中第三、第四、第五排的数字,需要要跟最大数的末尾数字比较,如果这个数字比7还大,说明溢出了。
  • 如果num<214748364,则没问题,继续处理。

这个结论对于负数也是一样的,所以实现代码就是:

public int reverse(int x) {int res = 0;while(x!=0) {//获得末尾数字int tmp = x%10;//判断是否大于最大32位整数,也可以使用Integer.MAX_VALUE/10来代替214748364if (res>Integer.MAX/10 || (res==Integer.MAX/10 && tmp>7)) {return 0;}//判断是否小于最小的32位整数if (res<-214748364 || (res==-214748364 && tmp<-8)) {return 0;}res = res*10 + tmp;x /= 10;}return res;
}

2.2 字符串转整数 

LeetCode8.意思就是字符串转整数(atoi函数),题目比较长,解决过程中要涉及很多异常情况的处理,我们在《字符串》一关进行了详细讲解,请回顾一下相关的内容。

2.3 回文数

LeetCode9 .给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。

思路解析:
映入脑海的第一个想法是将数字转换为字符串,并检查字符串是否为回文。但是,这需要额外的非常量空间来创建问题描述中所不允许的字符串。
第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。 但是,如果反转后的数字大于int.MAX,我们将遇到整数溢出问题。
按照第二个想法,为了避免数字反转可能导致的溢出问题,为什么不考虑只反转 int 数字的一半?毕竟,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。
例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。
这个反转思路与链表的反转是一样的,不过要简单多了。
这里还不能忘的问题就是,反转之后数字可能会溢出,因此必须做防范,方法我们上面说了,这里我们可以进一步简化一下:

public boolean isPalindrome(int x) {// 特殊情况:// 如上所述,当 x < 0 时,x 不是回文数。// 同样地,如果数字的最后一位是 0,为了使该数字为回文,// 则其第一位数字也应该是 0// 只有 0 满足这一属性if(x<0 || (x%10==0 && x!=0)){return false;}int revertedNumber = 0;while(x > revertedNumber){revertedNumber = revertedNumber*10 + x%10;x /= 10;}// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。return x==revertedNumber x==revertedNumber /10;
}

3.进制专题 

进制问题也是一个非常重要的专题,有的直接处理还挺费劲,我们看两道题。

3.1 七进制数

LeetCode504.给定一个整数 num,将其转化为 7 进制,并以字符串形式输出。其中-10^7 <= num <= 10^7。

示例1:

输入: num = 100

输出: "202"

我们先通过二进制想一下7进制数的变化特征。在二进制中,先是0,然后是1,而2就是10(2),3就是11(2),4就是(100)。同样在7进制中,计数应该是这样的:
0 1 2 3 4 5 6 10 11 12 13 14 15 16 20 21 22 ...
给定一个整数将其转换成7进制的主要过程是循环取余和整除 ,最后将所有的余数反过来即可。例如,将十进制数100 转成七进制:

100÷7=14 余 2

14÷7=2 余 0

2÷7=0 余 2

向遍历每次的余数,依次是 2、0、2,因此十进制数 100 转成七进制数是202 。如果num<0,则先对 num 取绝对值,然后再转换即可。使用代码同样可以实现该过程,需要注意的是如果单纯按照整数来处理会非常麻烦,既然题目说以字符串形式返回,那我们干脆直接用字符串类,代码如下:

 

public String convertToBase7(int num) {StringBuilder sb = new StringBuilder();//先拿到正负号boolean sign = num < 0;//这样预处理一下,后面都按照正数处理num就行了if(sign)num *= -1;//循环取余和整除    do{sb.append(num%7 + "");num/=7;}while(num > 0);//添加符号if(sign)sb.append("-");//上面的结果是逐个在末尾加的,需要反过来   return sb.reverse().toString();
}

3.2 进制转换 

给定一个十进制数M,以及需要转换的进制数N,将十进制数M转化为N进制数。M是32位整数,2<=N<=16。
这个题目的思路不复杂,但是想写正确却很不容易,甚至越写越糊涂。本题有好几个需要处理的问题:

  • 1.超过进制最大范围之后如何准确映射到其他进制,特别是ABCDEF这种情况。简单的方式是大量采用if 判断,但是这样会出现写了一坨,最后写不下去。
  • 2.需要对结果进行一次转置。
  • 3.需要判断负号。

下面这个是我总结出的最精简,最容易理解的实现方案。注意采取三个措施来方便处理:

  • 1.定义大小为16的数组F,保存的是2到16的各个进制的值对应的标记,这样赋值时只计算下标,不必考虑不同进制的转换关系了。
  • 2.使用StringBuffer完成数组转置等功能,如果不记得这个方法,工作量直接飙升。
  • 3.通过一个flag来判断正数还是负数,最后才处理。
  // 要考虑到 余数 > 9 的情况,2<=N<=16.public static final String[] F = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};//将十进制数M转化为N进制数public String convert (int M, int N) {Boolean flag=false;if(M<0){flag=true;M*=-1;}StringBuffer sb=new StringBuffer();int temp;while(M!=0){temp=M%N;//技巧一:通过数组F[]解决了大量繁琐的不同进制之间映射的问题sb.append(F[temp]);M=M/N;}//技巧二:使用StringBuffer的reverse()方法,让原本麻烦的转置瞬间美好sb.reverse();//技巧三:最后处理正负,不要从一开始就揉在一起。return (flag? "-":"")+sb.toString();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/256035.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MX6ULL学习笔记 (八) platform 设备驱动实验

前言&#xff1a; 什么是 Linux 下的 platform 设备驱动 Linux下的字符设备驱动一般都比较简单&#xff0c;只是对IO进行简单的读写操作。但是I2C、SPI、LCD、USB等外设的驱动就比较复杂了&#xff0c;需要考虑到驱动的可重用性&#xff0c;以避免内核中存在大量重复代码&…

uc_13_共享内存_消息队列_IPC对象

1 IPC对象 多个IPC -> 一个IPC对象 -> 一个IPC对象标识符 -> 一个键(整数)(即IPC对象的外部名称) 共享内存、消息队列和信号量&#xff0c;这三种IPC一般被合称为XSI IPC&#xff0c;它们有很多相似之处。 为了实现进程间的数据交换&#xff0c;系统内核会为参…

dockerfile简单实践部署(jenkins,wordpress)

实现部署jenkins的流程 配置java环境&#xff0c;导入jenkins包&#xff0c;运行命令 java -jar jenkins包&#xff0c;这里为了减少进入jenkins的web端安装插件&#xff0c;将插件提前部署到容器内。 制作dockerfile 创建镜像所在的文件夹和Dockerfile文件 mkdir /test cd …

【项目日记(一)】高并发内存池项目介绍

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:项目日记-高并发内存池⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 项目日记 1. 前言2. 什么是高并发内存池…

Textual Inversion

参考博客1:https://www.bilibili.com/read/cv25430752/

移动云荣获OpenInfra社区“算力基础设施技术突破奖”

近日&#xff0c;一年一度的 OpenInfra Days China在北京召开&#xff0c;大会汇聚了全球各大云厂商的技术专家&#xff0c;共同分享全球前沿基础设施技术的展望和实践经验。在本次大会上&#xff0c;移动云荣获OpenInfra社区颁发的“算力基础设施技术突破奖”&#xff0c;表明…

基于ssm实验室课程管理系统源码和论文

idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 环境&#xff1a; jdk8 tomcat8.5 摘 要 随着科学实验规模的不断扩大&#xff0c;实验室课程数量的急剧增加&#xff0c;有关实验室课程的各种信息量也在不断成倍增长。面对庞大的信息量&#xff0c;就需要有…

ChatGPT 应用开发(一)ChatGPT OpenAI API 免代理调用方式(通过 Cloudflare 的 AI Gateway)

前言 开发 ChatGPT 应用&#xff0c;我觉得最前置的点就是能使用 ChatGPT API 接口。首先我自己要能成功访问&#xff0c;这没问题&#xff0c;会魔法就可以本地调用。 那用户如何调用到我的应用 API 呢&#xff0c;我的理解是通过用户能访问到的中转服务器向 OpenAI 发起访问…

基于SSM实现的公文管理系统

一、技术架构 前端&#xff1a;jsp | jquery | bootstrap 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven 二、代码及数据库 三、功能介绍 01. 登录页 02. 首页 03. 系统管理-角色管理 04. 系统管理-功能管理 05. 系统管理-用…

猫咪瘦弱的原因是什么?适合给消瘦猫咪长肉吃的猫罐头分享

很多小猫咪吃得很多&#xff0c;但是还是很瘦&#xff0c;这让很多猫主人感到困惑&#xff0c;猫咪瘦弱的原因是什么呢&#xff1f;铲屎那么多年&#xff0c;还是有点子养猫知识在身上的。那么&#xff0c;小猫咪瘦弱的原因是什么呢&#xff1f;让我们看看是不是这些原因导致的…

详细解读电力DLT698.45-2017通信规约--正向有功总电能

建立连接请看这篇&#xff1a;详细解读DLT698.45-2017通信规约--预连接响应http://mp.weixin.qq.com/s?__bizMzA3NjAwMjQzMQ&mid2652026396&idx1&sna0a17f005d23136c922a7c381ddb7e75&chksm8481f30cb3f67a1a94e66db77e61fe73c22b1904fcdbb0144108e132b265e7b4…

黑苹果之显卡篇

一、什么是显卡 显卡GPU&#xff08;Video card、Display card、Graphics card、Video adapter&#xff09;是个人计算机基础的组成部分之一&#xff0c;将计算机系统需要的显示信息进行转换驱动显示器&#xff0c;并向显示器提供逐行或隔行扫描信号&#xff0c;控制显示器的正…