LeetCode算法题:8.字符串转换整数 (atoi)

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−2^31, 2^31 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31 的整数应该被固定为 −2^31 ,大于 2^31 − 1 的整数应该被固定为 2^31 − 1
  6. 返回整数作为最终结果。

注意:

  • 本题中的空白字符只包括空格字符 ' '
  • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。

示例 1:

输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"42"(读入 "42")
           ^
解析得到整数 42 。
由于 "42" 在范围 [-2^31, 2^31 - 1] 内,最终结果为 42 。

示例 2:

输入:s = "   -42"
输出:-42
解释:
第 1 步:"   -42"(读入前导空格,但忽视掉)
            ^
第 2 步:"   -42"(读入 '-' 字符,所以结果应该是负数)
             ^
第 3 步:"   -42"(读入 "42")
               ^
解析得到整数 -42 。
由于 "-42" 在范围 [-2^31, 2^31 - 1] 内,最终结果为 -42 。

示例 3:

输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
         ^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
         ^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
             ^
解析得到整数 4193 。
由于 "4193" 在范围 [-2^31, 2^31 - 1] 内,最终结果为 4193 。

提示:

  • 0 <= s.length <= 200
  • s 由英文字母(大写和小写)、数字(0-9)、' ''+''-''.' 组成

我的解题思路:
正常按逻辑处理就行,先跳过前面的空格和‘0’,然后检查是否有‘-’,没有的话则按正数处理,有的话则最后返回时添加去相反数。然后逐个遍历计算相加,直到不是数字停止。检查数值是否越界,做越界处理。最后返回值

代码:

class Solution {
    public int myAtoi(String s) {
        char[] cs = s.toCharArray();
        int len = s.length();
        int i;
        boolean isNegative = false;
        long result = 0;
        for ( i = 0; i < len && cs[i]==' '; i++) {// 跳过空格
        }
        if(cs[i]=='-'){// 有负号
            isNegative = true;
            i++;
        }
        while (i<len){
            if(cs[i] >= '0'&& cs[i]<='9'){// 是数字
                result = result*10 + (cs[i]-'0');//
            }else{// 不是数字结束
                break;
            }
            i++;
        }
        if(result<Integer.MIN_VALUE){
            result = Integer.MIN_VALUE;
        }
        if (isNegative) result = -result;
        return (int)result;
    }
}

出现错误:
在这里插入图片描述
错误原因:最后判断越界的逻辑写错了,应该是判断是否大于int的最大值,因为之前都没有进行负数处理,所以result一直是正数。

class Solution {
    public int myAtoi(String s) {
        char[] cs = s.toCharArray();
        int len = s.length();
        int i;
        boolean isNegative = false;
        long result = 0;
        for ( i = 0; i < len && cs[i]==' '; i++) {// 跳过空格
        }
        if(cs[i]=='-'){// 有负号
            isNegative = true;
            i++;
        }
        while (i<len){
            if(cs[i] >= '0'&& cs[i]<='9'){// 是数字
                result = result*10 + (cs[i]-'0');//
            }else{// 不是数字结束
                break;
            }
            i++;
        }
        if (isNegative) result = -result;
        if(result>=Integer.MAX_VALUE){
            result = Integer.MAX_VALUE;
        }
        if (result<=Integer.MIN_VALUE){
            result = Integer.MIN_VALUE;
        }
        return (int)result;
    }
}

再次出现错误:
在这里插入图片描述
错误原因:当字符串为空时造成数组下标越界。因此需要在一开始对空数组直接返回0处理。
再次出现错误:
在这里插入图片描述
错误原因,之前修改只是简单的对字符串判空,但是存在跳过空格之后为空字符的情况,因此,可以将判空放在跳过空字符之后。
继续出错:
在这里插入图片描述
错误原因:数值太大,造成long类型都越界且变成负数,因此上述判断是否大于int类型最大值的逻辑不太合理。

整理完上述错误逻辑之后重新梳理解题逻辑:
先将前面的空格全部跳过,然后判断字符串是否遍历完,遍历完则直接返回0,没遍历完则判断下一个字符是否是’+'或者‘-’,然后再对剩余字符遍历。停止条件有三个:

  1. 数值越界,即负数小于-231,或者正数大于231-1
  2. 遇到非数字字符。
  3. 正常遍历完了结束。

对正数和负数分别处理。最终正确题解:

class Solution {
    public int myAtoi(String s) {
        char[] cs = s.toCharArray();
        int len = s.length();
        int i;
        boolean isNegative = false;
        int result = 0;
        for ( i = 0; i < len && cs[i]==' '; i++) {// 跳过空格
        }
        if (i==len){// 字符串已经遍历完了
            return 0;
        }
        if (cs[i]=='-'||cs[i]=='+'){// 有正负号
            if (cs[i]=='-')isNegative = true;
            i++;
        }
        if(isNegative){// 负数处理逻辑
            while (i<len){
                if (cs[i]>='0'&& cs[i]<='9'){//是数字
                   if (result<Integer.MIN_VALUE/10){// 小于最小值了,直接返回最小值
                        result = Integer.MIN_VALUE;
                        return result;
                    }
                    result = result*10 - (cs[i]-'0');
                    if(result>0 ){// 小于最小值了,直接返回最小值
                        result = Integer.MIN_VALUE;
                        return result;
                    }
                }else{// 不是数字,直接结束遍历
                    break;
                }
                i++;
            }
        }else{// 正数处理逻辑
            while (i<len){
                if (cs[i]>='0'&& cs[i]<='9'){//是数字
                    if (result>Integer.MAX_VALUE/10){
                        result = Integer.MAX_VALUE;
                        return result;
                    }
                    result = result*10 + (cs[i]-'0');
                    if(result<0 ){// 大于最小值了,直接返回最大值
                        result = Integer.MAX_VALUE;
                        return result;
                    }
                }else{// 不是数字,直接结束遍历
                    break;
                }
                i++;
            }
        }

       // 正常返回
        return result;
    }
}

在这里插入图片描述
自己题解总结:
1.对于数值越界处理,对正数和负数分开处理,正数时计算之前判断是否大于最大值/10,计算之后判断是否为负数发生越界。负数时计算之前判断是否小于最小值/10,计算之后判断是否为正数发生越界。
2.对于前一步有两个逻辑判断的步骤,下一步必须得考虑清楚每一个逻辑,不落下没处理的逻辑。例如在这里插入图片描述
这里跳过空格有两个逻辑判断都可能结束遍历,则下一步得区分是哪一个条件导致的遍历结束。

官方题解:

class Solution {
    public int myAtoi(String str) {
        Automaton automaton = new Automaton();
        int length = str.length();
        for (int i = 0; i < length; ++i) {
            automaton.get(str.charAt(i));
        }
        return (int) (automaton.sign * automaton.ans);
    }
}

class Automaton {
    public int sign = 1;
    public long ans = 0;
    private String state = "start";
    private Map<String, String[]> table = new HashMap<String, String[]>() {{
        put("start", new String[]{"start", "signed", "in_number", "end"});
        put("signed", new String[]{"end", "end", "in_number", "end"});
        put("in_number", new String[]{"end", "end", "in_number", "end"});
        put("end", new String[]{"end", "end", "end", "end"});
    }};

    public void get(char c) {
        state = table.get(state)[get_col(c)];
        if ("in_number".equals(state)) {
            ans = ans * 10 + c - '0';
            ans = sign == 1 ? Math.min(ans, (long) Integer.MAX_VALUE) : Math.min(ans, -(long) Integer.MIN_VALUE);
        } else if ("signed".equals(state)) {
            sign = c == '+' ? 1 : -1;
        }
    }

    private int get_col(char c) {
        if (c == ' ') {
            return 0;
        }
        if (c == '+' || c == '-') {
            return 1;
        }
        if (Character.isDigit(c)) {
            return 2;
        }
        return 3;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/string-to-integer-atoi/solutions/183164/zi-fu-chuan-zhuan-huan-zheng-shu-atoi-by-leetcode-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思路

字符串处理的题目往往涉及复杂的流程以及条件情况,如果直接上手写程序,一不小心就会写出极其臃肿的代码。

因此,为了有条理地分析每个输入字符的处理方法,我们可以使用自动机这个概念:

我们的程序在每个时刻有一个状态 s,每次从序列中输入一个字符 c,并根据字符 c 转移到下一个状态 s’。这样,我们只需要建立一个覆盖所有情况的从 s 与 c 映射到 s’ 的表格即可解决题目中的问题。
作者:力扣官方题解
链接:https://leetcode.cn/problems/string-to-integer-atoi/solutions/183164/zi-fu-chuan-zhuan-huan-zheng-shu-atoi-by-leetcode-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在这里插入图片描述
说实话,一开始拿到这一题想到过可能可以用这方面去写,但是关于原理完全忘了,也就不敢去写,结果自己一个一个逻辑判断却总是存在漏洞,官方题解太优雅了,对于大多数人应该也都是看一看。这一题对于我更多的启发是在于如何判断int数据溢出。
官方使用了,其中ans为long类型,这就不会造成ans在计算时溢出,然后去区分正负数的情况,正数与int的最大值比较取小,负数与int的最小值的相反数比较取小

ans = sign == 1 ? Math.min(ans, (long) Integer.MAX_VALUE) : Math.min(ans, -(long) Integer.MIN_VALUE);

如果限制了为int类型,则可以使用我上述的方式计算前判断是否将会溢出,以及计算后的值是否溢出。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

NumPy及Matplotlib基本用法

NumPy及Matplotlib基本用法 导语NumPy导入与生成算术运算N维数组广播元素访问 Matplotlib简单图案绘制多函数绘制图像显示参考文献 导语 深度学习中经常需要对图像和矩阵进行操作&#xff0c;好在python提供了Numpy和Matplotlib库&#xff0c;前者类似一个已经定义的数组类&am…

【负载均衡在线OJ项目日记】编译与日志功能开发

目录 日志功能开发 常见的日志等级 日志功能代码 编译功能开发 创建子进程和程序替换 重定向 编译功能代码 日志功能开发 日志在软件开发和运维中起着至关重要的作用&#xff0c;目前我们不谈运维只谈软件开发&#xff1b;日志最大的作用就是用于故障排查和调试&#x…

国货美妆进入新纪元之际,毛戈平打好“高端牌”了吗?

当前&#xff0c;国内美妆市场的格局已发生较大变化。 一边是国际品牌的“退场”&#xff0c;据统计&#xff0c;2023年退出中国市场的海外美妆品牌有20多个&#xff1b;一边是国内美妆品牌正在迎来自己的时代。 根据魔镜洞察数据&#xff0c;2024年一季度&#xff0c;国货彩…

论文辅助笔记:Tempo之modules/lora.py

1 LoRALayer 基类 2 Linear 2.1 __init__ 2.2 reset_parameter & train 2.3 forward 3 MergeLinear 3.1__init__ enable_lora指定了哪些输出特征使用lora 3.2 reset_parameters & zero_pad & merge_AB 3.3 train & forward

纯血鸿蒙APP实战开发——底部面板嵌套列表滑动案例

介绍 本示例主要介绍了利用panel实现底部面板内嵌套列表&#xff0c;分阶段滑动效果场景。 效果图预览 使用说明 点击底部“展开”&#xff0c;弹出panel面板。在panel半展开时&#xff0c;手指向上滑动panel高度充满页面&#xff0c;手指向下滑动panel隐藏。在panel完全展开…

从零开始的软件测试学习之旅(七)接口测试三要素及案例

接口测试三要素及案例 接口测试介绍接口预定义接口测试的主要作用测试接口流程如下接口测试三要素接口测试分类RESTful架构风格RESTful架构三要素要素一要素二要素三 RESTful架构风格实现案例复习复盘 接口测试介绍 接口介绍 不同主体之间进行通信的通道,它应具有一套规范/标准…

Vulnhub项目:NAPPING: 1.0.1

1、靶机介绍 靶机地址&#xff1a;Napping: 1.0.1 ~ VulnHub 2、渗透过程 老规矩&#xff0c;先探测&#xff0c;靶机ip&#xff1a;192.168.56.152 本机ip&#xff1a;192.168.56.146 来看一看靶机开放哪些端口&#xff0c;nmap一下 nmap -sS -sV -A -T5 192.168.56.152 开…

UE5自动生成地形二:自动生成插件

UE5自动生成地形二&#xff1a;自动生成插件 Polycam使用步骤 本篇主要讲解UE5的一些自动生成地形的插件 Polycam 此插件是通过现实的多角度照片自动建模生成地形数据&#xff0c;也是免费的。这里感谢B站up主古道兮峰的分享 Polycam网站 插件下载地址 插件网盘下载 提取码&a…

6.移除元素

文章目录 题目简介题目解答解法一&#xff1a;双指针代码&#xff1a;复杂度分析&#xff1a; 解法二&#xff1a;双指针优化代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 相关的讲解&#xff01;&#x1f600; 题目简…

Portforge:一款功能强大的轻量级端口混淆工具

关于Portforge Portforge是一款功能强大的轻量级端口混淆工具&#xff0c;该工具使用Crystal语言开发&#xff0c;可以帮助广大研究人员防止网络映射&#xff0c;这样一来&#xff0c;他人就无法查看到你设备正在运行&#xff08;或没有运行&#xff09;的服务和程序了。简而言…

数据库(MySQL)—— 初识和创建用户

数据库&#xff08;MySQL&#xff09;—— 初识 什么是数据库数据库的种类创建用户mysql -h 主机名或IP地址 -u 用户名 -p 登录mysqlSELECT USER(); 查看当前用户切换用户GRANT ALL PRIVILEGES ON 赋予用户权限 REVOKE 撤销权限示例注意事项 MySQL的图形化界面工具查看所有用户…

ldap对接jenkins

ldap结构 配置 - jenkins进入到 系统管理–>全局安全配置 - 安全域 选择ldap - 配置ldap服务器地址&#xff0c;和配置ldap顶层唯一标识名 配置用户搜索路径 - 配置管理员DN和密码 测试认证是否OK

【xxl-job | 第三篇】SpringBoot整合xxl-job

文章目录 3.SpringBoot整合xxl-job3.1定时任务服务配置3.1.1导入maven依赖3.1.2yml配置3.1.3XxlJobConfig配置类3.1.4定时任务类 3.2xxl-job配置3.2.1新增执行器3.2.2新增任务3.2.3执行任务3.2.4查看日志3.2.5查看任务后台日志 3.3小结 3.SpringBoot整合xxl-job 3.1定时任务服…

B端UX/UI设计面试作品集分层源文件figmasketch模板

当您考虑找工作时&#xff0c;是否曾质疑过项目复盘作品集的重要性&#xff1f;实际上&#xff0c;一份精心准备的项目复盘作品集对于求职者来说具有无可估量的价值&#xff0c;特别是对于设计师这一职业领域。 以下所述或许对您而言已非陌生。您的作品集应当成为您专业技能与…

嵌入式linux学习第三天汇编语言点灯

嵌入式linux学习第三天汇编语言点灯 今天学习如何在linux板子上点灯。 I.MX6U GPIO 详解 我们发现I.MX6U GPIO是分为两类的&#xff0c;&#xff1a;SNVS 域的和通用的。在讨论i.MX6U或类似的复杂微处理器时&#xff0c;了解其GPIO&#xff08;通用输入输出&#xff09;引脚…

vivado Zynq UltraScale+ MPSoC 比特流设置

Zynq UltraScale MPSoC 比特流设置 下表所示 Zynq UltraScale MPSoC 器件的器件配置设置可搭配 set_property <Setting> <Value> [current_design] Vivado 工具 Tcl 命令一起使用。

科研学习|可视化——ggplot2版本的网络可视化

ggplot2是R语言中一个非常流行的数据可视化包&#xff0c;它也可以用于网络可视化。以下是三个基于ggplot2并专门用于网络可视化的R包&#xff1a; ggnet2: 这个包的使用方法与传统的plot函数相似&#xff0c;易于使用。更多信息可在其官方页面查看&#xff1a;ggnet2 geomnet…

python+flask+ldap3搭建简易版IDaaS系统(前端站点)

Python工具开源专栏 Py0006 pythonflaskldap3搭建简易版IDaaS系统&#xff08;前端站点&#xff09; Python工具开源专栏前言目录结构前端网站的部分演示首页查询数据数据同步数据关联查询系统日志 完整代码已在GitHub上开源 前言 pythonflaskldap3搭建简易版IDaaS系统的前端站…

VALSE 2024 Tutorial内容总结--开放词汇视觉感知

视觉与学习青年学者研讨会&#xff08;VALSE&#xff09;旨在为从事计算机视觉、图像处理、模式识别与机器学习研究的中国青年学者提供一个广泛而深入的学术交流平台。该平台旨在促进国内青年学者的思想交流和学术合作&#xff0c;以期在相关领域做出显著的学术贡献&#xff0c…

【Linux进程信号(一)】信号概念/产生/保存/处理

目录 入门 前&后台进程 前台进程&#xff1a; 后台进程 常用命令 ./XXX & fg命令 & bg命令 Ctrl c / Ctrl \ 信号的概念 信号的产生 1.键盘产生 2.系统调用指令 3.异常 4.软件条件 信号的保存 信号的处理 1.信号屏蔽字 2.未决信号表 3.信号处理…
最新文章