力扣练习4.26

2. 两数相加

解题思路

竖式相加。
要注意的点:
1.链表不等长,因此要在某个链表节点不够的情况下补0。
2.有可能连续进位,使得最后的数字超出最长的链表节点数,所以要判断进位变量的最后状态,若还有值,要新建一个节点。

步骤

1.初始化哑结点,指针节点指向哑结点
2.初始化进位和当前位的值
3.建立循环,要求遍历完全部链表
4.循环体内定义某个链表长度不足时补0
5.计算当前位和进位的值
6.将当前位新建为节点,添加到结果链表后。移动指针节点
7.移动链表节点
8.检查是否进位非0,还有值就新建节点添加进尾部
9.返回头节点。哑结点的下一个节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:# 哑结点dummy = ListNode(0)cur = dummycarry = 0 # 进位初始化为0_sum = 0 # 当前位初始化为0# 考虑不等长情况,补0while l1 or l2:if not l1:l1 = ListNode(0)if not l2:l2 = ListNode(0)# 求和_sum = l1.val + l2.val + carry# 个位now = _sum % 10# 检查十位carry = _sum // 10# 将个位写入新节点,加入结果链表cur.next = ListNode(now)cur = cur.next # 不要忘记移动指针# 移动l1 = l1.nextl2 = l2.next# 如果十位数连续多进位,导致最后只有进位的,就新建一个节点是它,续在末尾# 也就是该变量最后非0if carry:cur.next = ListNode(carry)return dummy.next

155. 最小栈

既要获得栈顶元素,又要立即获得栈的最小元素。
设定一个主栈还有一个辅助栈,辅助栈只存储当前最小元素。

实现思路:

  1. 使用两个栈

    • 主栈:用于存储所有元素,实现正常的栈操作。
    • 辅助栈:用于存储每个阶段的最小值。
  2. 操作解释

    • push(x):将元素 x 压入主栈。同时,将当前最小值压入辅助栈。这个当前最小值是 x 和辅助栈顶元素的较小者。
    • pop():从主栈中弹出顶部元素。同时,从辅助栈中也弹出顶部元素(保持两个栈的同步)。
    • top():返回主栈的顶部元素,不从栈中移除。
    • getMin():返回辅助栈的顶部元素,即当前栈中的最小值。
class MinStack:def __init__(self):# 主栈self.stack = []# 最小栈self.min_stack = []def push(self, val: int) -> None:# 同时入栈# 主栈直接入self.stack.append(val)# 最小栈检测是否是有值且最小的,保证每次都是最小的在最小栈最后if not self.min_stack or val <= self.min_stack[-1]:self.min_stack.append(val)def pop(self) -> None:# 栈顶出栈,删除最后一个元素item = self.stack.pop()# 如果弹出的是最小值,那最小栈也要弹出对应元素if item == self.min_stack[-1]:self.min_stack.pop()def top(self) -> int:# 获取栈顶部的元素item = self.stack[-1]return itemdef getMin(self) -> int:# 获取栈中的最小元素item = self.min_stack[-1]return item# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

20. 有效的括号

解题思路:

正确的括号组合应该是开放括号在前,同时开放括号所对应的闭合括号的位置是和本身的位置对称的。
也就是如果开放括号后再也没有开放括号了,那么下一个就必须是所对应的闭合括号,这样才能对应。

根据以上分析,可以使用栈结构处理,栈是先进后出的。
假设我们有’{([])}‘,那么遍历字符串,对开放括号入栈,得到[’{', ‘(’, ‘[’ ],如果说下一个字符不是[所对应的],那么就说明位置错乱,直接返回false;如果遍历完后还是空栈,说明也没有多余的括号,是正确的,返回True。
在上述操作中,首先需要一个字典存储开放和闭合括号的映射关系;其次,每次都可能尝试弹出栈顶元素,要是第一次就是个闭合括号,那程序不就报错了(未入栈,栈为空),因此还要添加一个默认值,防止空栈访问。

步骤

1.初始化一个字典和栈,字典包含开放:闭合,加上占位符号。栈加上占位字符。
2.遍历字符串,遇到开放括号,入栈。
3.否则,也就是遇见闭合括号,访问栈顶元素,检查是否是其对应的开放括号,如果不是,就说明位置错误,直接返回false。
4.遍历完字符串,检查栈中元素只有最开始的占位字符,如果是,说明已经全部消消乐掉了,返回True;否则,说明还有多余的括号,返回false。

class Solution:def isValid(self, s: str) -> bool:# 括号开放闭合字典bracket_map =  {'(':')', '{':'}', '[':']', '#':'#'}# 栈stack = ["#"]# 遍历字符串for i in s:# 如果是开放符号,入栈if i in bracket_map:stack.append(i)# 如果当前字符不是刚入栈的开放括号对应的闭合括号,说明位置错乱elif bracket_map[stack.pop()] != i:return False# 遍历完成后,所有括号都应该消除,只剩一个占位字符return len(stack) == 1

227. 基本计算器 II

解题思路

利用栈,维护一个全都是待加元素的栈。
在解析出数字的时候不能直接入栈,而是要看前一个运算符决定。
每个数字加入栈的最终形式,是由前一个运算符决定的,比如3,其前一个运算符就是+,直接入栈;而*3,其前一个运算符是*,那就要和栈顶元素相乘再重新入栈。

步骤

1.初始化栈,符号变量为+,数字为0
2.需要解析出每一个数字,因此遍历字符串,检查是否为数字,是数字则将字符转为数字,并要考虑可能有十位百位数,因此每次遍历都要检查当前数字*10.
3.如果字符为运算符,说明当前数字已经确定了,根据当前数字的前面的运算符计算入栈的结果:加减简单,乘的话是要先弹出栈顶元素,当前数字和栈顶元素相乘,乘积入栈;除法,因为 Python 的 // 运算符在被除数为负数时会向下取整到更小的整数,而通常的数学操作是向零取整,所以要考虑栈顶元素的正负,是负数时需要用最原始的解法。
4.当前字符为字符串,在将确定的数字入栈后,更新运算符变量和数字变量。
5.返回栈内所有元素的和。

class Solution:def calculate(self, s: str) -> int:# 初始化栈,符号变量,当前数字stack = []sign = '+' # 第一个为正num = 0 s += '+' # 给字符串末尾加一个符号,防止最后一个数字加不上(标识最后一个数字的结束)# 遍历字符串for i in s:# 如果是数字,就构造数字if i.isdigit():# 乘10是将已解析的数字往左移动一位,使得123这样的字符串能被正确识别,而不是变成6# 因为我们每次读到一个新的数字字符时,都需要将之前的数字值“扩大10倍”再加上新的数字。num = 10 * num + int(i)# 如果是运算符elif i in '+-*/':# 如果是前面是加,那就直接把当前数字入栈if sign == '+':stack.append(num)# 如果前面是减,那就将相反数入栈elif sign == '-':stack.append(-num)# 如果前面是乘,就弹出栈顶的元素相乘elif sign == '*':stack.append(stack.pop() * num)# 如果前面是除,那就要保留整数半部分,、# 但是因为Python的//在处理负数时向下取整,但是正常是向零取整,所以要先正常除,然后转整数else:temp = stack.pop()if temp < 0:stack.append(int(temp/num))else:stack.append(temp//num)# 遍历到运算符,更新运算符变量sign = i# 当前无数字,重置数字变量num = 0return sum(stack)

232. 用栈实现队列

解题思路

使用两个栈,逆向存储。
入队操作就直接入主栈;
移除队首元素,就先将主栈元素依次弹出,入辅助栈,这样辅助栈的栈顶元素就是队首元素,弹出即可,记得返回;
获取队首元素,同上,但是不能弹出,不是移除;
检查是否为空,检查两个栈是否都为空。

class MyQueue:def __init__(self):# 主栈self.in_stack = []# 辅助栈self.out_stack = []def push(self, x: int) -> None:# 入栈self.in_stack.append(x)def pop(self) -> int:# 出栈,检查辅助栈是否有值,有值就弹出栈顶元素# 没有,就将主栈元素依次弹出到辅助栈if not self.out_stack:while self.in_stack:self.out_stack.append(self.in_stack.pop())return self.out_stack.pop()# 获取队首元素def peek(self) -> int:if not self.out_stack:while self.in_stack:self.out_stack.append(self.in_stack.pop())# 不删除元素return self.out_stack[-1]# 检查是否队列为空def empty(self) -> bool:return not self.in_stack and not self.out_stack# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()

394. 字符串解码

解题思路

使用栈。类似于计算器二,对于数字都要考虑是多位的情况。
设置当前字符串和当前数字,用于遍历时入栈。
当遍历到数字时要解析数字。如果是左括号,就可以确定解析的数字了,还有当前的字符编码开始了。将其入栈。
如果是字符,说明还在增加字符编码,累加到当前字符串。
如果是右括号,说明字符编码已确定,需要将数字和字符编码结合,加到前一个字符串后面。
最后返回字符串。

步骤

您的代码实现基本上是正确的,对于394题“字符串解码”的解决方案很好地处理了基本情况,包括数字的读取、字符串的累积和括号内字符串的重复。我会先提供一个简单的算法步骤说明,然后对代码进行逐行检查和说明。

算法步骤

  1. 初始化数据结构

    • 使用一个栈来存储先前的状态。
    • 使用两个变量 cur_numcur_str 来分别存储当前解析的重复次数和当前解析的字符串。
  2. 遍历输入字符串

    • 如果当前字符是数字,将其转换为整数并更新 cur_num
    • 如果当前字符是 [,表示一个新的重复序列的开始,将 cur_numcur_str 压入栈中,然后重置这两个变量。
    • 如果当前字符是 ],表示一个重复序列的结束,从栈中弹出之前的字符串和重复次数,根据这个重复次数将当前字符串重复拼接,然后与之前的字符串连接。
    • 如果当前字符是字母,将其添加到 cur_str 中。
  3. 返回最终解析的字符串

    • 遍历完成后,cur_str 包含了整个解析后的字符串。
class Solution:def decodeString(self, s: str) -> str:stack = []  # 用于保存之前的字符串状态和重复次数cur_num = 0  # 当前解析的数字,即重复次数cur_str = ''  # 当前解析的字符串for i in s:if i.isdigit():cur_num = 10 * cur_num + int(i)  # 构建整数,处理多位数的情况elif i == '[':stack.append(cur_num)  # 将当前重复次数压入栈stack.append(cur_str)  # 将当前字符串压入栈cur_num = 0  # 重置重复次数cur_str = ''  # 重置当前字符串elif i == ']':pre_str = stack.pop()  # 弹出上一个字符串状态pre_k = stack.pop()  # 弹出上一个重复次数cur_str = pre_str + (cur_str * pre_k)  # 根据重复次数构造字符串,并与之前的字符串连接else:cur_str += i  # 累加非括号内的字符到当前字符串return cur_str  # 返回解析后的字符串

32. 最长有效括号

解题思路

栈先进后出,适合括号是否有效问题。
遍历字符串,只入栈左括号时的索引;否则,弹出栈顶元素,计算当前索引和当前栈顶元素的差值。这样不断更新最长长度。消消乐

步骤

1.初始化:创建一个栈,用于保存括号的索引,并先压入 -1 作为基准点,方便计算长度。
遍历字符串:
2.如果遇到 (,将其索引压入栈中。
3.如果遇到 ):弹出栈顶元素。然后

  • 如果栈为空,将当前索引压入栈(这成为新的基准点)。
  • 如果栈不为空,计算当前有效括号的长度,即 当前索引 - 栈顶元素索引,更新最大长度。

4.返回最大长度。

class Solution:def longestValidParentheses(self, s: str) -> int:# 初始化栈,使用-1作为初始基准点,这样对于'()'也能正确计算出是2stack = [-1]max_len = 0 # 最大长度# 遍历字符串for i in range(len(s)):# 如果是左括号索引,就入栈if s[i] == '(':stack.append(i)# 如果是右括号,弹出栈顶的左括号索引else:stack.pop()# 如果栈为空,说明一个连续的有效子串已经被消耗完。将当前索引入栈作为新的基准if not stack:stack.append(i)# 更新最长长度# 此时消掉了栈顶元素索引和当前索引,所以最长长度为目前栈顶元素和当前索引之差max_len = max(max_len, i - stack[-1])return max_len

42. 接雨水

著名hard题,我是不做的😇

双指针法

问题42 “接雨水” 要求计算在一个由整数表示的条形图中,可以存多少单位的雨水。这是一个经典的问题,可以通过几种方法解决,包括使用栈、动态规划或双指针。

解题思路:双指针法

双指针法是解决这个问题的一种高效方式。基本思想是用两个指针从两头开始遍历数组,使用两个变量来记录左右两边的最大高度,从而计算每个位置上能接的雨水量。

步骤:
  1. 初始化

    • left 指针开始于数组的第一个位置。
    • right 指针开始于数组的最后一个位置。
    • left_maxright_max 分别记录遍历过程中遇到的左侧和右侧的最大高度。
    • water 初始化为0,用于累计总的接水量。
  2. 遍历数组

    • 使用 while 循环,当 left 小于 right 时继续遍历。
    • 比较 height[left]height[right]
      • 如果 height[left] 小于或等于 height[right],则处理左边的部分:
        • 更新 left_max
        • 如果 left_max 大于 height[left],累加差值到 water
        • 移动 left 指针向右。
      • 否则,处理右边的部分:
        • 更新 right_max
        • 如果 right_max 大于 height[right],累加差值到 water
        • 移动 right 指针向左。
  3. 返回结果

    • 循环结束后,water 中存储的就是可以接的雨水总量。
class Solution:def trap(self, height):# 如果没有柱子或者小于3个,那就无法存贮水if not height or len(height) < 3:return 0# 初始化左右指针left, right = 0, len(height) - 1# 初始化左右边遇到的最大值left_max, right_max = height[left], height[right]# 接水量water_trapped = 0# 当双指针不相遇时while left < right:# 当左边柱子比右边低if height[left] < height[right]:# 如果当前柱子比最高还高,更新左边的最高值if height[left] >= left_max:left_max = height[left]# 否则,认定为有积水,积水量等于最高值减去当前的柱子高度else:water_trapped += left_max - height[left]# 左边柱子低,往右移动left += 1# 当右边柱子比左边低else:# 如果当前柱子比最高还高,更新右边的最高值if height[right] >= right_max:right_max = height[right]# 否则,认定为有积水,积水量等于最高值减去当前的柱子高度else:water_trapped += right_max - height[right]# 右边柱子低,往左移动right -= 1return water_trapped
解释
  • 此方法的核心在于,通过维护两个最大高度(从左和从右)来确定当前位置能接的雨水。
  • height[left] 较小时,水的高度由左侧最高的条形块决定(因为右边至少有一个条形块更高),反之亦然。

这种双指针方法的时间复杂度为 (O(n)),空间复杂度为 (O(1)),因为它只需要常数空间来存储指针和高度变量。

使用栈来解决接雨水问题也是一个非常有效的方法。通过栈,我们可以保持一个减少的高度序列,这样每次我们碰到一个比栈顶更高的条形块时,就可以计算接到的雨水量。

解题思路:使用栈

步骤:
  1. 初始化

    • 创建一个空栈,用来存储条形块的索引。
    • 初始化 water 为 0,用于累计总的接水量。
  2. 遍历数组

    • 对于每个条形块,执行以下操作:
      • 当栈不为空且当前条形块的高度大于栈顶条形块的高度时,执行循环:
        • 弹出栈顶元素(索引),记为 top
        • 如果栈变为空,跳出循环(没有左边界)。
        • 查找新的栈顶元素,这将是 top 的左边界。
        • 计算当前水的宽度和高度:
          • 宽度为 current index - stack top index - 1
          • 高度为 min(height[current index], height[stack top index]) - height[top]
        • 计算接的水量并加到 water 上。
      • 将当前条形块的索引压入栈中。
  3. 返回结果

    • 遍历结束后,water 中存储的就是可以接的雨水总量。
class Solution:def trap(self, height):# 初始化一个空栈来保存条形块的索引stack = []# 初始化水量计数为0water = 0# 从第一个条形块开始遍历current = 0# 遍历所有的条形块while current < len(height):# 当栈不为空且当前条形块高度大于栈顶条形块高度时while stack and height[current] > height[stack[-1]]:# 弹出栈顶元素,这是凹形区域的底部top = stack.pop()# 如果栈为空,说明没有左边界,跳出循环if not stack:break# 计算当前凹形区域的宽度distance = current - stack[-1] - 1# 找到边界高度的最小值,并减去凹底的高度,得到水的高度bounded_height = min(height[current], height[stack[-1]]) - height[top]# 根据宽度和水的高度计算当前凹形区域的水量,并加到总水量中water += distance * bounded_height# 将当前条形块索引压入栈中,表示可能的新的凹形区域的右边界stack.append(current)# 移动到下一个条形块current += 1# 返回计算的总水量return water
解释
  • 此方法利用栈来追踪可能存水的位置。
  • 当遇到一个条形块高于栈顶条形块时,可以确定一个凹形区域(即接水的区域)。通过计算这个凹形区域的宽度和界限高度来确定其可以接的水量。
  • 重复这一过程直到遍历完整个数组。

使用栈的方法在处理复杂的嵌套结构和计算界限时非常直观和有效。此方法的时间复杂度为 (O(n)),因为每个条形块最多被压入和弹出栈一次。空间复杂度也为 (O(n)),最坏情况下栈可能需要存储所有条形块的索引。

225. 用队列实现栈

解题思路

设置主队列和辅助队列,每次入栈先进入辅助队列,然后将主队列的全部元素依次入辅助队列,这样辅助队列的首个元素就是栈顶元素。再交叉引用,让主队列得到新的栈顺序

两个队列实现栈的操作步骤:

初始化
  • mainQueue 用于存储栈内元素。
  • tempQueue 用于 push 操作中的元素顺序调整。
push(x) 操作
  1. 将新元素 x 入队到 tempQueue
  2. mainQueue 中的所有元素依次出队,并入队到 tempQueue
  3. 交换 mainQueuetempQueue 的引用,使 mainQueue 包含新的元素序列,tempQueue 为空。
pop() 操作
  • 直接从 mainQueue 出队一个元素(即栈顶元素)。
top() 操作
  • 返回 mainQueue 的队首元素(即栈顶元素)。
empty() 操作
  • 检查 mainQueue 是否为空。

Python 示例代码

from collections import dequeclass MyStack:def __init__(self):"""Initialize your data structure here."""self.mainQueue = deque()self.tempQueue = deque()def push(self, x: int):"""Push element x onto stack."""# 先将元素入队到 tempQueueself.tempQueue.append(x)# 将 mainQueue 中的所有元素移到 tempQueuewhile self.mainQueue:self.tempQueue.append(self.mainQueue.popleft())# 交换两个队列的引用,使 mainQueue 包含新的栈顺序self.mainQueue, self.tempQueue = self.tempQueue, self.mainQueuedef pop(self):"""Removes the element on top of the stack and returns that element."""return self.mainQueue.popleft()def top(self):"""Get the top element."""return self.mainQueue[0]def empty(self):"""Returns whether the stack is empty."""return not self.mainQueue# Usage
stack = MyStack()
stack.push(1)
stack.push(2)
print(stack.top())    # returns 2
print(stack.pop())    # returns 2
print(stack.empty())  # returns False

这种实现方法虽然在每次 push 操作时需要移动所有元素(时间复杂度 O(n)),但它确保了 poptopempty 操作都是 O(1) 的时间复杂度。这样,栈的后进先出行为通过队列被成功模拟出来了。

1. 两数之和

解题思路1

双重循环,第二层循环应该从i+1开始,避免i==j的情况

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:# 双重循环# 遍历所有for i in range(len(nums)):# 遍历从i+1到最后,避免i==j的情况for j in range(i+1, len(nums)):# 发现有符号条件的,返回索引if nums[i] + nums[j] == target:return [i,j]

解题思路2

哈希表。
遍历数组,计算每个数字和目标值的差值,如果插值存在,则返回。否则加入当前数字。
key: 数字,vlaue:索引

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:# 哈希表_dict = {}# 遍历,记录索引for i,num in enumerate(nums):# 计算当前数和目标值的差值temp = target - num# 如果和差值相同的数字在哈希表内,就说明找到了两个数,返回对应下标if temp in _dict:return [_dict[temp], i]# 否则,将当前数作为键,当前索引作为值加入哈希表_dict[num] = i

15. 三数之和

解题思路

排序加双指针。
先对数组排序,遍历数组,每次遍历都要跳过重复数字,然后初始化左右指针,在左右区间内尝试找到三个数字满足条件。
如果小于0,移动左指针;大于,移动右指针;等于,就找到了符号要求的三个数字,加入到结果列表。
找到一组结果,不代表这个区间内没有了,因此还要跳过左右指针的重复元素,避免找到相同的结果。最后移动左右指针到新的元素。

  1. 排序:首先对数组进行排序。排序有助于后续操作,特别是在跳过重复元素时。
  2. 使用固定指针和双指针
    • 固定一个数 nums[i],然后使用两个指针,一个指向 i+1left),另一个指向数组的最后一个元素(right)。
    • 移动 leftright 指针来找到三元组,使得 nums[i] + nums[left] + nums[right] == 0
  3. 处理重复元素
    • 在遍历和移动指针时,要注意跳过重复的元素以避免重复的三元组。
  4. 时间复杂度:排序操作为 (O(n \log n)),双指针扫描为 (O(n^2)),整体复杂度为 (O(n^2))。
class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:# 排序nums.sort()res = [] # 结果列表# 遍历数组for i in range(len(nums)-2):# 经过排序后,如果当前数字大于0,那剩下加上肯定也大于0if nums[i] > 0:break# 跳过重复元素if nums[i] == nums[i-1] and i > 0:continue# 设置左右指针,从不重复的开始left, right = i+1, len(nums)-1# 开始循环while left < right:total = nums[i] + nums[left] + nums[right]if total < 0: # 如果总和小于0,说明负数太大left += 1elif total > 0: # 正数太大right -= 1else: # 找到了目标,加入到结果列表res.append([nums[i], nums[left], nums[right]])# 然后跳过重复元素while left < right and nums[left] == nums[left+1]:left += 1while left < right and nums[right] == nums[right-1]:right -= 1# 移动指针left += 1right -= 1return res

说明

  • 排序:排序是为了方便处理重复元素和简化三数之和的查找。
  • 双指针移动:通过比较三数之和与零的关系来决定指针的移动方向。
  • 去重:在找到一个有效的三元组后,需要跳过所有重复的元素,以确保结果的唯一性。

41. 缺失的第一个正数

解题思路

原地哈希。因为要求不使用额外空间,所以可以将数字和其索引作为哈希表的键和值。
尝试将所有的数字都放在对应的索引上,如果说有不对应的,那就是缺失。
第一次遍历,将乱序数组进行原地哈希;第二次遍历,找到缺失值。

步骤

1.第一次遍历:检查每个数字是否在1-n(n为数组长度)之间,索引对应的位置是否是正确的数字。如果不是,则要进行交换,使其回到对应的索引为止。

nums[nums[i]-1] != nums[i]
对于数字nums[i],应该放在数组的nums[i]-1位置上,如果该位置上的数字不等于它,说明位置不对。

2.第二次遍历:针对原地哈希后的数组,检测是否有不满足原地哈希的索引,返回其+1,也就是缺失的第一个值
3.如果以上没有返回,那就说明是满足原地哈希的。返回数组后面的第一个整数。

class Solution:def firstMissingPositive(self, nums: List[int]) -> int:# 原地哈希,数字1:索引0n = len(nums)# 遍历数组for i in range(n):# 当数字在1到n之间,并且没有在正确的位置上,数字和索引之间差1while 1 <= nums[i] <= n and nums[nums[i]-1] != nums[i]:# 就要将 nums[i] 交换到它应该去的位置,也就是nums[nums[i]-1]nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]# 原地哈希结束后,如果有不满足原地哈希条件的,就返回其值(索引+1)for i in range(n):if nums[i]-1 != i:return i + 1# 如果数组所有元素都没有不符合要求的,那结果就是后面的正整数缺失return n + 1

128. 最长连续序列

解题思路

利用哈希集合。遍历哈希集合,每次尝试找到一个新的子序列起点(当前值-1不在哈希集合),然后扩展它(当前值+1在集合),找到完整的子序列后,更新结果。

步骤

1.初始化哈希集合和结果变量。
2.遍历哈希集合,检查当前元素是否为一个新的子序列起点
3.如果是,就将子序列长度初始化为1,子序列起点设为当前元素;然后以子序列起点,找是否有下一个元素,有的话就将子序列起点更新为它,并且子序列长度加1.最后找不到下一个元素了,说明子序列到此为止,更新结果。

class Solution:def longestConsecutive(self, nums: List[int]) -> int:# 集合nums = set(nums)# 最大长度res = 0for i in nums:# 只有其前一个数字不在集合中,才算一个新的连续子序列的开始if (i-1) not in nums:cur_num = i # 当前数字作为子序列的起点cur_res = 1 # 当前子序列的长度初始化为1# 尝试从子序列起点构建连续序列,检查后一个数是否存在于集合while (cur_num+1) in nums:cur_num += 1 # 子序列起点更新cur_res += 1 # 子序列长度更新# 在得到一个完整的子序列后,更新最长长度res = max(res, cur_res)# 返回结果return res

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/4315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构-图搜索算法详解

图搜索算法是数据结构和算法学科中的一个重要领域&#xff0c;它们用于在图中搜索顶点&#xff08;节点&#xff09;和边&#xff08;连接节点的线&#xff09;。图可以是有向的&#xff08;边有方向&#xff09;或无向的&#xff08;边没有方向&#xff09;。图搜索算法主要用…

C++高级特性:C/C++内存结构模型(十一)

1、内存结构 C/C语言一只被认为是一种底层语言&#xff0c;与其他语言不一样&#xff0c;对内存结构理解是C/C程序员从入门到入土的开端。 其他编程语言对内存管理是透明的&#xff0c;程序员无序关心可以认为是一个黑盒&#xff1b;而C/C不一样理解好内存结构有利于编写健壮性…

使用C++实现尾插式循环链表结构

在编码中避免不了使用链表&#xff0c;特别是循环链表&#xff0c;很多同学使用时为了省事直接使用C STL库中的链表实现&#xff0c;这样当然很简单也不容易出错&#xff0c;但同时也不可避免的带来了一些问题&#xff1a; 是半个黑盒&#xff0c;虽然能看源码&#xff0c;但是…

一个缓存泛型自动处理队列,留有处理事件接口

在C#中&#xff0c;创建一个通用泛型缓存队列工具通常涉及到使用泛型&#xff08;T&#xff09;来支持任意类型的队列项&#xff0c;并且实现先进先出&#xff08;FIFO&#xff09;的队列逻辑。为了提供自动处理和事件通知的功能&#xff0c;我们可以使用后台线程来处理队列中的…

【禅道客户案例】同方智慧能源数智化转型新实践 禅道助力前行

同方智慧能源是同方股份有限公司的骨干企业。依托中核集团、清华大学的科技优势&#xff0c;坚持技术和资源双核驱动&#xff0c;基于30多年行业积淀&#xff0c;面向建筑、交通、工业、北方供热、数据中心等主要用能场景提供设计咨询、产品技术、投资建设、运营服务&#xff0…

Redis集合 set 详解

Set简介 set 类似于 Java 中的 HashSet ,是redis中的一种数据结构&#xff0c;它是一个无序并且唯一的键值集合&#xff0c;并且储存时不会按照插入的先后顺序进行.一个集合中最多可以储存2^32 -1个元素。当你需要存储一个列表数据&#xff0c;又不希望出现重复数据时&#xf…

day26 java lambda

lambda lambda表达式 &#xff1a;对匿名内部类的对象的一种简写lambda表达式的格式 : (形参列表) -> {方法体}说明 &#xff1a;-> : lambda操作符 例:&#xff1a;Comparator 原代码&#xff1a; Collections.sort(list, new Comparator<Integer>() {Override…

DELL PowerEdge服务器通过iDRAC升级BIOS遇到的问题

本文对PowerEdge 12G系统&#xff0c;也就是iDRAC 7版本升级BIOS中遇到的几个问题做个总结&#xff0c;对于其他版本理论上应该也是适用的。如果还遇到其他问题&#xff0c;可以添加VX&#xff0c;VX号为 StorageExpert 进行进一步的分析探讨。 第一个问题&#xff0c;成功下载…

Android 11 裁剪系统显示区域(适配异形屏)

概述 在显示技术中&#xff0c;"OverScan"&#xff08;超扫描&#xff09;是一种调整显示图像边界的技术。通常情况下&#xff0c;OverScan 会在显示屏的边缘周围裁剪一小部分图像。这种裁剪是为了确保显示内容在屏幕上的完整可见性&#xff0c;尤其是在老式电视或投…

ZABAPGIT问题,导入github上的程序包时报 DBSQL_DUPLICATE_KEY_ERROR

跟踪程序发现在94050行 INSERT seocompotx FROM TABLE it_descriptions 报的错 刚开始&#xff0c;不想着改动他&#xff0c;把seocompotx 表的数据做下指定清楚&#xff0c;但是5次清楚后&#xff0c;果断注释掉 改成 MODIFY seocompotx FROM TABLE it_descriptions。 在用…

航片水体空洞修补

水体空洞情况如下图所示&#xff1a; 水体空洞修补结果如下图所示&#xff1a; 操作视频教程&#xff1a; MCM智拼图软件V8.5-漏洞空洞修补-水体修补_哔哩哔哩_bilibili

鸿蒙OpenHarmony【小型系统 编译】(基于Hi3516开发板)

编译 OpenHarmony支持hb和build.sh两种编译方式。此处介绍hb方式&#xff0c;build.sh脚本编译方式请参考[使用build.sh脚本编译源码]。 使用build.sh脚本编译源码 进入源码根目录&#xff0c;执行如下命令进行版本编译。 ./build.sh --product-name name --ccache 说明&…

基于LDLT分解求解Ax=b

前置知识&#xff0c;矩阵 A T ∗ A A^T * A AT∗A的性质&#xff1a; 实对称性&#xff1a;如果 A A A是实矩阵&#xff0c;那么 A T ∗ A A^T * A AT∗A是实对称矩阵。这意味着 ( A T ∗ A ) T A T ∗ ( A T ) T A T ∗ A (A^T * A)^T A^T * (A^T)^T A^T * A (AT∗A)…

基于数据挖掘的斗鱼直播数据可视化分析系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 随着网络直播平台的兴起&#xff0c;斗鱼直播作为其中的佼佼者&#xff0c;吸引了大量用户和观众。为了更好地理解和分析斗鱼直播中的数据&#xff0c;本项目介绍了一个基于数据挖掘的斗鱼直播数据…

【AI导师写作】毕业论文答辩PPT生成

无论是大专、本科或者硕博&#xff0c;撰写毕业论文、开题报告、文献综述、任务书、课程论文、调研报告等都是必不可少的一件事。而这些任务重往往都需要我们花费大量的时间和精力&#xff0c;而“AI导师写作”在这一方面无疑提供了高效和便捷。可毕业季的论文答辩也是每个学者…

C#调用skiasharp实现绘制并拖拽图形

SkiaSharp是基于.net的跨平台二维图形库&#xff0c;封装的谷歌的Skia库&#xff0c;SkiaSharp支持在以下平台或运行时中使用&#xff0c;能够在图片中绘图&#xff0c;也提供控件在Winform、WPF等使用。本文学习skiasharp在Winform的基本用法&#xff0c;并参照参考文献5实现绘…

【Java那些年系列-启航篇 04】Java程序架构:深入理解类与对象的设计原则

作者名称&#xff1a;纸飞机-暖阳 作者简介&#xff1a;专注于Java和大数据领域&#xff0c;致力于探索技术的边界&#xff0c;分享前沿的实践和洞见 文章专栏&#xff1a;Java那些年专栏 专栏介绍&#xff1a;本专栏涵盖了 Java SE从基础语法到面向对象编程&#xff0c;从异常…

一键PDF水印添加工具

一键PDF水印添加工具 引言优点1. 精准定位与灵活布局2. 自由旋转与透明度调控3. 精细化页码选择4. 全方位自定义水印内容5. 无缝整合工作流程 功能详解结语工具示意图【工具链接】 引言 PDF作为最常用的文档格式之一&#xff0c;其安全性和版权保护显得尤为重要。今天&#xff…

(delphi11最新学习资料) Object Pascal 学习笔记---第10章第3节( 委托的概念)

10.3.2 委托的概念 ​ 乍一看&#xff0c;委托这项技术的目标可能并不明确&#xff0c;但它却是Object Pascal 组件技术的基石之一。秘密就在委托这个词上。如果有人创建了一个对象&#xff0c;这个对象有一些方法指针&#xff0c;那么你只需把新的方法赋值给这些指针&#xf…

[移动端] “viewport“ content=“width=device-width, initial-scale=1.0“ 什么意思

布局视口, 代码如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>Document</title><style>body,html {margin: 0;padding: 0;}.box {width: 200px;height: 200px;background-color: pi…