• 编程之法:面试和算法心得(字符串转换成整数)


    内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java

    题目描述

    输入一个由数字组成的字符串,把它转换成整数并输出。例如:输入字符串"123",输出整数123。

    分析与解法

    本题考查的实际上就是字符串转换成整数的问题,或者说是要你自行实现atoi函数。那如何实现把表示整数的字符串正确地转换成整数呢?以"123"作为例子:

    • 当我们扫描到字符串的第一个字符'1'时,由于我们知道这是第一位,所以得到数字1。
    • 当扫描到第二个数字'2'时,而之前我们知道前面有一个1,所以便在后面加上一个数字2,那前面的1相当于10,因此得到数字:1*10+2=12。
    • 继续扫描到字符'3','3'的前面已经有了12,由于前面的12相当于120,加上后面扫描到的3,最终得到的数是:12*10+3=123。

    因此,此题的基本思路便是:从左至右扫描字符串,把之前得到的数字乘以10,再加上当前字符表示的数字。

    思路有了,你可能不假思索,写下如下代码:

    public static int strToInt1(String s)
        {
            int n=0;
            for(int i=0;i<s.length();i++)
            {
                n = n*10+Character.getNumericValue(s.charAt(i));
            }
            return n;
        }

    显然,上述代码忽略了以下细节:

    1. 空指针输入:输入的是指针,在访问空指针时程序会崩溃,因此在使用指针之前需要先判断指针是否为空。(由于是java不存在空指针异常
    2. 正负符号:整数不仅包含数字,还有可能是以'+'或'-'开头表示正负整数,因此如果第一个字符是'-'号,则要把得到的整数转换成负整数。
    3. 非法字符:输入的字符串中可能含有不是数字的字符。因此,每当碰到这些非法的字符,程序应停止转换。
    4. 整型溢出:输入的数字是以字符串的形式输入,因此输入一个很长的字符串将可能导致溢出。

    首先我们处理问题2和3

    思路很简单判断首位如果是+或者数字则为正数,如果是-则为负数。如果是其他字符则抛出异常。循环的过程中检查如果不为数字则抛出异常

    代码如下

    /*
         * 从左至右扫描字符串,把之前得到的数字乘以10,再加上当前字符表示的数字
         * 无法处理超界限输入
         */
        public static int strToInt2(String s) throws Exception
        {
            int n=0;
            if(s.charAt(0)=='+')
            {
                for(int i=1;i<s.length();i++)
                {
                    if((int)s.charAt(i)>=48&&(int)s.charAt(i)<=57)
                    {
                        n = n*10+Character.getNumericValue(s.charAt(i));
                    }
                    else {
                        throw new Exception("非首位必需为数字");
                    }
                }
                return n;
            }
            else if(s.charAt(0)=='-')
            {
                for(int i=1;i<s.length();i++)
                {
                    if((int)s.charAt(i)>=48&&(int)s.charAt(i)<=57)
                    {
                        n = n*10+Character.getNumericValue(s.charAt(i));
                    }
                    else {
                        throw new Exception("非首位必需为数字");
                    }
                }
                return 0-n;
            }
            else if((int)s.charAt(0)>=48&&(int)s.charAt(0)<=57)
            {
                for(int i=0;i<s.length();i++)
                {
                    if((int)s.charAt(i)>=48&&(int)s.charAt(i)<=57)
                    {
                        n = n*10+Character.getNumericValue(s.charAt(i));
                    }
                    else {
                        throw new Exception("非首位必需为数字");
                    }
                }
                return n;
            }
            else {
                throw new Exception("首位只能为+、-或数字");
            }
        }

    一般说来,当发生溢出时,取最大或最小的int值。即大于正整数能表示的范围时返回MAX_INT:2147483647;小于负整数能表示的范围时返回MIN_INT:-2147483648。

    现在重点看看如何处理溢出

    比较n和MAX_INT / 10的大小,即:

    • 若n > MAX_INT / 10,那么说明最后一步转换时,n*10必定大于MAX_INT,所以在得知n > MAX_INT / 10时,当即返回MAX_INT。
    • 若n == MAX_INT / 10时,那么比较最后一个数字c跟MAX_INT % 10的大小,即如果n == MAX_INT / 10且c > MAX_INT % 10,则照样返回MAX_INT。

    对于上面第二种方式,先举两个例子说明下:

    • 如果我们要转换的字符串是"2147483697",那么当我扫描到字符'9'时,判断出214748369 > MAX_INT / 10 = 2147483647 / 10 = 214748364(C语言里,整数相除自动取整,不留小数),则返回MAX_INT;
    • 如果我们要转换的字符串是"2147483648",那么判断最后一个字符'8'所代表的数字8与MAX_INT % 10 = 7的大小,前者大,依然返回MAX_INT。

    一直以来,我们努力的目的归根结底是为了更好的处理溢出,但上述第二种处理方式考虑到直接计算n 10 + c 可能会大于MAX_INT导致溢出,那么便两边同时除以10,只比较n和MAX_INT / 10的大小,从而巧妙的规避了计算n10这一乘法步骤,转换成计算除法MAX_INT/10代替,不能不说此法颇妙。

    代码如下

    /*
         * 从左至右扫描字符串,把之前得到的数字乘以10,再加上当前字符表示的数字
         */
        public static int strToInt3(String s) throws Exception
        {
            int n=0;
            int maxInt = Integer.MAX_VALUE;
            int minInt = Integer.MIN_VALUE;
            if(s.charAt(0)=='+')
            {
                for(int i=1;i<s.length();i++)
                {
                    if((int)s.charAt(i)>=48&&(int)s.charAt(i)<=57)
                    {
                        if(n<maxInt/10||(n==maxInt/10&&maxInt%10>Character.getNumericValue(s.charAt(i))))
                        {
                            n = n*10+Character.getNumericValue(s.charAt(i));
                        }
                        else {
                            return maxInt;
                        }
                        
                    }
                    else {
                        throw new Exception("非首位必需为数字");
                    }
                }
                return n;
            }
            else if(s.charAt(0)=='-')
            {
                for(int i=1;i<s.length();i++)
                {
                    if((int)s.charAt(i)>=48&&(int)s.charAt(i)<=57)
                    {
                        if(n>minInt/10||(n==minInt/10&&(0-maxInt%10)>Character.getNumericValue(s.charAt(i))))
                        {
                            n = n*10-Character.getNumericValue(s.charAt(i));
                        }
                        else {
                            return minInt;
                        }
                    }
                    else {
                        throw new Exception("非首位必需为数字");
                    }
                }
                return n;
            }
            else if((int)s.charAt(0)>=48&&(int)s.charAt(0)<=57)
            {
                for(int i=0;i<s.length();i++)
                {
                    if((int)s.charAt(i)>=48&&(int)s.charAt(i)<=57)
                    {
                        if(n<maxInt/10||(n==maxInt/10&&maxInt%10>Character.getNumericValue(s.charAt(i))))
                        {
                            n = n*10+Character.getNumericValue(s.charAt(i));
                        }
                        else {
                            return maxInt;
                        }
                    }
                    else {
                        throw new Exception("非首位必需为数字");
                    }
                }
                return n;
            }
            else {
                throw new Exception("首位只能为+、-或数字");
            }
        }

    其实代码思路上没有什么难度,主要问题在于各种异常的处理,这也是考验代码是否严谨。例如如果判断是否溢出用N*10这样则不能避免溢出。

  • 相关阅读:
    linux反汇编
    Java中UML图
    Java设计模式_创建型模式_单例模式
    Javadoc注释的用法
    VIM使用技巧1
    手动破解的 Linux下的Maltab 2014b
    让vim的在输入模式下现实光标不同
    Vim 自动补全成对的括号和引号
    MAMP:在 OSX 中搭建 Apache, MySQL, PHP 环境并本地安装、调试 WordPress
    MAC+iTerm定制目录显示颜色和提示符
  • 原文地址:https://www.cnblogs.com/icysnow/p/8182817.html
Copyright © 2020-2023  润新知