【Leetcode】数与位

  • 题目汇总

能完成:7/168/172/191/263/326/405/461/492/507/693

要优化:231/258/400

不会做:50/372

  • 基础操作总结

转二进制:bin(n).replace('0b','')    #因为bin生成的二进制字符串会带有'0b'的前缀

  • 基础数学知识

乘法在取模的意义下满足分配律    即: (a*b) % m = (a%m * b%m) % m

完全数:所有的真因子(即除了自身以外的约数)之和恰好等于它本身     32位内只有5位完全数{6, 28, 496, 8128, 33550336}

数根:将一正整数的各个位数相加(即横向相加),若加完后的值大于10的话,则继续将各位数进行横向相加直到其值为个位数为止;    数根=对9取余的结果

  •  优化思路
231

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。

进阶:不使用循环/递归

思路一:转二进制后判断是否有且仅有一个1     return n > 0 and bin(n).count('1') == 1

trickbinary&(binary-1)                                  return n > 0 and (n & (n-1)) == 0

            若只有1个1,则(binary-1)会出现退位,该位置的1消失,进行按位与操作只能得到0

            若有2个及以上的1,则(binary-1)会出现退位,但高位的1仍保持不变,进行按位与操作不能得到0

258

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。

进阶:不使用循环或者递归,时间复杂度 O(1) 

数学推导:1.写出某个整数的求和表示;

                  2.用添1的方法凑出各个位上的数字和;

                  3.观察发现10^i-1都是9的倍数,故该整数对9的取余结果即为所需返回值;

特殊情况:取余结果为0:1.该数为0,返回0;2.该数不为0,返回9;

class Solution(object):
    def addDigits(self, num):
        """
        :type num: int
        :rtype: int
        """
        return ((num-1)%9)+1 if num else 0

        #除开0后还需要输出的范围[1,9],而对9取余结果范围[0,8],故需要+1

400

给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] 中找出并返回第 n 位上的数字

分析:1-9:9 // 10-99:90x2 // 100-999:900x3 // 1000-9999:9000x4

数字1-910-99100-9991000-9999...——
长度990x2900x39000x4...900000000x9(>2**31-1)

     假设 n = 11:

     1.根据长度可以判断是在几位数的范围里;                                     9<11<9+90x2   两位数

     2.减去前一区间的长度总和再与当前位数相除就可以得到当前区间的相对位置;            (11-9)//2=1

     3.与前一区间的终点值相加得到其绝对数值;                                  9+1=10

     4.根据余数判断在数值的哪一位;                                                    (11-9)%2=0    ‘0’

        余数为0对应绝对数值的最后一位;余数为i则对应下一数值的第i位;

        假设数值为123456:

        取第一位:123456//100000=1

        取第二位:123456//10000=12%10=2

        ...取第n位:123456//10**(len-n)%10

class Solution(object):
    def largestPalindrome(self, n):
        """
        :type n: int
        :rtype: int
        """
        a, b = 1, 9
        while n > a*b:
            n = n - a*b
            a, b = a+1, b*10
        m = n//a + 10**(a-1) -1            #a为位数        
        return (m+1)//10**(a-n%a)%10 if n%a else m%10
  • 解题思路
50

实现 pow(x,n) ,即计算 x 的整数 n 次幂函数(即,x^n )

思路:n^1=n;n^2=n^1 * n;n^3=n^2 * n...     因此只需要一次循环实现连乘即可;

           处理指数为负:去掉负号进循环,返回时若是负数则返回1.0/out

优化点:若求n^2m = n^m * n^m,若求n^(2m+1) = n^m * n^m * n    

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

        return 1.0/self.poww(x,-n) if n < 0 else self.poww(x,n)   #处理符号
        
    def poww(self, x, n):                                         #处理正幂
        if n == 0: return 1.0
        else:
            m = self.poww(x, n//2)
            return m*m*x if n%2 else m*m
372

你的任务是计算 a^b 对 1337 取模,a 是一个正整数,b 是一个非常大的正整数且会以数组形式给出。

分析:处理以数组形式给出的b = [m, n] ,令 f(a,x) = a^x % k    

           f(a, mn) = [ a^(m*10)*a^n ] % k = [ f(a,m*10) * f(a,n) ] % k,而f(a,m*10) = (a^m)^10 % k = f(a^m, 10)  

           通过观察发现需要需要编写一个计算f(i,j)的函数poww(i,j),其中j-[0,10],

           当j=0时,结果为1;

           当j=1时,结果为a^k;

           当j-[2,10]时,结果为 f(j) = [ f(j-1) * f(1) ] % k   需要循环j-1次

class Solution(object):
    def superPow(self, a, b):
        """
        :type a: int
        :type b: List[int]
        :rtype: int
        """
        if a == 1: return 1                                  #直接结束
    
        if len(b)==1: return self.poww(a,b[-1])              #不需要拆分b
        else:
            out1 = self.superPow(a,b[-1:])                   #fn
            out2 = self.poww(self.superPow(a,b[:-1]),10)     #fm*10
            return (out1 * out2) % 1337

    def poww(self, a, b):     #计算a^b % k
        if b==0: return 1
        elif b==1:return a % 1337
        else: 
            out = f1 = a % 1337
            for _ in range(b-1): out = (out * f1) % 1337   #b-1次循环
            return out

#测试用时较长,内存占用较多

优化点:在求幂时用快速幂   50

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值