Code Ganker: LeetCode总结 -- 数值计算篇

2014年8月22日星期五

LeetCode总结 -- 数值计算篇

数值计算在工业界是非常实用而且常见的具体问题, 所以在面试中出现频率非常高, 几乎可以说是必考题目。 LeetCode中关于数值运算的有以下题目:
Palindrome Number
Reverse Integer
Sqrt(x)
Pow(x, n)
Divide Two Integers
Max Points on a Line
在LeetCode中, 关于数值运算的题目分为三种类型, 下面将进行一一讲解。

第一种类型是最简单的, 就是对整数进行直接操作, 一般来说就是逐位操作, 比如反转, 比较等。 LeetCode中这类题目有Palindrome NumberReverse Integer。 这类题目通常思路很清晰, 要注意的点就是对于边界情况的考虑, 对于数值而言, 主要问题是对于越界情况的考虑。 实际上越界问题是贯穿于所有数值计算题目的常见问题, 下面大多问题都会强调这点。
Palindrome Number中因为只是进行判断, 并不需要修改数字, 所以没有越界问题。 思路比较简单, 就是每次取出最高位和最低位进行比较, 直到相遇或者出现违背条件(也就是不相等)即可返回。 对于Reverse Integer因为需要对数字进行反转, 所以需要注意反转后的数字可能会越界。 对于越界一般都是两种处理方法, 一种是返回最大(或者最小)数字, 一种则是抛出异常, 这个可以跟面试官讨论, 一般来说, 面试只要简单的返回最大最小或者dummy数字就可以了, 但是处理和检查这种corner case(也就是越界)的想法一定要有和跟面试官讨论。

第二种题型是算术运算的题目, 比如乘除法, 阶乘, 开方等, LeetCode中这类题目有Sqrt(x)Pow(x, n)Divide Two Integers。 这种题目有时候看似复杂, 其实还是有几个比较通用的解法的, 下面主要介绍三种方法:
(1)二分法。 二分法是数值计算中很常用和易懂的方法。 基本思路是对于所求运算进行对半切割, 有时是排除一半, 有时则是得到可重复使用的历史数据。 Sqrt(x)就是属于每次排除一半的类型, 对于要求的开方数字进行猜测, 如果大于目标, 则切去大的一半, 否则切去大的一半, 原理跟二分查找是一样的。 Pow(x, n)则是属于重复利用数据的类型, 因为x的n次方实际上是两个x的n/2次方相乘, 所以我们只需要递归一次求出当前x的当前指数的1/2次方, 然后两个相乘就可以最后结果。 二分法很明显都是每次解决一半, 所以时间复杂度通常是O(logn)量级的。
(2)牛顿法。 这种方法可以说主要是数学方法, 不了解原理的朋友可以先看看牛顿法-维基百科Sqrt(x)就非常适合用牛顿法来解决, 因为它的递推式中的项都比较简单。 Pow(x, n)当然原理上也可以用牛顿法解答, 但是因为他的递推式中有项是进行x的开n次方的, 这个计算代价也是相当大的, 如果为了求x的n次方而去每一步求开n次方就没有太大实际意义了, 所以对于这种题我们一般不用牛顿法。
(3)位移法。 这种方法主要基于任何一个整数可以表示成以2的幂为底的一组基的线性组合, 对一个整数进行位数次迭代求解, 因为复杂度是位数的数量, 所以也跟二分法一样是O(logn)量级的。 Pow(x, n)Divide Two Integers就是比较典型可以用这种方法解决的题目。 对于Pow(x, n)可以把n分解成位, 每次左移恰好是当前数的平方, 所以进行位数次迭代后即可以得到结果, 代码中很大的篇幅都是在处理越界问题, 而关于逐位迭代代码却很简短。 Divide Two Integers同样把结果分解成位, 每次对除数进行位移并且减去对应的除数来确定每一位上的结果。 这种方法可能理解起来没有二分法那么直观, 还是要消化一下哈。

第三种题目是解析几何的题目, 一般来说解析几何题目的模型都比较复杂, 而且实现细节比较多, 在面试中并不常见, LeetCode中也只有Max Points on a Line是属于这种题型。 这种题目没有什么通法, 主要就是要理清数学和几何模型, 比如Max Points on a Line中主要是理解判断点在直线的判断公式, 然后进行迭代实现。 实现细节还是比较多的, 需要对一些边界情况仔细考虑。

这篇总结主要列举了LeetCode中关于数值计算的题目, 介绍了这类问题的主要考点(比如越界判断)和常用的几种实用方法, 总体感觉这类问题是在面试中比较难很快写对的题目, 因为有一些边界情况和数值实现的细节。 因为出现频率很高, 还是需要对这类题目重点练习哈。

没有评论:

发表评论