math-special

  • 29、Divide Two Integers
  • 43、multiply strings
  • 50、pow(x,y)
  • 60、Permutation Sequence
  • 66、plus one
  • 67、add binary
  • 69、 Sqrt(x)
  • 166、 Fraction to Recurring Decimal
  • 168、 Excel Sheet Column Title

29. Divide Two Integers

Divide two integers without using multiplication, division and mod operator.
If it is overflow, return MAX_INT.
不使用乘法,除法和求模运算,求两整数相除。

最简单的思路就是累加,但是超时,网上有另一种思路,利用位操作。
知识回顾:http://www.jianshu.com/p/7bba031b11e7

class Solution(object):
    def divide(self, dividend, divisor):
        """
        :type dividend: int
        :type divisor: int
        :rtype: int
        """
        count = 0
        if (dividend < 0 and divisor < 0) or (divisor > 0 and dividend > 0):
            flag = 1
        else:
            flag = -1
        divisor, dividend = abs(divisor), abs(dividend)
        for i in xrange(31, -1, -1):
            if (divisor << i) <= dividend:
                count += 2 ** i
                dividend -= (divisor << i)
        if flag == -1:
            count = -count
        return min(max(-2147483648, count), 2147483647)

有几个要点,第一个是如何处理overflow,python其实不需要处理这样的问题,但题目要求,要注意的是对int型数据(4字节)最大的正数是2**31-1,本来是2**32-1,但是最高位表示正负。负数最小是-2**31,可以多表示一位是因为在计算机中用补码表示负数,之前10000000和00000000都表示0,但补码中发现不用+0和-0表示同一个数,而且-1+(-127)的补码就是10000000,因此可以多表示一位。
原码、反码补码回顾

43、multiply strings

Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2.
Note:
The length of both num1 and num2 is < 110.
Both num1 and num2 contains only digits 0-9.
Both num1 and num2 does not contain any leading zero.
You must not use any built-in BigInteger library or convert the inputs to integer directly.

一时很萌比,实现两个长字符串代表的数字的乘积。

class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        if num1 == '0' or num2 == '0':
            return '0'
        num1, num2 = num1[::-1], num2[::-1]
        res, pre_res = '', ''
        for i in xrange(len(num1)):
            res, carry = '', 0
            res += '0' * i
            for j in num2:
                temp = int(num1[i]) * int(j) + carry
                carry, temp = temp / 10, temp % 10
                res += str(temp)
            if carry:
                res += str(carry)
            pre_res = self.addStr(res, pre_res)

        return pre_res[::-1]

    def addStr(self, list1, list2):
        m, n = len(list1), len(list2)
        assert m >= n
        carry, pre_res = 0, ''
        for i in xrange(n):
            temp = int(list1[i]) + int(list2[i]) + carry
            carry, temp = temp / 10, temp % 10
            pre_res += str(temp)
        for i in list1[n:m]:
            temp = int(i) + carry
            carry, temp = temp / 10, temp % 10
            pre_res += str(temp)
        if carry:
            pre_res += str(carry)

        return pre_res

if __name__ == '__main__':
    s = Solution()
    print s.multiply('999', '999')

效率出奇的低,虽然结果是正确的。

class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        num1, num2 = num1[::-1], num2[::-1]
        res = [0] * (len(num1) + len(num2))
        for i in xrange(len(num1)):
            for j in xrange(len(num2)):
                res[i + j] += int(num1[i]) * int(num2[j])
                res[i + j + 1] += res[i + j] / 10
                res[i + j] %= 10

        # Skip leading 0s.
        i = len(res) - 1
        while i > 0 and res[i] == 0:
            i -= 1
        return ''.join(map(str, res[i::-1]))

50、pow(x,y)

实现幂函数

Example 1:
Input: 2.00000, 10
Output: 1024.00000
Example 2:
Input: 2.10000, 3
Output: 9.26100

题目到底想考什么呢,看起来挺简单的,一步步提交代码发现,发现需要注意的有指数的正负以及 0.000001**2147483647之类的会超时。所以还是很有意思,2**100肯定不能100个2连续相乘,而是可以2**50 x 2**50.
最后借用递归完成为:

class Solution(object):
    def myPow(self, x, n):
        """
        :type x: float
        :type n: int
        :rtype: float
        """

        if n == 0:
            return 1
        if n < 0:
            res = self.myPow(x, -n)
            return 1.0 / res
        temp = self.myPow(x, n / 2)
        if n % 2:
            return temp * temp * x
        else:
            return temp * temp

    def myPow(self, x, n):
        """
        :type x: float
        :type n: int
        :rtype: float
        """
        result = 1
        abs_n = abs(n)
        while abs_n:
            if abs_n & 1:
                result *= x
            abs_n >>= 1
            x *= x

        return 1 / result if n < 0 else result

两种方法效率似乎都只有10-30,有时间看看别的高效的思路。

60、Permutation Sequence

The set [1,2,3,…,n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note: Given n will be between 1 and 9 inclusive.

初步观察,应该具有某些特定的规律.

from math import factorial

class Solution(object):
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        k -= 1
        res = []
        array = list(range(1,n+1))
        for i in xrange(n,1,-1):
            temp = factorial(i-1)
            a, k = k / temp, k % temp
            res.append(str(array[a]))
            array = array[:a] + array[a+1:]
        res.append(str(array[0]))
        return ''.join(res)

上面是自己思路,但是有些细节还是处理不够熟练,一是知道下面规律,但是处理每位数字时比较模糊,只是局限于知道第几位是剩下的第几大的数,比如处理到第二位是3,则只是知道第二位是除去第一位中剩下的大小在第(3+1)位的数,借鉴的下面array处理方法。同时注意到的是调用factorial函数具有重复计算,没有下面简便。

因为n个不同的数字可以组成n!个序列,那么首位确定的序列都有(n-1)!种不同的可能性,而且这些序列都根据首位的大小进行了分组,1...是最小的(n-1)!个,2...是(n-1)!+1到2(n-1)!个,那么现在只需要计算k中有几个(n-1)!就可以确定首位的数字,同样可以通过这样的方法来确定第二位、第三位……

class Solution(object):
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        k -= 1
        factorial = 1
        for i in range(1, n):
            factorial *= i

        result = []
        array = list(range(1, n + 1))
        for i in range(n - 1, 0, -1):
            index = k // factorial
            result.append(str(array[index]))
            array = array[:index] + array[index + 1:]
            k %= factorial
            factorial //= i
        result.append(str(array[0]))
        return "".join(result)

66、plus one

一串数字用列表表示,求加上1之后的列表表示值。

class Solution(object):
    def plusOne(self, digits):
        """
        :type digits: List[int]
        :rtype: List[int]
        """
        digits = digits[::-1]
        carry = 1
        for i in xrange(len(digits)):
            temp = digits[i] + carry
            carry, res = temp / 10, temp % 10
            digits[i] = res
        if carry:
            digits.append(carry)

        return digits[::-1]

67、add binary

将两个字符串表示的二进制数相加。

class Solution(object):
    def addBinary(self, a, b):
        """
        :type a: str
        :type b: str
        :rtype: str
        """
        m, n = len(a), len(b)
        if m > n:
            return self.addBinary(b, a)
        carry, res = 0, ''
        a, b = a[::-1], b[::-1]
        for i in xrange(m):
            temp = int(a[i]) + int(b[i]) + carry
            carry = temp / 2
            res += str(temp % 2)
        for item in b[m:n]:
            temp = int(item) + carry
            carry = temp / 2
            res += str(temp % 2)
        if carry:
            res += str(carry)
        return res[::-1]

另一种,参考


class Solution:
    # @param a, a string
    # @param b, a string
    # @return a string
    def addBinary(self, a, b):
        result, carry, val = "", 0, 0
        for i in xrange(max(len(a), len(b))):
            val = carry
            if i < len(a):
                val += int(a[-(i + 1)])
            if i < len(b): 
                val += int(b[-(i + 1)])
            carry, val = val / 2, val % 2
            result += str(val)
        if carry:
            result += str(carry)
        return result[::-1]

69. Sqrt(x)

实现平方根函数,只要求整数部分。
最简单的就是暴力,从一开始试,复杂度比较高,第二种方法就是用二分法。


class Solution(object):
    def mySqrt(self, x):
        """
        :type x: int
        :rtype: int
        """
        if x == 1 or x == 0:
            return x
        high, low = x,  0
        while low < high:
            middle = (low + high) / 2
            temp = middle * middle
            if temp > x:
                high = middle
            elif temp < x:
                low = middle
            else:
                return middle
            if low + 1 == high:
                return low

另一种方法参考:

class Solution(object):
    def mySqrt(self, x):
        """
        :type x: int
        :rtype: int
        """
        if x < 2:
            return x
        
        left, right = 1, x // 2
        while left <= right:
            mid = left + (right - left) // 2
            if mid > x / mid:
                right = mid - 1
            else:
                left = mid + 1

        return left - 1

166. Fraction to Recurring Decimal

Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
For example,
Given numerator = 1, denominator = 2, return "0.5".
Given numerator = 2, denominator = 1, return "2".
Given numerator = 2, denominator = 3, return "0.(6)".

特殊之处在于要处理循环小数,如果分数是循环小数,循环部分用括号括起来。

class Solution(object):
    def fractionToDecimal(self, numerator, denominator):
        """
        :type numerator: int
        :type denominator: int
        :rtype: str
        """
        if denominator == 0 or numerator == 0:
            return '0'
        if (denominator > 0 and numerator > 0) or (denominator < 0 and numerator < 0):
            res = ''
        else:
            res = '-'
        numerator, denominator = abs(numerator), abs(denominator)
        quo, rem = numerator // denominator, numerator % denominator

        if rem == 0:
            res += str(quo)

        else:
            res = res + str(quo) + '.'
            print res

        lookup = {}
        while rem and rem not in lookup:
            lookup[rem] = len(res)
            rem *= 10
            res += str(rem/denominator)
            rem %= denominator

        if rem in lookup:
            res = res[:lookup[rem]] + '(' + res[lookup[rem]:] + ')'

        return res

要注意的有一是正负号的处理,二是商和除数为0时,最重要的还是如何处理无限循环部分,这也是这道题的关键。

168、 Excel Sheet Column Title

还是会一下转不过弯来,整个思路不是很难,关键要理解整个过程。实际上为 n = a + b*26 + c*26*26 + d*26*26*26 ...., a,b,c,d就是依次的相对于A-Z的输出,要注意下标问题。

class Solution(object):
    def convertToTitle(self, n):
        """
        :type n: int
        :rtype: str
        """
        result = []
        base = ord('A')
        while n:
            n, r = divmod(n - 1, 26)
            result.append(chr(base + r))
        return ''.join(result[::-1])

171. Excel Sheet Column Number

For example:
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28

有史以来最顺手的一道题。

class Solution(object):
    def titleToNumber(self, s):
        """
        :type s: str
        :rtype: int
        """
        s = s[::-1]
        res = 0
        for i, item in enumerate(s):            
            res += (ord(item)-ord('A') + 1) * (26 ** i)
        
        return res

较高效率版:

class Solution(object):
    def titleToNumber(self, s):
        """
        :type s: str
        :rtype: int
        """
        result = 0
        for i in xrange(len(s)):
            result *= 26
            result += ord(s[i]) - ord('A') + 1
        return result

172. Factorial Trailing Zeroes

Given an integer n, return the number of trailing zeroes in n!.
求n的阶乘中尾随0的个数。
比较简单,应该有比较简便的方法。

class Solution(object):
    def trailingZeroes(self, n):
        """
        :type n: int
        :rtype: int
        """
        res,count = 1, 0
        for item in xrange(1, n+1):
            while item % 5 == 0:
                res *= 5
                item /= 5
            while item % 2 == 0:
                res *= 2
                item /= 2
        while res % 10 == 0:
            res /= 10
            count += 1
        return count

    def trailingZeroes1(self, n):
        """
        :type n: int
        :rtype: int
        """
        res, count = 1, 0
        a, b = 0, 0
        for item in xrange(1, n+1):
            while item % 10 == 0:
                count += 1
                item /= 10
            while item % 5 == 0:
                a += 1
                item /= 5
            while item % 2 == 0:
                b += 1
                item /= 2

        return count + min(a,b)

这道题真是考验性能的时候,第一种方法在 4660上超时,第二种方法满心欢喜,挂在 1808548329 上。
还是彻底败了,人类一思考,数学家就发笑。尴尬。

class Solution(object):
    def trailingZeroes(self, n):
        """
        :type n: int
        :rtype: int
        """
        result = 0
        while n > 0:
            result += n / 5
            n /= 5
        return result

在于注意到10=2x5,而2远远多于5的个数,因此只要知道有多少个5就可以,而 10!有10/5=2个,20!有20/5=4个,而且还有一点要注意,目前只是按照简单规律没10个中就有两个5的倍数出现。但是像25,5x5xn之类的会多出来5,需要格外考虑。其实就是
res = floor(n/5) + floor(n/25) + floor(n/125) + ....
一开始总是很扭,n/5是计算的以5为步长,从1到n的个数,也就是5,10,15,20,25,...,但因为不准因此同样思想25为步长在找一遍,125为步长找一遍,这样就比较好理解了。

202、happy number

最大问题在于如何判断在一直循环,如果单独测试完全可以在函数外面单独写一个数据结构。

class Solution(object):
    s = set()
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if 10 < n < 100:
            if n not in self.s:
                self.s.add(n)
            else:
                return False

        res = 0
        while n:
            n, temp = n / 10, n % 10
            res += temp * temp
        if res == 1:
            return True
        else:
            return self.isHappy(res)

上面解法有两个问题,一是只适用于一次性计算,因为set中保存的全局变量会影响下一次的判断。再者,self.s.add(n)的条件(10,100)实际意义不明确。

class Solution(object):
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        s = set()
        res = n
        while True:
            if 10 < res < 100:
                if res not in s:
                    s.add(res)
                else:
                    return False
            var, res = res, 0
            while var:
                var, temp = var / 10, var % 10
                res += temp * temp
            if res == 1:
                return True

上面算法明显解决了第一种中递归引入的不足,有(10,100)的判断后性能明显提升了很多。
参考对比:

class Solution:
    # @param {integer} n
    # @return {boolean}
    def isHappy(self, n):
        lookup = {}
        while n != 1 and n not in lookup:
            lookup[n] = True
            n = self.nextNumber(n)
        return n == 1
    
    def nextNumber(self, n):
        new = 0
        for char in str(n):
            new += int(char)**2
        return new

上面思路是将每个数都保存到字典中。

204. Count Primes

给定一个数,求出比它小的质数。
第一步是判断是否是质数,然后计算个数。考虑用动态规划。
一般方法是用两次循环,逐个数进行判断,但容易造成复杂度太高。如下:

class Solution(object):
    lookup = {}
    def countPrimes(self, n):
        """
        :type n: int
        :rtype: int
        """
        count = 0
        for i in xrange(1, n):
            if self.isPrimes(i):
                count += 1
        return count

    def isPrimes(self, n):
        if n == 1:
            return False
        if n == 2 or n == 3:
            return True
        for i in xrange(2, int(n**0.5)+1):
            if n % i == 0:
                return False
        return True

上面思路在数比较大时会计算超时。
参考:

def countPrimes2(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n < 3:
            return 0
        primes = [True] * n
        primes[0] = primes[1] = False
        for i in range(2, int(n ** 0.5) + 1):
            if primes[i]:
                primes[i * i: n: i] = [False] * len(primes[i * i: n: i])
        return sum(primes)

上面这种思路比较巧,首先建立一个列表,从2开始,实际上一个数的倍数肯定不是质数,可是为什么要从i的平方开始呢。经测试发现primes[2*i: n: i] = [False] * len(primes[2*i: n: i])也是可以正常工作,也比较符合一般的常识。
其实是 厄拉多塞筛法

具体操作:先将 2~n 的各个数放入表中,然后在2的上面画一个圆圈,然后划去2的其他倍数;第一个既未画圈又没有被划去的数是3,将它画圈,再划去3的其他倍数;现在既未画圈又没有被划去的第一个数 是5,将它画圈,并划去5的其他倍数……依次类推,一直到所有小于或等于 n 的各数都画了圈或划去为止。这时,表中画了圈的以及未划去的那些数正好就是小于 n 的素数。
其实,当你要画圈的素数的平方大于 n 时,那么后面没有划去的数都是素数,就不用继续判了

223. Rectangle Area

Find the total area covered by two rectilinear rectangles in a 2D plane.Each rectangle is defined by its bottom left corner and top right corner as shown in the figure.

math-special_第1张图片
Rectangle Area

Assume that the total area is never beyond the maximum possible value of int.
分类讨论的化过于复杂,不可行。

class Solution(object):
    def computeArea(self, A, B, C, D, E, F, G, H):
        """
        :type A: int
        :type B: int
        :type C: int
        :type D: int
        :type E: int
        :type F: int
        :type G: int
        :type H: int
        :rtype: int
        """
        total = (C - A) * (D - B) + (G - E) * (H - F)
        if E >= C or G <= A or B >= H or D <= F:
            return total
        h = min(C, G) - max(A, E) 
        v = min(D, H) - max(B, F)
        area = h * v
        return total - area

还是没有想到上面如此简洁的表达方式。一开始总是陷入分类的小怪圈中,不可自拔。

313. Super Ugly Number

Write a program to find the nth super ugly number.
Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4.
Note:
(1) 1 is a super ugly number for any given primes.
(2) The given numbers in primes are in ascending order.
(3) 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000.
(4) The nth super ugly number is guaranteed to fit in a 32-bit signed integer.

和动态规划中一个题很像,

你可能感兴趣的:(math-special)