热题系列章节22

补充题8. 计算数组的小和

29. 两数相除

给定两个整数,被除数 dividend 和除数 divisor。将两数相除,要求不使用乘法、除法和 mod 运算符。

返回被除数 dividend 除以除数 divisor 得到的商。

整数除法的结果应当截去(truncate)其小数部分,例如:truncate(8.345) = 8 以及 truncate(-2.7335) = -2

示例 1:

输入: dividend = 10, divisor = 3
输出: 3
解释: 10/3 = truncate(3.33333..) = truncate(3) = 3
示例 2:

输入: dividend = 7, divisor = -3
输出: -2
解释: 7/-3 = truncate(-2.33333..) = -2
提示:

被除数和除数均为 32 位有符号整数。
除数不为 0。
假设我们的环境只能存储 32 位有符号整数,其数值范围是 [−2^31^, 2^31^ − 1]。本题中,如果除法结果溢出,则返回 2^31^ − 1
class Solution:
    def divide(self, dividend: int, divisor: int) -> int:
        # 越界的直接返回
        if dividend == -2147483648 and divisor == -1:
            return 2147483647
        # 将正负号提出来
        sign = 1
        if dividend < 0:
            dividend = - dividend
            sign = -sign
        if divisor < 0:
            divisor = - divisor
            sign = -sign
        
        left_over = dividend
        ans = 0
        while left_over >= divisor:  # 还可以继续除
            bit = 1
            v_divisor = divisor
            while (v_divisor<<1) <= left_over:
                v_divisor <<= 1
                bit <<= 1
            ans += bit
            left_over -= v_divisor
        return sign * ans

159. 至多包含两个不同字符的最长子串

给定一个字符串 s,找出至多包含两个不同字符的最长子串,并返回该子串的长度。
示例 1:
输入: s = “eceba”
输出: 3
解释: t 是 “ece”,长度为 3。

示例 2:
输入: s = “ccaabbb”
输出: 5
解释: t 是 “aabbb”,长度为 5。

解题思路
初步分析:
需要找到一个字符串 s 中最长的子串,该子串至多包含两个不同的字符。
可以使用滑动窗口的方法来解决这个问题。
滑动窗口方法:

使用两个指针来表示窗口的左右边界,维护一个哈希表来存储窗口内字符的频率。
当窗口内的不同字符数超过两个时,移动左指针缩小窗口,直到窗口内的不同字符数不超过两个。
记录并更新窗口的最大长度。
方法:滑动窗口
步骤:
初始化两个指针 left 和 right,表示窗口的左右边界。
初始化一个哈希表 char_count,用来存储窗口内字符的频率。
使用一个变量 max_length 来记录最长子串的长度。
使用一个循环来扩展窗口:
将右指针指向的字符添加到哈希表中,并更新其频率。
如果窗口内的不同字符数超过两个,移动左指针缩小窗口,直到窗口内的不同字符数不超过两个。
更新最长子串的长度。

def lengthOfLongestSubstringTwoDistinct(s):
    left, right = 0, 0
    char_count = {}
    max_length = 0

    while right < len(s):
        if s[right] in char_count:
            char_count[s[right]] += 1
        else:
            char_count[s[right]] = 1

        while len(char_count) > 2:
            char_count[s[left]] -= 1
            if char_count[s[left]] == 0:
                del char_count[s[left]]
            left += 1

        max_length = max(max_length, right - left + 1)
        right += 1

    return max_length

140. 单词拆分 II

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
分隔时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。

作者:阿凯被注册了
链接:https://www.jianshu.com/p/3dde44388439
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解题思路:

动态规划+回溯;
单独用回溯算会出现“超出时间限制”错误,因此先用动态规划判断dp[-1]==True;
如果可以拆分,再使用回溯计算结果,否则返回[]。

class Solution:
    def wordBreak(self, s: str, wordDict: List[str]) -> List[str]:
        size = len(s)
        dp = [False for i in range(size+1)]
        dp[0] = True
        word_set = set(wordDict)
        for i in range(1,size+1):
            for j in range(i):
                if dp[j] and s[j:i] in word_set:
                    dp[i] = True
                    break

        res = []
        if dp[-1]:
            def func(begin, track):
                if len(''.join(track))==size:
                    res.append(' '.join(track))
                    return 
                for i in range(begin, size):
                    if s[begin:i+1] in word_set:
                        func(i+1, track+[s[begin:i+1]])
            func(0, [])
        return res

486. 预测赢家

题目
给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手。开始时,两个玩家的初始分值都是 0 。每一回合,玩家从数组的任意一端取一个数字(即,nums[0] 或 nums[nums.length - 1]),取到的数字将会从数组中移除(数组长度减 1 )。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时,游戏结束。如果玩家 1 能成为赢家,返回 true 。如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true 。你可以假设每个玩家的玩法都会使他的分数最大化。

示例
输入:nums = [1,5,2]
输出:false
解释:一开始,玩家 1 可以从 1 和 2 中进行选择。如果他选择 2(或者 1 ),那么玩家 2 可以从 1(或者 2 )和 5 中进行选择。如果玩家 2 选择了 5 ,那么玩家 1 则只剩下 1(或者 2 )可选。 所以,玩家 1 的最终分数为 1 + 2 = 3,而玩家 2 为 5 。因此,玩家 1 永远不会成为赢家,返回 false 。

class Solution:
    def PredictTheWinner(self, nums: List[int]) -> bool:
        if len(nums)<=2 and nums[0]>=nums[-1]:
            return True
        @cache
        def dfs(start,end):
            #终止条件
            if start==end:
                return nums[start]
            #选择首数字下当前玩家的得分差的计算
            start_score=nums[start]-dfs(start+1,end)
            #选择尾数字下当前玩家的得分差的计算
            end_score=nums[end]-dfs(start,end-1)
            return max(start_score,end_score)
        return dfs(0,len(nums)-1)>=0

面试题 16.25. LRU缓存

480. 滑动窗口中位数

127. 单词接龙

给定两个单词(beginWord 和 endWord*)和一个字典,找到从 *beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]

输出: 5

解释: 一个最短转换序列是 “hit” -> “hot” -> “dot” -> “dog” -> “cog”,
返回它的长度 5。

输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]

输出: 0

解释: endWord “cog” 不在字典中,所以无法进行转换。

import string
from collections import deque


class Solution:
    def ladderLength(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: int
        """
        # 根据单词的每一位来改变,然后每一位变为a->z,判断是否是end是就return 层数+1,
        # steps里已经存在则证明走长了,就continue,不存在就添加到steps,并入队作为下一层的元素
        # 使用一个set记录单词的使用情况
        if beginWord == endWord or not beginWord or not wordList:
            return 0
        word_unused = set(wordList)
        dfs_que = deque([beginWord])
        steps = {beginWord: 1}

        while dfs_que:
            deepth = dfs_que.pop()
            step = steps[deepth]
            for i in range(len(beginWord)):
                for each_char in string.ascii_lowercase:
                    if deepth[i] == each_char:  # 如果字母相同就直接比较下个
                        continue
                    new_word = deepth[:i] + each_char + deepth[i + 1:]
                    if new_word == endWord:
                        return step + 1
                    if new_word in word_unused:
                        dfs_que.append(new_word)
                        word_unused.remove(new_word)
                        steps[new_word] = step + 1
        return 0  # 如果直到最后还没有返回,就返回0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值