力扣练习4.23

2024-04-23 23:12
文章标签 力扣 练习 4.23

本文主要是介绍力扣练习4.23,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

415. 字符串相加

解题思路:
将竖式加法实现,从个位开始相加。需要处理两个点:两个数加起来大于10的进位;两个数不一样长。
第一个需要新建一个进位变量,每次加完对10整除,得到进位;
第二个需要判断指针位置是否不存在,不存在则置为0.

步骤:
1.新建结果字符串、进位变量、指向两个字符串尾部的指针。
2.建立while循环,循环体内提取两个字符串的同位置数字,这里处理第二个难点;
3.处理进位,更新进位变量,计算当前位得到的值。
4.将当前位的值添加到结果字符串前面,形成结果。

class Solution:def addStrings(self, num1: str, num2: str) -> str:# 结果字符串res = ''# 进位carry = 0# 双指针,指向两个字符串的末尾index1, index2 = len(num1)-1, len(num2)-1# 从个位开始相加while index1 >= 0 or index2 >= 0 or carry:# 第一个字符串的某一位的数字,如果不够长,就置为0x = int(num1[index1]) if index1 >= 0 else 0y = int(num2[index2]) if index2 >= 0 else 0# 计算当前位的值value = (x+y+carry) % 10# 计算进位carry = (x+y+carry) // 10# 将当前位的值转为字符串加进结果字符串的前面res = str(value) + res# 移动指针,向前一位index1 -= 1index2 -= 1return res

239. 滑动窗口最大值

最初的想法:直接模拟,结果当然是超时,是O(nk)的复杂度。

from collections import dequeclass Solution:def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:if not nums:return []if k == 1:return nums# 初始化滑动窗口temp = nums[:k]# 结果列表res = [max(temp)]for i in range(k, len(nums)):# 滑动窗口移除第一个元素temp.pop(0)# 添加当前元素到最后temp.append(nums[i])# 计算当前窗口最大值max_num = max(temp)# 添加到结果列表res.append(max_num)return res

解题方法

将滑动窗口实现为双向队列,队列中存储索引,维护队列的第一个元素为窗口内最大值的索引,在每个窗口内取出第一个元素,在数组中访问即可得到每个滑动窗口内的最大值。
步骤:
1.初始化双向队列,结果列表
2.遍历数组。

  • 首先检查是否满足滑动窗口范围,否则就移除一次窗口最左边的元素;
  • 然后循环检查队列的尾部对应的数组元素是不是比当前遍历到的数组元素小,小的话就移除,因为我们要的是最大的。这样就构造了窗口内第一个元素对应的数组元素是最大值。
  • 队列添加当前元素的索引;
  • 如果已经遍历了k次,说明第一个滑动窗口已经形成,可以直接添加队列的首个元素对应的数组元素到结果列表。
from collections import dequeclass Solution:def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:if not nums:return []if k == 1:return nums# 初始化滑动窗口,双向队列dep = deque()# 结果列表res = []for i in range(len(nums)):# 滑动窗口移除出超出窗口范围的索引if dep and dep[0] < i-k+1:dep.popleft()# 移除窗口中所有小于当前元素的索引while dep and nums[dep[-1]] < nums[i]:dep.pop()# 添加当前元素的索引到窗口dep.append(i)# 这个时候对于到索引k-1的位置,已经初始化了一个滑动窗口,dep=[3,-1]if i >= k-1:res.append(nums[dep[0]])return res

3. 无重复字符的最长子串

解题思路:
快慢双指针,逐步扩大窗口,维护一个只有不重复元素的窗口;
判断不重复的方法:哈希表,每个元素都只有一个计数(每次遍历都检查一遍)
每次循环都更新长度。
步骤:
1.初始化快慢双指针,结果变量,哈希表
2.循环条件:快指针没有遍历完数组
3.循环体:

  • 将快指针指向元素添加进哈希表(本身有则加1,无则设1);
  • 内置循环检查当前元素是否在哈希表内重复,循环条件是当前元素的值>1,如果是,则将慢指针指向元素技术减1,代表窗口缩减;移动慢指针;
  • 更新长度变量;
  • 移动快指针。
class Solution:def lengthOfLongestSubstring(self, s: str) -> int:# 初始化快慢指针,最大长度,记录字符数的哈希表slow, fast, res = 0,0,0_dict = {}# 如果快指针还没遍历完成while fast < len(s):# 如果快指针指向的元素不在字典,添加if s[fast] not in _dict:_dict[s[fast]] = 1else:_dict[s[fast]] += 1# 检查当前元素是否有重复。重复则移动左指针while _dict[s[fast]] >= 2:_dict[s[slow]] -= 1# 如果删完了,就直接移除这个元素# 这一步没必要,因为要是后面有新的这个元素,会自动# if _dict[s[slow]] == 0:# del _dict[s[slow]]slow += 1# 更新长度res = max(res, fast-slow+1)# 移动右指针fast += 1return res

718. 最长重复子数组

解题思路1:滑动窗口

将两个数组对齐,考虑所有可能的对齐方式,每种方式都计算出公共数组长度,得到最长的长度。
算法步骤

  1. 定义辅助函数 max_len

    • 这个函数用来计算当 nums1 从索引 i 开始和 nums2 从索引 j 开始对齐时的最长公共子数组的长度。
    • 输入参数包括 nums1nums2,起始索引 ij
    • 在这个函数中,初始化 cur_len 为0(当前匹配的连续长度)和 max_len 为0(遍历过程中遇到的最长匹配长度)。
  2. 遍历数组元素

    • 使用一个循环,同时遍历 nums1nums2,从 ij 开始。
    • 如果 nums1[i] 等于 nums2[j],增加 cur_len 并更新 max_len
    • 如果不相等,则将 cur_len 重置为0。
  3. 返回最长公共子数组长度

    • 当某次对齐检查完成后,函数返回这次对齐的最长重复子数组长度。
  4. 遍历所有可能的对齐方式

    • 在主函数中,首先遍历 nums1,对每个可能的起始位置 i,调用 max_len 函数,把 nums2 的起始位置设置为0。
    • 然后遍历 nums2,对每个可能的起始位置 i,调用 max_len 函数,这次把 nums1 的起始位置设置为0。
  5. 更新和返回结果

    • 在主函数中,用变量 res 来保存遇到的最长的重复子数组长度。
    • 每次调用 max_len 后,用返回值更新 res
    • 最终返回 res,它是两个数组所有对齐方式中最长重复子数组的长度。
class Solution:def findLength(self, nums1: List[int], nums2: List[int]) -> int:# 滑动窗口# 求以某个数组为开始的公共子数组def max_len(nums1, nums2, i, j):n1,n2= len(nums1), len(nums2)max_len = 0 # 全局最长cur_len = 0 # 局部长度while i < n1 and j < n2:# 如果有公共元素,就增加局部长度,更新最长长度if nums1[i] == nums2[j]:cur_len += 1max_len = max(max_len, cur_len)else:cur_len = 0i += 1j += 1return max_lenn1, n2 = len(nums1), len(nums2)res = 0 # 最终的最长长度for i in range(n1):res = max(res,max_len(nums1,nums2,i,0))for i in range(n2):res = max(res,max_len(nums1,nums2,0,i))return res

解题思路2:动态规划

1.阶段划分:以子数组结尾部分划分。
2.状态定义:二维数组,dp[i][j]是以nums1[i-1],nums2[j-1]为结尾的最长子数组长度
3.状态转移方程:如果nums1[i-1] == nums2[j-1],则dp[i][j]=dp[i-1][j-1]+1;
否则,为0
4.状态初始化:默认以 nums1[i - 1] 结尾和 nums2[j - 1] 结尾的最长公共子数组长度为 0,dp[i][j]=0。
5.最终结果:取矩阵的最大的dp[i][j]作为结果

class Solution:def findLength(self, nums1: List[int], nums2: List[int]) -> int:# 动态规划size1, size2 = len(nums1), len(nums2)# 结果res = 0# 状态矩阵dp = [[0 for _ in range(size2+1)] for _ in range(size1+1)]# 遍历矩阵,for i in range(1,size1+1):for j in range(1,size2+1):# 状态转移if nums1[i-1] == nums2[j-1]:dp[i][j] = dp[i-1][j-1] + 1# 获取最大值if dp[i][j] > res:res = dp[i][j]return res

83. 删除排序链表中的重复元素

解题思路:
因为已经排好序了,所以只用关注当前和下一个节点,如果值相等,就把当前节点的指针指向下下个节点;否则,移动到下一个节点,继续比较。
步骤:
1.初始化指针节点,指向头结点
2.创建while循环,条件是指针节点和下一个节点都非空
3.循环体:如果两个节点值相同,则跳过下一个节点;否则,移动指针节点到下一个节点,这样就算是1-1-1-1-2也不怕。
4.返回头节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:# 指针节点cur_node = headwhile cur_node and cur_node.next:# 两个节点重复,将当前元素的指针指向下下个元素if cur_node.val == cur_node.next.val:cur_node.next = cur_node.next.nextelse:# 否则,移动到下一个节点cur_node = cur_node.next# 返回头节点return head

82. 删除排序链表中的重复元素 II

跟上一题的不同在于要把所有重复的元素删除,上一题还保留呢。
解题思路:
为了防止头结点也是重复元素,需要设置一个哑结点,指向头结点;
然后判断相邻的两个节点是否重复。如果重复,就将相邻的前一个元素另存为临时变量,并且循环判断相邻的后一个元素和其后的元素是否重复,重复则移动临时变量到下一个节点;
临时变量退出循环后,其下一个元素是与前面的任意元素都不重复的,因此将指针指向临时变量的下一个元素。
如果不重复,则移动指针到下一个元素。

代码分析

  1. 哑节点(Dummy Node):

    • 创建一个哑节点 dummy_head 并将其 next 指针指向链表的头部 head。这样做的好处是可以方便地处理头部可能为重复节点需要删除的情况。
  2. 初始化指针:

    • cur 指针初始化为 dummy_head。这个指针用于遍历链表,并且指向当前考虑的节点的前一个节点,以便于进行节点的删除操作。
  3. 循环遍历链表:

    • 使用 while 循环遍历链表。条件 cur.next and cur.next.next 确保 cur 后至少有两个节点,这是检测重复的前提条件。
  4. 检测并跳过重复节点:

    • 如果 cur.next.val 等于 cur.next.next.val,说明找到了重复的节点。
    • 内部 while 循环 (while temp and temp.next and temp.val == temp.next.val) 用于跳过所有重复的节点。temp
      指针从当前重复节点的第一个节点开始,一直移动到这组重复节点的最后一个节点。
    • 之后,通过 cur.next = temp.next 将最后一个重复节点的下一个节点(非重复节点或None)连接到 curnext,从而跳过了所有重复的节点。
  5. 移动指针:

    • 如果当前的两个节点不相等,即 cur.next.val 不等于 cur.next.next.val,则直接将 cur 指针向前移动一位(cur = cur.next)。这表明当前节点没有重复,可以安全地保留。
  6. 返回修改后的链表:

    • 返回 dummy_head.next,这是删除重复节点后链表的新头部。

示例

给定链表 1 -> 2 -> 2 -> 3 -> 4 -> 4 -> 5,该算法将工作如下:

  • 初始时,dummy_head -> 1 -> 2 -> 2 -> 3 -> 4 -> 4 -> 5
  • cur 指向 1,发现 2 重复,跳过所有 2
  • 然后 cur 指向 3,再次发现 4 重复,跳过所有 4
  • 最终,链表变为 1 -> 3 -> 5
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:# 创建虚拟节点dummy_head = ListNode(0)dummy_head.next = head# 创建指针cur = dummy_head# 当指针节点的下一个和下下个都存在while cur.next and cur.next.next:# 如果这两个节点相同if cur.next.val == cur.next.next.val:# 将第二个节点保存temp = cur.next# 只要一直跟后面有重复,就不断更新节点while temp and temp.next and temp.val == temp.next.val:temp = temp.next# 这个时候得到的下一个节点是与前面的节点不重复的# 将其与伪节点相连cur.next = temp.nextelse:# 不重复,就移动节点cur = cur.next# 返回伪节点的下一个节点,也就是头节点return dummy_head.next

206. 反转链表在这里插入代码片

解题思路:
遍历链表。
首先将链表最后一个节点看作指向null;
每次遍历,将当前节点修改指向到前驱节点,将前驱节点更新为第一个节点。

步骤:
1.初始化前驱节点为null,指针。
2.创建循环,只要指针不为空
3.循环体:
因为下面要修改当前节点的指针,所以先创建一个临时变量存储其后继节点;
修改当前节点的指针指向前驱节点;
将前驱节点更新为当前节点;
移动指针到原始的后继节点(临时变量)
4.最终得到的前驱节点就是反转后的头节点

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:# 前驱节点pre = None# 指针cur = headwhile cur:# 暂存后继节点temp = cur.next# 将当前节点的指针指向前驱节点cur.next = pre# 将当前节点作为下一个前驱节点pre = cur# 移动指针,到下一个节点cur = tempreturn pre

这篇关于力扣练习4.23的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/930149

相关文章

RabbitMQ练习(AMQP 0-9-1 Overview)

1、What is AMQP 0-9-1 AMQP 0-9-1(高级消息队列协议)是一种网络协议,它允许遵从该协议的客户端(Publisher或者Consumer)应用程序与遵从该协议的消息中间件代理(Broker,如RabbitMQ)进行通信。 AMQP 0-9-1模型的核心概念包括消息发布者(producers/publisher)、消息(messages)、交换机(exchanges)、

【Rust练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m

MySql 事务练习

事务(transaction) -- 事务 transaction-- 事务是一组操作的集合,是一个不可分割的工作单位,事务会将所有的操作作为一个整体一起向系统提交或撤销请求-- 事务的操作要么同时成功,要么同时失败-- MySql的事务默认是自动提交的,当执行一个DML语句,MySql会立即自动隐式提交事务-- 常见案例:银行转账-- 逻辑:A给B转账1000:1.查询

html css jquery选项卡 代码练习小项目

在学习 html 和 css jquery 结合使用的时候 做好是能尝试做一些简单的小功能,来提高自己的 逻辑能力,熟悉代码的编写语法 下面分享一段代码 使用html css jquery选项卡 代码练习 <div class="box"><dl class="tab"><dd class="active">手机</dd><dd>家电</dd><dd>服装</dd><dd>数码</dd><dd

两数之和--力扣1

两数之和 题目思路C++代码 题目 思路 根据题目要求,元素不能重复且不需要排序,我们这里使用哈希表unordered_map。注意题目说了只对应一种答案。 所以我们在循环中,使用目标值减去当前循环的nums[i],得到差值,如果我们在map中能够找到这个差值,就说明存在两个整数的和为目标值。 如果没有找到,就将当前循环的nums[i]以及下标i放入map中,以便后续查

力扣第347题 前K个高频元素

前言 记录一下刷题历程 力扣第347题 前K个高频元素 前K个高频元素 原题目: 分析 我们首先使用哈希表来统计数字出现的频率,然后我们使用一个桶排序。我们首先定义一个长度为n+1的数组,对于下图这个示例就是长度为7的数组。为什么需要一个长度为n+1的数组呢?假如说总共有三个数字都为1,那么我们需要把这个1放在数组下标为3的位置,假如说数组长度为n,对于这个例子就是长度为3,那么它的

014.Python爬虫系列_解析练习

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈 优

如何快速练习键盘盲打

盲打是指在不看键盘的情况下进行打字,这样可以显著提高打字速度和效率。以下是一些练习盲打的方法: 熟悉键盘布局:首先,你需要熟悉键盘上的字母和符号的位置。可以通过键盘图或者键盘贴纸来帮助记忆。 使用在线打字练习工具:有许多在线的打字练习网站,如Typing.com、10FastFingers等,它们提供了不同难度的练习和测试。 练习基本键位:先从学习手指放在键盘上的“家位”开始,通常是左手的

anaconda3下的python编程练习-csv翻译器

相关理解和命令 一、环境配置1、conda命令2、pip命令3、python命令 二、开发思路三、开发步骤 一、环境配置 1、conda命令 镜像源配置 conda config --show channels //查看镜像源conda config --remove-key channels //删除添加源,恢复默认源#添加镜像源conda config --ad

推荐练习键盘盲打的网站

对于初学者来说,以下是一些推荐的在线打字练习网站: 打字侠:这是一个专业的在线打字练习平台,提供科学合理的课程设置和个性化学习计划,适合各个水平的用户。它还提供实时反馈和数据分析,帮助你提升打字速度和准确度。 dazidazi.com:这个网站提供了基础的打字练习,适合初学者从零开始学习打字。 Type.fun打字星球:提供了丰富的盲打课程和科学的打字课程设计,还有诗词歌赋、经典名著等多样