补充题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,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
分隔时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
解题思路:
动态规划+回溯;
单独用回溯算会出现“超出时间限制”错误,因此先用动态规划判断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