每日一题
2609. 最长平衡子字符串 给你一个仅由 0 和 1 组成的二进制字符串 s 。 如果子字符串中 所有的 0 都在 1 之前 且其中 0 的数量等于 1 的数量, 则认为 s 的 这个子字符串是平衡子字符串。请注意,空子字符串也视作平衡子字符串。 返回 s 中最长的平衡子字符串长度。 子字符串是字符串中的一个连续字符序列。
题解:暴力枚举法,直接数01 0011 000111 00001111 等数量
本质就是数出0和1 的数量,判断是不是连着的,如果不是计数置零,连着的数出来,则平衡串为小的数量的2倍,(多的肯定够配出平衡串,但是少的不行,故需要以少的为基准)
class Solution:
def findTheLongestBalancedSubstring(self, s) :
res = 0
zero, one = 0, 0
i = 0
n = len(s)
if n == 0:
return 0
while i <= n - 1:
while i <= n - 1 and s[i] == '0':
i += 1
zero += 1
while i <= n - 1 and s[i] == '1':
i += 1
one += 1
if one >= zero:
res = max(res, 2 * zero)
else:
res = max(res, 2 * one)
one = 0
zero = 0
return res
15.三数之和
18. 四数之和 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。 请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复): 0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] + nums[d] == target 你可以按 任意顺序 返回答案 。 示例 1: 输入:nums = [1,0,-1,0,-2,2], target = 0 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]] 示例 2: 输入:nums = [2,2,2,2,2], target = 8 输出:[[2,2,2,2]]
15 与 18可以说是一模一样,这里以18为例(15 题解代码也赋上)
题解:由于是遍历类型,如果暴力枚举,需要遍历四次,并且会有很多的重复操作,故可以采用哈希表双指针优化,可以大大减少不必要的计算
就不写具体题解了,我把代码每行注释都给表明了,基本完全小白也能看懂了,现对遍历类型百试不爽的双指针简单总结一下
双指针总结:
1.对待操作序列排序(可以是数组元素,也可为字典索引(key,value均可反正能查到就行))
2.指针赋值 (左右指针,分别置于待处理序列俩端) 注意:是待处理序列,需要辨析,如果对初始序列切片了,辨清看是在哪里使用双指针,18题中就有例子
3.大条件 while left<right: (我一般都打 l ,r 大家注意辨析,就是个人习惯问题)
4.移动条件,这里就与事先排序有关了,知道大小顺序,可以根据自己要求,看是怎么移动指针
# 15
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
nums.sort() # 首先对数组进行排序
result = [] # 初始化结果列表
for i in range(len(nums) - 2): # 遍历数组,注意我们只需要遍历到倒数第三个元素,要求为三元组,后面俩个没有必要了,构不成三元组了
if i > 0 and nums[i] == nums[i - 1]: # 如果当前元素和前一个元素相同,我们就跳过,因为我们不想有重复的解
continue
l, r = i + 1, len(nums) - 1 # 初始化左右指针,它们分别指向当前元素的下一个元素和数组的最后一个元素
while l < r: # 当左指针小于右指针时,我们继续寻找解
s = nums[i] + nums[l] + nums[r] # 计算当前三个元素的和
if s < 0: # 如果和小于0,我们就将左指针向右移动,以增大和
l += 1
elif s > 0: # 如果和大于0,我们就将右指针向左移动,以减小和
r -= 1
else: # 如果和等于0,我们就找到了一个解
result.append([nums[i], nums[l], nums[r]]) # 将解添加到结果列表中
while l < r and nums[l] == nums[l + 1]: # 如果左指针的下一个元素和当前元素相同,我们就将左指针向右移动,以避免重复的解
l += 1
while l < r and nums[r] == nums[r - 1]: # 如果右指针的前一个元素和当前元素相同,我们就将右指针向左移动,以避免重复的解
r -= 1
l += 1 # 找到一个解后,我们将左右指针都移动,以寻找下一个解
r -= 1
return result
# 18
# 优化
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = set()
nums.sort() # 凡是考虑用双指针,先将其索引或者值排序更好,后续更方便判断指针以东方走向
for i in range(len(nums) - 3): # 四元组 到达长度-3时就可,后面就剩三个不够构成
for j in range(i+1,len(nums) - 2): # 确定第二个元素,相当于,四元组已知了第一个元素,只要找三那个元素就可,长度-2原因同上
new = nums[i] + nums[j] # 此时确定下的俩数和,也方便后续代码可读性
# 定义双指针,在定了俩个元素情况下
l = j + 1 # 此时相当于将原数组划分,从j+1到完
r = len(nums) - 1
while r > l:
if new + nums[l] + nums[r] == target:
if (nums[i], nums[j], nums[l], nums[r]) not in result: # 注意链表不可哈希,即不可集合操作,需要改为元组
result.add((nums[i], nums[j], nums[l], nums[r]))
if new + nums[l] + nums[r] < target:
l += 1
# elif new + nums[l] + nums[r] > target:
# r -= 1
# else :
# break
else :
r-=1
return list(result)
16. 最接近的三数之和 给你一个长度为 n 的整数数组 nums 和 一个目标值 target。 请你从 nums 中选出三个整数,使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 示例 1: 输入:nums = [-1,2,1,-4], target = 1 输出:2 解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。 示例 2: 输入:nums = [0,0,0], target = 1 输出:0
题解:与三数四数求和没啥区别,只是将一个确定的 target 变为一个范围加一个判断条件就可
双指针,在0和倒数第三个元素(后面俩个元素不够三元组了,注意,数组下标从0开始)
记录每次的三元组值计算与target的差值(接近程度),与一个无穷大与target差值(此时肯定为最大的,好初始更新)进行比较,然后将小的保存,不断更新最小值,即答案最接近的数
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
nums.sort()
closest_sum = float('inf') # 初始化最接近的和为无穷大
for i in range(len(nums) - 2):
l, r = i + 1, len(nums) - 1
while l < r:
s = nums[i] + nums[l] + nums[r]
if abs(s - target) < abs(closest_sum - target): # 如果当前和更接近目标值,就更新最接近的和
closest_sum = s
if s < target:
l += 1
elif s > target:
r -= 1
else: # 如果和等于目标值,就直接返回
return target
return closest_sum # 返回最接近的和
17. 电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
题解:建立数字与字母的字典,然后一层一层遍历,这里完全可直接返会temp 只是为了满足题目要求返回【】,故用temp 转化一下,先遍历数组,取出单个数子,将其对应的字母遍历保存,然后第二个数子,取出字母,在遍历第一个数字字母的循环下,全都组合一遍,存入链表(这里第一个数子与第二个数字谁先遍历无所谓,只要最后添加的时候调好位置就行)
class Solution(object):
def letterCombinations(self, digits):
"""
:type digits: str
:rtype: List[str]
"""
digits_dict={
1:'1',2:'abc',3:'def',
4:"ghi",5:'jkl',6:'mno',
7:'pqrs',8:'tuv',9:'wxyz',
0:'0'
}
if not digits:
return []
result=[""]
for x in digits:
temp=[]
for ch in digits_dict[int(x)]:
for str in result:
temp.append(str + ch)
result=temp
return result