• 剑指offer2 整数


    剑指 Offer II 001. 整数除法

    题目描述

    给定两个整数 a 和 b ,求它们的除法的商 a/b ,要求不得使用乘号 '*'、除号 '/' 以及求余符号 '%' 。

    • 整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2
    • 假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−231, 231−1]。本题中,如果除法结果溢出,则返回 231 − 1

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/xoh6Oh

    题解

     由于乘法不允许使用,不是2的偶次幂又不是很“快”,把右边算法想成对左边结果的分解,是不是就了然?

    1. 初始化返回值ret = 0
    2. 如果被除数大于除数,则除数扩大一倍
    3. 若被除数仍大于除数,这除数再次扩大一倍
    4. 直到除数下一次翻倍比被除数大时,将被除数减去除数,并将ret+=除数扩大的倍数,结束这一轮循环
    5. 重复2、3、4,直到被除数小于除数,终止循环并返回ret即可。
    def divide(self, a: int, b: int) -> int:
        flag = False if (a>0 and b > 0) or (a < 0 and b < 0) else True
        a,b = abs(a),abs(b)
    
        def caculateCore(x,y):
            # where y is divider
            n = 1
            while x > (y<<1):
                y<<=1
                n<<=1
            return n,y
    
        ret = 0
        while a>=b:
            # cnt 是放大倍数, val 是除数b被方法cnt倍的值
            cnt,val = caculateCore(a,b)
            ret += cnt
            a-=val
        ret = -ret if flag else ret
        return 2**31 -1 if ret >= 2**31 else ret

    剑指 Offer II 002. 二进制加法

    题目描述

    给定两个 01 字符串 a 和 b ,请计算它们的和,并以二进制字符串的形式输出。

    输入为 非空 字符串且只包含数字 1 和 0

     题源:剑指 Offer II 002. 二进制加法 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    牢记以下三点即可:

    1. 二进制的法则:逢二进一
    2. 进位的这个一,需要找个变量才存储它,才能在下一次的循环中获取
    3. 对于不等长的字符串,需要进行适当的优化与判断
    def addBinary(self, a: str, b: str) -> str:
        #return bin(int(a,2)+int(b,2))[2:]
        ret = ''
        carryBit = 0 #用于存进位
        i, j = len(a) - 1, len(b) - 1
        while i >= 0 or j >= 0 or carryBit:
            if i >= 0:
                carryBit += ord(a[i]) - ord('0')
            if j >= 0:
                carryBit += ord(b[j]) - ord('0')
            ret += str(carryBit % 2)
            carryBit //= 2
            i, j = i - 1, j - 1
        return ret[::-1]

     因为是从低位开始,放在ret的左边,所以需要ret[::-1]字符串转置一下

    ord()函数

    ord() 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。

    ord(c) # c是一个字符,返回值是对应十进制整数

    剑指 Offer II 003. 前 n 个数字二进制中 1 的个数

    题目描述

    给定一个非负整数 n ,请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数,并输出一个数组。

    题源:剑指 Offer II 003. 前 n 个数字二进制中 1 的个数 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    使用python内置函数计算汉明重量

    #调用库函数  对应c++中的 ((bitset<32>)n).count()
    bin(n).count('1')

    使用自定义函数(位运算)计算汉明重量O(M) O(1)

    def hammingWeight(n:int) -> int:
            # *巧用 n & (n-1)  把复杂度将为 O(M) O(1)  P.S. n & (n-1) 还可以用来判断n是不是2的幂
            res = 0
            while(n>0):
                res+=1
                n = n & (n-1)
            return res

    对于这题来说这个方法不太好,没有动态规划快,因为不是计算单个数的汉明重量而是计算 [n] 的汉明重量

    使用动态规划,汉明重量的特征

    • 如果 i 是偶数,那么他刚好是 i/2 左移,他的汉明重量和 i/2 是一样的
    • 如果 i 是奇数,那么他的汉明重量是 i-1 的汉明重量+1  
    def countBits(self, n: int) -> List[int]:
        #线性时间 O(n) 内用一趟扫描做到
        #算法的空间复杂度为 O(n)
        #不使用任何内置函数(如 C++ 中的 __builtin_popcount )来执行此操作 使用动态规划
        dp = []
        dp.append(0)
        for i in range(1,n+1):
            dp.append(dp[i-1]+1) if i%2==1 else dp.append(dp[int(i/2)])
        return dp

    剑指 Offer II 004. 只出现一次的数字

    题目描述

    给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

    题源:剑指 Offer II 004. 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)

    题解

    FSM+位运算

    参考K神题解:剑指 Offer II 004. 只出现一次的数字(有限状态自动机 + 位运算,清晰图解) - 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)

     

    上面是对每个数的单独一个bit考虑的,应用到所有比特也成立,因为各bit之间互不干扰 

    而恰好这样的状态设置,就完成了 mod 3 的操作,所以最后高位 b 一定是全0, a 就是那个只出现一次的数

    def singleNumber(self, nums: List[int]) -> int:
        # 对于最低位而言 这个位上有多少个1记为wt(b_0)  wt(b_0) mod 3 \in {0,1,2}    三种状态     00 01 10 分别对应表示0,1,2  
        # 直接应用在所有的位上逻辑同样成立
        a,b = 0,0
        for num in nums:
            a = ~b &(num^a)
            # 状态高位是在状态地位修改后的基础上修改的
            b = ~a &(num^b)
        # 因为状态的缘故  只关心状态啊=的地位就可以  就是说当所有的数加上之后,状态的高位肯定是0
        return a

    hash表

    • 创建一个哈希表
    • 循环数组,将每个元素挨个加入哈希表中
    • 遍历哈希表中的数据,查找哪个数字只出现了一次返回。
    def singleNumber(self, nums: List[int]) -> int:
        mydict = {}
        for num in nums:
            if num in mydict:
                mydict[num] += 1  
            else:
                mydict[num] = 1
        for key, value in mydict.items():
            if 1 == value:return key

    剑指 Offer II 005. 单词长度的最大乘积

    题目描述

    给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。

    • 单个字符串有重复没关系,主要是两个字符串不能出现任何一个相同的字符

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/aseY1I

    题解

    暴力搜+集合

    def maxProduct(self, words: List[str]) -> int:
        # 暴力搜O(n^2) 
        def twoStrProduct(str1,str2)->int:
            set1,set2 = set(str1),set(str2)
            set3 = set1.union(str2)
            #if len(set1)+len(set2)==len(str1)+len(str2) and len(set3)== len(set1)+len(set2):
            if len(set3)== len(set1)+len(set2):
                return len(str1)*len(str2)
            else:
                return 0
        ret = 0
        for i in range(len(words)-1):
            for j in range(i+1,len(words)):
                tmp = twoStrProduct(words[i],words[j])
                if tmp>ret:
                    ret = tmp
        return ret

    二进制特性

    • 利用二进制特性,将字符是否出现作为标志位,通过按位与判断是否有重复字符,比较操作的复杂度低
    • 第一个循环为统计26个字母是否出现在word中,并存在一个数中。例如,如果 'a' 在 word[0] 中,那么 res[0] 的 LSB 便为1。
        def maxProduct(self, words) -> int:
            '''二进制思路
            26个字母对应26位长度的二进制数字,1表示含对应字母
            位运算的一些trick可以快速计算是否重合
            '''
            res = [0]*len(words)
            max_res = 0
    
            for i in range(len(words)):
                for c in words[i]:
                    res[i] |= 1 << ord(c) - ord('a')
    
            for i in range(len(res)):
                for j in range(i, len(res)):
                    if res[i] & res[j] == 0:
                        # 按位与判断是否有重合,若结果为0,说明没有重合
                        max_res = max(max_res, len(words[i])*len(words[j]))
    
            return max_res
    
    作者:frovvn
    链接:https://leetcode-cn.com/problems/aseY1I/solution/li-yong-er-jin-zhi-te-xing-huo-counterji-zhpg/
    

    剑指 Offer II 006. 排序数组中两个数字之和

    题目描述

    给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

    函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 0 开始计数 ,所以答案数组应当满足 0 <= answer[0] < answer[1] < numbers.length 。

    假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/kLl5u1

    题解

    对撞(双)指针

    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        #假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。
        #升序排列  
        #双指针
        i,j = 0,len(numbers)-1
        while i<j:
            sum = numbers[i]+numbers[j]
            if sum<target:
                i+=1
            elif sum > target:
                j-=1
            else:
                return [i,j]

    hash表

    • 遍历 enumerate(numbers) ,即遍历 numbers
    • 如果 num不在字典 d 中,字典新增键值对:键是该元素的目标匹配元素,值是该元素的下标
    • 如果 遇到新的元素num 在字典中,意味着这个元素和之前某个元素匹配,返回 [之前元素的下标,当前元素的下标]
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        #假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。
        #升序排列  
        #hash表
        d = {}
        for i, num in enumerate(numbers):
            if num not in d:
                d[target - num] = i
            else:
                return [d[num], i]

    enumerate(list)用法
    tetslist = [0,0,3,4]
    valuelist = list(range(len(tetslist)))
    mydict = enumerate(tetslist)
    for i in mydict:
        print(i)
    
    output:
    (0, 0)
    (1, 0)
    (2, 3)
    (3, 4)

  • 相关阅读:
    jQuery链式编程时修复断开的链
    只是一个用EF写的一个简单的分页方法而已
    asp.net Core 获取应用程序所在目录的2种方式
    FineUI使用记录
    C#判断一个string是否为数字
    MVC中利用ViewBag传递Json数据时的前端处理方法
    基于Ajax的文件上传使用FileInput插件(使用谷歌翻译作者的原文,大致意思是对的,自己把握)
    ansible中tag的用法
    rabbitMQ中vhost虚拟主机的理解
    一些比较好的链接
  • 原文地址:https://www.cnblogs.com/PiaYie/p/15712889.html
Copyright © 2020-2023  润新知