面试算法题(3)--编写算法:字符串类型的小数转换成double类型的小数值

自己编写算法,将一个字符串类型的小数,转换成double类型的小数。
比喻:"15.246"转换成15.246,不能使用系统提供的Integer.parseInt和Double.parseDouble等方法。


初步一想,感觉是没办法啊。
其实不难,我之前讲过一个类似的例子,
两个大数相加:https://blog.csdn.net/fesdgasdgasdg/article/details/80953829
使用对应字符与'0'的ASCII相减,得到对应的字面值即可。


嗯,这个确实可以实现,转换成int类型就简单了。但是,小数怎么办?
以小数点为分隔符,切割成两个字符串,然后各自转换成int类型,然后再后期处理成double即可。
嗯,理解。简单了,下面开始描述性的演示"15.246"例子:

String str = "15.246";
先以小数点为分隔符,拆分成两个子字符串:
String[] arr = str.split("\\.");
注意上面步骤,为什么split时,需要\\符号?因为split的参数是正则表达式,正则中的.代表什么?自己去查一查吧。


在正则中
\\.表示字符.
\\\\表示字符串\\


那么arr数组的内容就是{"15","246"},我们先只考虑同时包含整数小数的情况


字符串"15"如何转换成int类型的15?
十位值 = ('1' - '0') * 10 = 10
个位值 = ('5' - '0') * 1 = 5
总和 = 15
注意,每个位上的数字,需要乘以位的单位。


同样的步骤,小数部分也得到了对应的int值246,然后想办法让246转换成0.246.
最后结果 = 15 + 0.246 = 15.246。
大致思路如上,我们开始撸点代码:
private static double toDouble(String str) {
	if (str == null || "".equals(str.trim())) {
		return 0;
	}
	str = str.trim();
	//整个字符串直面值结果
	double result = 0;
	//先把字符串的小数,以小数点分割切开成两部分小数(注意正则)
	String[] strNumArr = str.split("\\.");
	//先处理整数部分的数字,转换成int数字
	int intNumResult = 0;
	for (int i = 0; i < strNumArr[0].length(); i++) {
		int val = strNumArr[0].charAt(i) - '0';
		//获得当前字符的字面整数值,然后乘以当前位的进制值
		intNumResult += val * makeInteger10N(strNumArr[0].length() - i - 1);
	}
	//存储小数部分的整数值
	int decimalNumResult = 0;
	//strNumArr数组的长度大于1,证明原始字符串有小数部分
	for (int i = 0; i < strNumArr[1].length(); i++) {
		int val = strNumArr[1].charAt(i) - '0';
		//获得当前字符的字面整数值,然后乘以当前位的进制值
		decimalNumResult += val * makeInteger10N(strNumArr[1].length() - i - 1);
	}
	//保存小数部分最终结果
	result = decimalNumResult * makeDecimal01N(strNumArr[1].length());
	//加上之前的整数部分
	result += intNumResult;
	return result;
}
上面出现了两个函数,一个是构造整数十进制位的单位,即1、10、100等
另一个是构造小数值,即0.1、0.01、0.001,目的是转换上小数部分的int值为小数值。


/**
 * 构造10的n倍数
 *
 * @return
 */
private static int makeInteger10N(int n) {
	int i = 1;
	for (int j = 0; j < n; j++) {
		i *= 10;
	}
	return i;
}

/**
 * 构造小数n个10分之一
 *
 * @return
 */
private static double makeDecimal01N(int n) {
	double i = 1;
	for (int j = 0; j < n; j++) {
		i /= 10;
	}
	return i;
}
大概的代码撸完了,思路原理也讲了。面试时如果写到这里算是过关了。
但是,如果追求完美的话,上面的代码是有问题的。
1、如果字符串不包含小数点呢?如:"13"
2、如果字符串前面包含符号呢?如:"+24","-156"
3、如果字符串只包含小数部分呢?如:".246","-.132"
4、如果字符串还包含无效字符呢?如:"ff2.67","-1hh5.246","-1a2.5a5"


处理起来很简单,对于正负符号,需要在最后的结果乘以 -1 与否 即可。
对于其他的无效字符,判断 '?' - '0' 结果是否在0 ~ 9之间即可得知。


最后贴出完整代码:


public class ConvertToDouble {
    public static void main(String[] args) {
        String strDouble = "-12.25";
        double result = toDouble(strDouble);
        System.out.println(result);
    }

    private static double toDouble(String str) {
        if (str == null || "".equals(str.trim())) {
            return 0;
        }
        str = str.trim();
        boolean isMinus = false;
        if (str.startsWith("-")) {
            //是负数
            isMinus = true;
            //去除负号
            str = str.substring(1);
        }
        //整个字符串直面值结果
        double result = 0;
        //先把字符串的小数,以小数点分割切开成两部分小数(注意正则)
        String[] strNumArr = str.split("\\.");
        //先处理整数部分的数字,转换成int数字
        int intNumResult = 0;
        for (int i = 0; i < strNumArr[0].length(); i++) {
            int val = strNumArr[0].charAt(i) - '0';
            if (val < 0 || val > 9) {
                //非数字
                intNumResult /= 10;
                continue;
            }
            //获得当前字符的字面整数值,然后乘以当前位的进制值
            intNumResult += val * makeInteger10N(strNumArr[0].length() - i - 1);
        }
        //存储小数部分的整数值
        int decimalNumResult = 0;
        if (strNumArr.length > 1) {
            //记录非法字符个数
            int numNaN = 0;
            //strNumArr数组的长度大于1,证明原始字符串有小数部分
            for (int i = 0; i < strNumArr[1].length(); i++) {
                int val = strNumArr[1].charAt(i) - '0';
                if (val < 0 || val > 9) {
                    //非数字
                    decimalNumResult /= 10;
                    numNaN++;
                    continue;
                }
                //获得当前字符的字面整数值,然后乘以当前位的进制值
                decimalNumResult += val * makeInteger10N(strNumArr[1].length() - i - 1);
            }
            //保存小数部分最终结果
            result = decimalNumResult * makeDecimal01N(strNumArr[1].length() - numNaN);
        }
        //加上之前的整数部分
        result += intNumResult;
        //加上数值负号
        if (isMinus) {
            result *= -1;
        }
        return result;
    }

    /**
     * 构造10的n倍数
     *
     * @return
     */
    private static int makeInteger10N(int n) {
        int i = 1;
        for (int j = 0; j < n; j++) {
            i *= 10;
        }
        return i;
    }

    /**
     * 构造小数n个10分之一
     *
     * @return
     */
    private static double makeDecimal01N(int n) {
        double i = 1;
        for (int j = 0; j < n; j++) {
            i /= 10;
        }
        return i;
    }
}



猜你喜欢

转载自blog.csdn.net/fesdgasdgasdg/article/details/80993045