博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
剑指Offer(Java版):把字符串转换成整数
阅读量:5974 次
发布时间:2019-06-19

本文共 7651 字,大约阅读时间需要 25 分钟。

hot3.png

题目:实现一个函数 stringToInt,实现把字符串转换成整数这个功能,不能使用 atoi 或者其他类似的库函数。

题目解析

这看起来是很简单的题目,实现基本功能 ,大部分人都能用10行之内的代码解决。可是,当我们要把很多特殊情况即测试用例都考虑进去,却不是件容易的事。解决数值转换问题本身并不难,但我希望在 写转换数值的代码之前,应聘者至少能把空指针,空字符串”“,正负号,溢出等方方面面的测试用例都考虑到,并且在写代码的时候对这些特殊的输入都定义好合 理的输出。当然,这些输出并不一定要和atoi完全保持一致,但必须要有显式的说明,和面试官沟通好。

这个应聘者最大的问题就是还没有养成在写代码之前考虑所有可能的测试用例的习惯,逻辑不够严谨,因此一开始的代码只处理了最基本的数值转换。后来我 每次提醒他一处特殊的测试用例之后,他改一处代码。尽管他已经做了两次修改,但仍然有不少很明显的漏洞,特殊输入空字符串”“,边界条件比如最大的正整数 与最小的负整数等。由于这道题思路本身不难,因此我希望他把问题考虑得极可能周到,代码尽量写完整。

概括起来有几种情况

1)字符串开头是“+”号或“-”号的处理

2)非法字符的判断(不是数字)

3)整数溢出问题。

看看Java函数库中的Integer.parseInt(String sting)的源码如何处理这些问题的。

/** * Parses the specified string as a signed decimal integer value. The ASCII * character \u002d ('-') is recognized as the minus sign. * * @param string *			the string representation of an integer value. * @return the primitive integer value represented by {@code string}. * @throws NumberFormatException *			 if {@code string} cannot be parsed as an integer value. */public static int parseInt(String string) throws NumberFormatException {  return parseInt(string, 10);} /** * Parses the specified string as a signed integer value using the specified * radix. The ASCII character \u002d ('-') is recognized as the minus sign. * * @param string *			the string representation of an integer value. * @param radix *			the radix to use when parsing. * @return the primitive integer value represented by {@code string} using *		 {@code radix}. * @throws NumberFormatException *			 if {@code string} cannot be parsed as an integer value, *			 or {@code radix < Character.MIN_RADIX || *			 radix > Character.MAX_RADIX}. */public static int parseInt(String string, int radix) throws NumberFormatException {  if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {    throw new NumberFormatException("Invalid radix: " + radix);  }  if (string == null) {    throw invalidInt(string);  }  int length = string.length(), i = 0;  if (length == 0) {    throw invalidInt(string);  }  boolean negative = string.charAt(i) == '-';  if (negative && ++i == length) {    throw invalidInt(string);  }   return parse(string, i, radix, negative);} private static int parse(String string, int offset, int radix, boolean negative) throws NumberFormatException {  int max = Integer.MIN_VALUE / radix;  int result = 0, length = string.length();  while (offset < length) {    int digit = Character.digit(string.charAt(offset++), radix);    if (digit == -1) {      throw invalidInt(string);    }    if (max > result) {      throw invalidInt(string);    }    int next = result * radix - digit;    if (next > result) {      throw invalidInt(string);    }    result = next;  }  if (!negative) {    result = -result;    if (result < 0) {      throw invalidInt(string);    }  }  return result;}

 parseInt(String string,  int  radix)判断了

1) radix进制超出范围 ( Character. MIN_RADIX  = 2, Character. MAX_RADIX )=36)

2)字符串为null

3)字符串长度为空

4)字符串第一位为“-”且只有一位

  没有异常之后进行 parse(String string,  int  offset,  int  radix,  boolean  negative) 判断,参数即字符串,偏移量,进制, negative (如果开头没有“-”则offset=0,negative=false,否则为offset=1,neagtive=true)

   在 parse(String string,  int  offset,  int  radix,  boolean  negative)主要进行了溢出的判断。利用 offset++来控制移动,  在 while  (offset < length)  循环中 直到倒数 第二位的时候,如果已经 小于  max = Integer.MIN_VALUE / radix 的话表明一定会溢出。例如"-2147483648"

倒数第二位的时候 :result= -214748364,max = -214748364,max>result不成立表明 可以进行最后一位的处理。

如下代码:

package cglib;

public class jiekou {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        try {
          System.out.println(parseInt("cao21'''474fefda8364fe7"));
          //System.out.println(parseInt(""));
          System.out.println(parseInt(null));
          System.out.println(parseInt("-2147483648"));
          System.out.println(parseInt("-2147483651"));
          System.out.println(parseInt("-2147483648"));
          System.out.println(parseInt("-21474836410"));
        } catch (MyException e) {
          // TODO 自动生成的 catch 块
          e.printStackTrace();
        }
    
      }
    
      private static int parseInt(String string) throws MyException {
        /* 异常情况1:字符串为null */
        if (string == null) {
          throw new MyException("字符串为null!");
        }
        int length = string.length(), offset = 0;
        /* 异常情况2:字符串长度为0 */
        if (length == 0) {
          throw new MyException("字符串长度为0!");
        }
        boolean negative = string.charAt(offset) == '-';
        /* 异常情况3:字符串为'-' */
        if (negative && ++offset == length) {
          throw new MyException("字符串为:'-'!");
        }
        int result = 0;
        char[] temp = string.toCharArray();
        while (offset < length) {
          char digit = temp[offset++];
          if (digit <= '9' && digit >= '0') {
            int currentDigit = digit - '0';
            /*
             * 异常情况4:已经等于Integer.MAX_VALUE / 10,判断要添加的最后一位的情况:
             * 如果是负数的话,最后一位最大是8 如果是正数的话最后一位最大是7
             */
            if (result == Integer.MAX_VALUE / 10) {
    
              if ((negative == false && currentDigit > 7)
                  || (negative && currentDigit > 8)) {
                throw new MyException("溢出!");
              }
              /*
               * 异常情况5:已经大于Integer.MAX_VALUE / 10
               * 无论最后一位是什么都会超过Integer.MAX_VALUE
               */
            } else if (result > Integer.MAX_VALUE / 10) {
              throw new MyException("溢出!");
            }
    
            int next = result * 10 + currentDigit;
            result = next;
          }
        }
        if (negative) {
          result = -result;
        }
        return result;
      }
    
    }
    
    /* 自定义异常 */
    @SuppressWarnings("serial")
    class MyException extends Exception {
      /**
       *
       */
      @SuppressWarnings("unused")
    private static  long serialVersionUID = 1749149488419303367L;
      String message;
    
      public MyException(String message) {
        // TODO 自动生成的构造函数存根
        this.message = message;
      }
    
      @Override
      public String getMessage() {
        // TODO 自动生成的方法存根
        return message;
      }
    }
   输出:

147483647

cglib.MyException: 字符串为null!
    at cglib.jiekou.parseInt(jiekou.java:25)
    at cglib.jiekou.main(jiekou.java:10)

 

或者:

package cglib;

public class jiekou {
    /**
     * 题目:实现一个函数stringToInt,实现把字符串转换成整数这个功能,
     * 不能使用atoi或者其他类似的库函数。
     *
     * num
     *
     */
    public static int stringToInt(String num) {
        if (num == null || num.length() < 1) {
            throw new NumberFormatException(num);
        }
        char first = num.charAt(0);
        if (first == '-') {
            return parseString(num, 1, false);
        } else if (first == '+') {
            return parseString(num, 1, true);
        } else if (first <= '9' && first >= '0') {
            return parseString(num, 0, true);
        } else {
            throw new NumberFormatException(num);
        }
    }
    /**
     * 判断字符是否是数字
     *
     * @param c 字符
     * @return true是,false否
     */
    private static boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }
    /**
     * 对字符串进行解析
     *
     * @param num      数字串
     * @param index    开始解析的索引
     * @param positive 是正数还是负数
     * @return 返回结果
     */
    private static int parseString(String num, int index, boolean positive) {
        if (index >= num.length()) {
            throw new NumberFormatException(num);
        }
        int result;
        long tmp = 0;
        while (index < num.length() && isDigit(num.charAt(index))) {
            tmp = tmp * 10 + num.charAt(index) - '0';
            // 保证求的得的值不超出整数的最大绝对值
            if (tmp > 0x8000_0000L) {
                throw new NumberFormatException(num);
            }
            index++;
        }
        if (positive) {
            if (tmp >= 0x8000_0000L) {
                throw new NumberFormatException(num);
            } else {
                result = (int) tmp;
            }
        } else {
            if (tmp == 0x8000_0000L) {
                result = 0x8000_0000;
            } else {
                result = (int) -tmp;
            }
        }
        return result;
    }
    public static void main(String[] args) {
      //System.out.println(Integer.parseInt(Integer.MIN_VALUE + ""));
     //   System.out.println(0x8000_0000L);
     //   System.out.println(stringToInt(""));
        System.out.println(stringToInt("123"));
        System.out.println(stringToInt("+123"));
        System.out.println(stringToInt("-123"));
        System.out.println(stringToInt("aaa"));
        System.out.println(stringToInt("+2147483647"));
        System.out.println(stringToInt("-2147483647"));
        System.out.println(stringToInt("+2147483648"));
        System.out.println(stringToInt("-2147483648"));
      System.out.println(stringToInt("+2147483649"));
      System.out.println(stringToInt("-2147483649"));
       System.out.println(stringToInt("+"));
        System.out.println(stringToInt("-"));
    }
    }
    

输出:
Exception in thread "main" java.lang.NumberFormatException: aaa
    at cglib.jiekou.stringToInt(jiekou.java:24)
    at cglib.jiekou.main(jiekou.java:80)
123
123
-123

 

转载于:https://my.oschina.net/u/2822116/blog/729592

你可能感兴趣的文章
MD5 加密原理(转)
查看>>
js http 请求 多个相同参数名传值
查看>>
sqlserver数据库三范式的理解
查看>>
Python 进阶_函数式编程
查看>>
手动配置 ESXi 主机挂载 NFS 的最大值
查看>>
数据结构与算法
查看>>
1.2封装数组之添加元素
查看>>
使用react的一点提醒17/10/26
查看>>
一步一步学习SignalR进行实时通信_7_非代理
查看>>
UDP可靠传输那些事(转)
查看>>
在CenOS7.5里安装Redis
查看>>
ionic+angularJS+cordova(FileTransfer)上传图片
查看>>
SNS的盈利模式分析
查看>>
矩阵快速幂模板
查看>>
利用express搭建一个restful api 服务器
查看>>
(转)调整.NET控件WebBrowser的默认浏览器内核版本
查看>>
HDU4116 Fruit Ninja (2011 Asia ChengDu Regional Contest)
查看>>
2017day2
查看>>
IPSec
查看>>
关于使用Java开发Mis系统
查看>>