算法通过村第十三关-术数|青铜笔记|数字与数学

news2024/11/18 10:31:21

文章目录

  • 前言
  • 数字统计专题
    • 符号统计
    • 阶乘0的个数
  • 溢出问题
    • 整数反转
    • 字符串转整数
    • 回文数
  • 进制专题
    • 七进制数
    • 进制转换
  • 总结


前言


提示:生活是正着来生活,倒着去理解。 --戴维·迈尔斯《社会心理学》

数学是学生时代掉头发的学科,那算法是毕业后掉头发的学科。那么如果两者相遇,你会不会更头疼,其实很多算法本身就是数学问题,而且很多数学问题也需要借助算法才能用代码实现。数学的门类有很多,也涉及到很多问题。很多都是相当难的题目。但是在算法中,一半只会选择各个学科中的基础问题来考察,例如素数问题,幂、对数、阶乘、幂运算、初等代数、几何问题、组合数学等待。本次就来讨论一下这些热门的话题。

数字统计专题

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

符号统计

参考题目介绍:1822. 数组元素积的符号 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述

你看下这个题目,如果将所有的数都乘起来,在判断正负的话,工作量真的可以了,还要考虑溢出问题。但是换个思路,如果我们只统计负数的个数呢?是不是就能够判断最后乘积的正负(符号了呢?

    /**
     * 数组元素乘积的符号
     * @param nums
     * @return
     */
    public static int arraySign(int[] nums) {
       int sign = 1;
       for(int i = 0; i < nums.length; i++) {
           // 出现 0 就直接返回
           if (nums[i] == 0){
               return 0;
           }else if (nums[i] < 0){
               sign = -sign;
           }
       }
       return sign;
    }

阶乘0的个数

参考题目地址:面试题 16.05. 阶乘尾数 - 力扣(LeetCode)

在这里插入图片描述
这个题如果硬算,我想也很是头疼,题目的重点是计算有多少个0.转化一下,是计算有多少个2和5一起出现,当然2的次数要大于5的次数,因此我们只需要检查5出现的次数就可以了,那么我们在统计的过程中,我们只需统计5,10,15,25,… 5 * n 这样的整数倍就可以了。然后在累加起来,就知道有多少个0。

代码可以这样写😎:

    /**
     * 阶乘尾数0的个数
     * @param n
     * @return
     */
    public static int trailingZeroes(int n) {
      int cnt = 0;
      for(long num = 5; n / num > 0; num*=5){
          cnt += n / num;
      }
      return cnt;
    }

这个也可以简化求5因子的个数哈哈🤣

数学不仅与算法难以区分,很多算法问题还与位运算密不可分,有些题目真的不好说是不是倍错分了。我们就一块看看吧。

溢出问题

溢出问题是一个极其重要的问题,只要涉及到输出一个数字,都可能遇到,典型的题目有三种:

  • 数字反转
  • 将字符串转成数字
  • 回文数

不过溢出问题也不会单独考察,面试官也不会提醒你,但是你需要留意是不是的陷阱,凡是涉及到输出结果为数字的,需要考虑数学的特有问题。(溢出☠️)

溢出处理的技巧都是一致的,我们学习一下。

整数反转

参考题目地址:7. 整数反转 - 力扣(LeetCode)

在这里插入图片描述

在这里插入图片描述
这个题的关键点有两个:

  1. 怎么反转
  2. 如何处理溢出

反转:用栈 不不不,或者将整数转字符串? 不不不。 我们只需要一边左移一边处理末尾数字就可以了。就比如12345。 我们要的是54321。(可以循环取模解决)

12345        						 54321
12345 % 10 = 5  12345 / 10 = 1234   (5)
1234  % 10 = 4  1234  / 10  = 123   (54)
123   % 10 = 3  123   / 10  = 12    (543)
12    % 10 = 2  12    / 10  = 1     (5432)
1     % 10 = 1  1     / 10  = 0     (54321)

画图就是这样:

在这里插入图片描述

这样的话,是不是将循环的判断条件改为x > 0 就可以了呢? 当然不行(负数呢?) 应该是while(x != 0)。去掉符号,剩下的数字,无论是正数还是负数,按照上面的不到 / 10 这样的操作,最终都会变成0,所以判断终止条件就是 != 0。有了取模和除法操作就可以解决第一个反转问题。

那么怎么处理溢出呢? 这里就要考虑到32为最大整数时MAX=2147483647,如果一个整数num > MAX,那么就应该由一下规律:

  • num / 10 > MAX / 10 = 214748364 (也就是说倒数第二位 大于4,不管是什么都会溢出)

如图:

在这里插入图片描述
所以这里从倒数第二位就开始判断了,

  • 如果 num > 214748364 后面就不用判断了,必定溢出
  • 如果 num = 214748364 需要判断最后一个位数是否大于 7,比7大说明溢出了。
  • 如果 num < 214748364 没问题,可以继续处理。

对于负数也是一样,所以代码可以这样写:

   /**
     * 整数反转
     * @param x
     * @return
     */
    public static int reverse(int x) {
        int res = 0;
        // 注意条件
        while (x != 0) {
            // 获取最后一个余数
            int temp = x % 10;
            // 判断是否溢出
            // 正数溢出
            if (res > 214748364 || res == 214748364 && temp > 7) {
                return 0;
            }

            if (res < -214748364 || res == -214748364 && temp < -8) {
                return 0;
            }
            res = res * 10 + temp;
            x /= 10;
        }
        return res;
    }

当然这里也可以使用 Integer.MAX_VALUE / 10 代替

字符串转整数

参考题目地址:8. 字符串转换整数 (atoi) - 力扣(LeetCode)

这道题我们在字符串章节已经做过了,但是再回顾一下是不是,有理解了很多。请参考看:算法通过村第十二关-字符串|青铜笔记|隐形的王者-CSDN博客

在这里插入图片描述

 public int myAtoi(String s) {
        int index = 0;
        char[] chars = s.toCharArray();
        int n = chars.length;
        // 1.丢掉无用的空格
        while(index < n && chars[index] == ' '){
                index++;
        }
        // 排除一些特殊情况
        if (index == n){
            return 0;
        }
        // 3.这里记录正负数
        int sign = 1;
        char characterOps = chars[index];
        if (characterOps == '+'){
            index ++;
        }else if (characterOps == '-'){
            index ++;
            sign= -1;
        }
        int res = 0;
        // 4.继续循环
        while(index < n){
            char currChar = chars[index];
            // 4.1 判断是否合法
            if (currChar < '0' || currChar > '9'){
                break;
            }
            // 4.2 判断溢出问题
            if (res > Integer.MAX_VALUE / 10 || res == Integer.MAX_VALUE / 10 && (currChar - '0')> Integer.MAX_VALUE % 10 ){
                return Integer.MAX_VALUE;
            }
            if (res < Integer.MIN_VALUE / 10 || res == Integer.MIN_VALUE / 10 && (currChar - '0') > -(Integer.MIN_VALUE % 10) ){
                return Integer.MIN_VALUE;
            }
            res = res*10 + sign*(currChar - '0');
            // 注意index 变化
            index ++;
        }
        return res;
    }

回文数

参考题目介绍:9. 回文数 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
思考如何利用数字特性呢?

第一个想到的是不是上面的转字符串哈哈🤣,然后再检查是不是回文。但是,需要这里增加了额外空间和题目描述不一样。

换一种思路,那我们将数字本身反转,然后将反转后的数字与原始数字进行比较,如果他们时相同的,那么这个数字就是回文。但是如果这个数字反转后溢出了,就属于一出问题了。

接着这个想法:为了避免溢出,我们可以考虑int数字的一半,回文数字嘛,后半部分和前半部分时一样的。

例如:输入1221,我们可以将数组1221 后半部分21 转成 12 并和前半部分比较如果反转后一样就说明回文了。

这个反转思路与链表反转一样的,请参考:算法通过村第二关-链表青铜笔记_师晓峰的博客-CSDN博客,思路一样的。

这里还不能忘记的问题就是,反转之后数字肯会溢出,因此必须要做防护,根据上面的方法我们写一下代码:

    /**
     * 方法2:通过移位计算
     *
     * @param x
     * @return
     */
    public static boolean isPalindrome2(int x) {
        if(x < 0){
            return false;
        }
        long res = 0;
        int old = x;
        while(x > 0){
            res = res * 10 + x % 10;
            x /= 10;
        }
        return res == old;
    }

折半(数字)

    /**
     * 折半查找
     * @param x
     * @return
     */
    public static boolean isPalindrome3(int 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;
        }
        // 当数字长度为奇数时 采用 x == revertedNumber / 10
        // 当数字长度为偶数时 采用 revertedNumber == x 
        return  revertedNumber == x || x == revertedNumber / 10;
    }

进制专题

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

七进制数

参考题目介绍:504. 七进制数 - 力扣(LeetCode)

在这里插入图片描述

我们可以先想想二进制的特征,迁移一下7进制数的。在二进制中,先是 0 ,然后 1。而 2 就是 10(2),3就是11(3) 一次类推。同样在7进制中,计数应该是这样的:

0 1 2 3 4 5 6 10 11 12 13 14 15 16 …

所以 7 进制主要过程也是循环取余和整除【特色】,最后将所有的余数反过来就行了。

例如:将10进制数100转换为七进制:

100 % 7 = 14  余数 2
14  % 7 = 2   余数 0
2   % 7 = 0   余数 2

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

    /**
     * 七进制转换
     * @param num
     * @return
     */
    public static String convertToBase7(int num) {
        StringBuilder sb = new StringBuilder();
        // 先确定到正负号
        boolean sign = num < 0;
        if (sign) {
            num *= -1;
        }
        // 循环取余和整数
        do{
            sb.append(num % 7 + "");
            num /= 7;
        }while(num > 0);
        // 添加符号
        if (sign) {
            sb.append("-");
        }

        // 这里需要反转一下
        StringBuilder res = reverse(sb,0,sb.length() - 1);
        return res.toString();
    }

    public static StringBuilder  reverse(StringBuilder sb, int start, int end) {
        while(start < end){
            char temp = sb.charAt(start);   
            sb.setCharAt(start++,sb.charAt(end));
            sb.setCharAt(end--, temp);
        }
        return sb;
    }

进制转换

给定一个十进制M,以及需要转换的进制数N,将十进制数M转换为N进制数。M是32位整数,2 <= N <= 16。

这个题目思路不复杂,但是想写却很不容易,甚至越写越糊涂。本题有好几个需要处理的问题:

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

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

  1. 首先定义大小为16 的数组F,保存的是2到16的各个进制的值对应的标记,这样赋值计算只需要处理下标,不必考虑不同进制之间的转换问题。
  2. 使用 StringBuffer 完成数组转置等功能,如果不采用这个思路,工作量直接飙升。
  3. 通过一个 flag 来判断正数还是负数,最后才处理。
        /**
         * 将十进制数M转化为N进制数
         *
         * @param M
         * @param N
         * @return
         */
        public static 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.coloradmin.cn/o/1076563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaEE】文件操作

文章目录 前言什么是文件树型结构组织和目录文件路径文件类型文件权限Java中的文件操作File 类的常见属性File 类常见构造方法File 类常用方法 前言 文件是我们日常生活中使用非常广泛的&#xff0c;我们使用任何一个程序都离不开文件操作&#xff0c;这个文件不仅仅指平时可以…

【java学习】变量的分类:成员变量与局部变量(16)

变量的分类 1. 基本概念2. 成员变量3. 局部变量4. 成员变量(属性)和局部变量的区别 1. 基本概念 概念&#xff1a; 在方法体外&#xff0c;类体内声明的变量称为成员变量。在方法体内部声明的变量称为局部变量。 2. 成员变量 实例变量&#xff1a;在类实例化成对象才能使用 …

多线程 - 线程池

线程池 相关的背景知识 线程池存在的意义: 使用进程来实现并发编程,效率太低了,任务太重了,为了提高效率,此时就引入了线程,线程也叫做“轻量级进程”,创建线程比创建进程更高效;销毁线程比销毁进程更高效;调度线程比调度进程更高效…此时,使用多线程就可以在很多时候代替进程…

在美国如何申请批准销售儿童玩具?提交哪些相关文件?需要的认证是?

在美国如何申请批准销售儿童玩具&#xff1f;提交哪些相关文件&#xff1f;需要的认证是&#xff1f;ASTM F963-17 ​在美国销售玩具 重要&#xff1a; 如果您要在亚马逊商城销售商品&#xff0c;则必须遵守适用于这些商品和商品信息的所有联邦、州和地方法律以及亚马逊政策。…

dockerfile lnmp 搭建wordpress、docker-compose搭建wordpress

-----------------安装 Docker--------------------------- 目前 Docker 只能支持 64 位系统。systemctl stop firewalld.service setenforce 0#安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 --------------------------------------------------…

什么是信创测试?信创测试工具有哪些?

信创全称是“信息技术应用创新”&#xff0c;旨在实现信息技术自主可控&#xff0c;规避外部技术制裁和风险&#xff0c;其涉及产业链包括硬件、基础软件、应用软件、云服务、数据安全等领域。 信创测试是指对信创工程项目中的产品、系统等进行测试和验证&#xff0c;以确保其…

【B/S架构】医院不良事件报告系统源码

医院不良事件报告系统为医院内质量控制、患者安全关注、医疗安全不良事件方面的精细化的管理提供了平台&#xff0c;是等级医院评审的必备内容&#xff0c;评审要求医院直报系统要与卫生部“医疗安全(不良)事件报告系统”建立网络对接。 不良事件报告系统源码包括护理相关事件、…

写一个名为Rectangle的类表示矩形

如何使用Rectangle类计算矩形的面积 要求&#xff1a;其属性包括宽width、高height和颜色color&#xff0c;访问权限分别为private&#xff0c;width和height都是double型的&#xff0c;而color则是String类型的。要求该类提供计算面积的方法getArea()方法&#xff0c;以及修改…

Node.js 做 Web 后端的优势在哪?为什么是明智的选择?

当我们谈论构建强大的Web应用程序时&#xff0c;选择适当的后端技术至关重要。在如今的技术领域中&#xff0c;Node.js已经崭露头角&#xff0c;并且越来越多的开发者和企业选择将其作为首选的后端开发工具。但是&#xff0c;Node.js究竟有哪些优势&#xff0c;使得它成为众多开…

WMS仓储管理系统的盘点功能解析

随着电商行业的快速发展&#xff0c;仓储管理在企业的运营中扮演着越来越重要的角色。为了提高仓库的运营效率和管理水平&#xff0c;许多企业引入了WMS仓储管理系统。本文将对WMS仓储管理系统的盘点功能进行解析&#xff0c;探讨其在实际应用中的价值。 一、WMS仓储管理系统概…

【分享】影刀使用xpath捕获指定的元素

xpath捕获元素比较精准&#xff0c;前面也介绍了xpath的用法 现在捕获社区里帖子详情页的标题 //*[class‘discuss_detail_header___3LhnQ’]/h1 找到class是discuss_detail_header___3LhnQ的子元素h1 获取文章内容 //*[id‘w-e-textarea-1’] 找到id是w-e-textarea-1的元…

这短短 6 行代码你能数出几个bug?

前言&#xff1a;本文仅仅只是分享笔者一年前见到的诡异代码&#xff0c;大家可以看看乐子&#xff0c;随便数一数一共有多少个bug&#xff0c;这数bug多少还是要点水平的 在初学编程的时候&#xff0c;写的第一个代码大多都是 hello world&#xff0c;可是就算是 hello world…

如何使用CSS和JavaScript实施暗模式?

近年来&#xff0c;暗模式作为用户界面选项备受追捧。它提供了更暗的背景和更亮的文本&#xff0c;不仅可以减轻眼睛疲劳&#xff0c;还可以节省电池续航时间&#xff0c;尤其是在OLED屏幕上。 不妨了解如何结合使用CSS和JavaScript为网站和Web应用程序添加暗模式选项。 了解暗…

因果图测试用例设计方法介绍(超全的总结笔记错过就没有了)

前言 为什么需要测试用例 测试的目的是在有限的资源下&#xff0c;尽可能多的找出系统的缺陷。这就要求在测试中&#xff0c;尽可能完全的走完系统的所有流程&#xff0c;保证所有的分支都经过测试。 而测试过程是由人来执行的&#xff0c;不可能避免的会遗漏一些应该测试内容…

新增TOP!10月SCI/SSCI/EI刊源表已更新!

2023年10月SCI/SSCI/EI期刊目录更新 2023年10月份刊源表已更新&#xff01;计算机领域新增TOP期刊、SSCI、EI新增多本好刊&#xff0c;重点期刊如下&#xff0c;相关领域作者注意投稿截止时间&#xff01; 01 计算机领域 02 医学与制药领域 03 工程综合领域 04 环境生物化学地…

uniapp实现扫一扫功能,扫码成功后跳转页面

uniapp官方有提供的相关api实现跳转到web网页(h5)的功能,在开发小程序中,是一项很常见的功能开发。该功能使用到的api uni.scanCode 详细步骤如下: 1.在ui库中找到扫码icon,以uViewUI为例 绑定点击事件@click <u-icon class="scanIcon" name="scan…

Maven 项目文档

本章节我们主要学习如何创建 Maven 项目文档。 比如我们在 C:/MVN 目录下&#xff0c;创建了 consumerBanking 项目&#xff0c;Maven 使用下面的命令来快速创建 java 项目&#xff1a; mvn archetype:generate -DgroupIdcom.companyname.bank -DartifactIdconsumerBanking -…

含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度

MATLAB代码&#xff1a;含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度 关键词&#xff1a;冰蓄冷空调 CCHP-MG 多时间尺度优化 冷热电联供 参考文档&#xff1a;《含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度》完全复现 仿真平台&#xff1a;MATLAB yalmipcplex…

PowerShell install 一键部署hfish

hfish前言 HFish是一款社区型免费蜜罐,侧重企业安全场景,从内网失陷检测、外网威胁感知、威胁情报生产三个场景出发,为用户提供可独立操作且实用的功能,通过安全、敏捷、可靠的中低交互蜜罐增加用户在失陷感知和威胁情报领域的能力。 HFish具有超过40种蜜罐环境、提供免费…

修改了windows dns配置,在wsl2中不生效

本地做测试环境&#xff0c;需要劫持dns解析&#xff0c;所以在本地搭dns解析服务&#xff0c;用来劫持域名解析流量&#xff0c;需要将本地dns服务器地址配到127.0.0.1&#xff0c;如图&#xff0c;但是 wsl 中&#xff0c;却没有变化&#xff0c;依然是原来的dns&#xff0c;…