当前位置: 首页 > news >正文

初学python的我开始Leetcode题-17

提示:100道LeetCode热题-17主要是一些技巧,包括五题:只出现一次的数字、多数元素、颜色分类、下一个排列、寻找重复数。由于初学,所以我的代码部分仅供参考。


前言

这是Leetcode100题的最后一点啦,记得时时复习哇!加油~


提示:以下是本篇文章正文内容,下面结果代码仅供参考

题目1:只出现一次的数字

1.题目要求:

题目如下:

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1 :

输入:nums = [2,2,1]

输出:1

示例 2 :

输入:nums = [4,1,2,1,2]

输出:4

示例 3 :

输入:nums = [1]

输出:1

提示:

  • 1 <= nums.length <= 3 * 10^{4}
  • -3 * 10^{4} <= nums[i] <= 3 * 10^{4}
  • 除了某个元素只出现一次以外,其余每个元素均出现两次。

代码框架已经提供如下:

class Solution(object):

    def singleNumber(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

2.结果代码:

class Solution(object):def singleNumber(self, nums):""":type nums: List[int]:rtype: int"""result = 0for num in nums:result ^= numreturn result

说明:

可能的解决方案:

方法一:哈希表

使用哈希表(如 Python 的 dictcollections.Counter)来统计每个数字出现的次数。然后遍历哈希表,找出出现次数为1的数字。

  • 时间复杂度:O(n),因为需要遍历数组统计次数,再遍历哈希表找出单元素。

  • 空间复杂度:O(n),因为哈希表需要存储最多 n/2 + 1 个键值对。

问题:虽然时间复杂度满足 O(n),但空间复杂度是 O(n),不满足 O(1) 的要求。因此,这种方法不符合题目要求。

方法二:排序后查找

先对数组排序,然后遍历数组,检查相邻元素是否相同。因为相同的元素会相邻出现,所以可以找到单独的元素。

  • 时间复杂度:排序需要 O(n log n),遍历需要 O(n),总体是 O(n log n)。

  • 空间复杂度:如果使用原地排序(如 Timsort),空间复杂度可能是 O(1) 或 O(log n)。

问题:时间复杂度不满足 O(n) 的要求。

方法三:数学方法

利用数学性质,所有数字的和可以表示为:

sum(nums) = 2 * sum(set(nums)) - single_number

因此:

single_number = 2 * sum(set(nums)) - sum(nums)

  • 时间复杂度:O(n),因为 sumset 都是 O(n)。

  • 空间复杂度set(nums) 需要 O(n) 空间。

问题:空间复杂度不满足 O(1)。

方法四:位运算(异或)

异或(XOR)运算有以下性质:

  1. a ^ a = 0(任何数异或自己等于 0)。

  2. a ^ 0 = a(任何数异或 0 等于自己)。

  3. 异或运算满足交换律和结合律:a ^ b ^ a = (a ^ a) ^ b = 0 ^ b = b

因此,可以将所有数字进行异或运算,出现两次的数字会互相抵消为 0,最终剩下的就是只出现一次的数字。

  • 时间复杂度:O(n),只需遍历数组一次。

  • 空间复杂度:O(1),只需要一个变量存储结果。

综上所述,这里使用异或(XOR)

代码解释:

  1. 初始化 result 为 0:因为 0 ^ x = x,0 是异或运算的单位元。

  2. 遍历数组 nums:对每个元素 num,执行 result ^= num

  3. 返回 result:遍历结束后,result 就是只出现一次的数字。

题目2:多数元素

1.题目要求:

题目如下:

给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:nums = [3,2,3]
输出:3

示例 2:

输入:nums = [2,2,1,1,1,2,2]
输出:2

提示:
  • n == nums.length
  • 1 <= n <= 5 * 10^{4}
  • -10^{9} <= nums[i] <= 10^{9}

进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。

代码框架已经提供如下:

class Solution(object):

    def majorityElement(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

2.结果代码:

class Solution(object):def majorityElement(self, nums):""":type nums: List[int]:rtype: int"""candidate = Nonecount = 0for num in nums:if count == 0:candidate = numcount += (1 if num == candidate else -1)return candidate

说明:

可能的解决方案

方法一:哈希表计数

使用哈希表(如 Python 的 dictcollections.Counter)统计每个数字的出现次数,然后遍历哈希表找到出现次数大于 n/2 的数字。

  • 时间复杂度:O(n),遍历数组统计次数需要 O(n),遍历哈希表需要 O(k)(k 是不同元素的数量,最坏为 n)。

  • 空间复杂度:O(n),哈希表最多存储 n 个键值对。

问题:虽然时间复杂度满足 O(n),但空间复杂度是 O(n)。可以接受,但不是最优解。

方法二:排序后取中位数

多数元素的出现次数大于 n/2,因此排序后,中间位置的元素一定是多数元素。

  • 时间复杂度:O(n log n),排序需要时间。

  • 空间复杂度:O(1) 或 O(log n)(取决于排序实现)。

问题:时间复杂度不满足 O(n)。

方法三:Boyer-Moore 投票算法

这是一种专门用于寻找多数元素的高效算法,满足 O(n) 时间和 O(1) 空间。

算法思路

  1. 初始化候选元素 candidate 和计数器 count 为 0。

  2. 遍历数组:

    • 如果 count == 0,将当前元素设为 candidate

    • 如果当前元素等于 candidatecount 加 1;否则减 1。

  3. 遍历结束后,candidate 就是多数元素。

综上所述,选择Boyer-Moore 投票算法。

代码解释:

  1. 初始化

    • candidate:当前候选的多数元素,初始为 None

    • count:当前候选元素的“净票数”,初始为 0。

  2. 遍历数组

    • 如果 count == 0,说明之前的候选元素已被抵消完,重新选择当前元素作为候选。

    • 如果当前元素等于 candidatecount 加 1(支持票);否则减 1(反对票)。

  3. 返回结果:遍历结束后,candidate 一定是多数元素(题目保证多数元素存在)。

题目3:颜色分类

1.题目要求:

题目如下:

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

    必须在不使用库内置的 sort 函数的情况下解决这个问题。

    示例 1:

    输入:nums = [2,0,2,1,1,0]
    输出:[0,0,1,1,2,2]
    

    示例 2:

    输入:nums = [2,0,1]
    输出:[0,1,2]
    

    提示:

    • n == nums.length
    • 1 <= n <= 300
    • nums[i] 为 01 或 2

    进阶:

    • 你能想出一个仅使用常数空间的一趟扫描算法吗?

    代码框架已经提供如下:

    class Solution(object):

        def sortColors(self, nums):

            """

            :type nums: List[int]

            :rtype: None Do not return anything, modify nums in-place instead.

            """

    2.结果代码:

    class Solution(object):def sortColors(self, nums):""":type nums: List[int]:rtype: None Do not return anything, modify nums in-place instead."""low, mid, high = 0, 0, len(nums) - 1while mid <= high:if nums[mid] == 0:nums[low], nums[mid] = nums[mid], nums[low]low += 1mid += 1elif nums[mid] == 1:mid += 1else:  # nums[mid] == 2nums[high], nums[mid] = nums[mid], nums[high]high -= 1

    说明:

    这是经典的“荷兰国旗问题”,可以用三指针(或双指针)在一趟扫描内完成。

    思路

    • 维护三个指针:

      • low:0 的右边界(nums[0..low-1] 都是 0)。

      • mid:当前考察的元素。

      • high:2 的左边界(nums[high+1..n-1] 都是 2)。

    • 初始:low = 0, mid = 0, high = n - 1

    • 遍历条件:mid <= high

      • nums[mid] == 0:交换 nums[low]nums[mid],然后 low += 1, mid += 1

      • nums[mid] == 1mid += 1(直接跳过)。

      • nums[mid] == 2:交换 nums[mid]nums[high],然后 high -= 1(不移动 mid,因为交换后 nums[mid] 可能是 0 或 1)。

    题目4:下一个排列

    1.题目要求:

    题目如下:

    整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。

    • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3][1,3,2][3,1,2][2,3,1] 。

    整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

    • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
    • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
    • 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

    给你一个整数数组 nums ,找出 nums 的下一个排列。

    必须 原地 修改,只允许使用额外常数空间。

    示例 1:

    输入:nums = [1,2,3]
    输出:[1,3,2]
    

    示例 2:

    输入:nums = [3,2,1]
    输出:[1,2,3]
    

    示例 3:

    输入:nums = [1,1,5]
    输出:[1,5,1]
    

    提示:

    • 1 <= nums.length <= 100
    • 0 <= nums[i] <= 100

    代码框架已经提供如下:

    class Solution(object):

        def nextPermutation(self, nums):

            """

            :type nums: List[int]

            :rtype: None Do not return anything, modify nums in-place instead.

            """

    2.结果代码:

    class Solution(object):def nextPermutation(self, nums):""":type nums: List[int]:rtype: None Do not return anything, modify nums in-place instead."""n = len(nums)if n <= 1:return# Step 1: Find the first decreasing element from the endi = n - 2while i >= 0 and nums[i] >= nums[i + 1]:i -= 1if i >= 0:# Step 2: Find the first element larger than nums[i] from the endj = n - 1while j >= 0 and nums[j] <= nums[i]:j -= 1# Step 3: Swap nums[i] and nums[j]nums[i], nums[j] = nums[j], nums[i]# Step 4: Reverse the subarray from i+1 to endleft, right = i + 1, n - 1while left < right:nums[left], nums[right] = nums[right], nums[left]left += 1right -= 1

    说明:

    我们需要找到给定整数数组 nums下一个排列。下一个排列是指字典序比当前排列大的最小排列。如果当前排列已经是最大的字典序,则返回最小的字典序(即升序排列)。

    关键概念:字典序:

    字典序是比较两个序列的顺序,类似于字典中单词的顺序。例如:

    • [1,2,3] < [1,3,2](因为第二个元素 2 < 3)。

    • [3,2,1] 是最大的字典序,因此下一个排列是 [1,2,3]

    寻找下一个排列的步骤

    1. 从后向前查找第一个下降的位置 i

      • 即找到最大的 i 使得 nums[i] < nums[i+1]

      • 如果找不到这样的 i,说明整个数组是降序排列,已经是最大字典序,直接反转整个数组即可。

    2. 从后向前查找第一个大于 nums[i] 的位置 j

      • 即找到最大的 j 使得 nums[j] > nums[i]

    3. 交换 nums[i]nums[j]

    4. 反转 i+1 到末尾的子数组

      • 因为 i+1 到末尾的子数组是降序排列,反转后变为升序,这是比原排列大的最小排列。

    题目5:寻找重复数

    1.题目要求:

    题目如下:

    给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

    假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

    你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

    示例 1:

    输入:nums = [1,3,4,2,2]
    输出:2
    

    示例 2:

    输入:nums = [3,1,3,4,2]
    输出:3
    

    示例 3 :

    输入:nums = [3,3,3,3,3]
    输出:3

    提示:

    • 1 <= n <= 10^{5}
    • nums.length == n + 1
    • 1 <= nums[i] <= n
    • nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

    进阶:

    • 如何证明 nums 中至少存在一个重复的数字?
    • 你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?

    代码框架已经提供如下:

    class Solution(object):

        def findDuplicate(self, nums):

            """

            :type nums: List[int]

            :rtype: int

            """

    2.结果代码:

    class Solution(object):def findDuplicate(self, nums):""":type nums: List[int]:rtype: int"""# 快慢指针初始化slow = nums[0]fast = nums[nums[0]]# 第一阶段:找到相遇点while slow != fast:slow = nums[slow]fast = nums[nums[fast]]# 第二阶段:找到环入口slow = 0while slow != fast:slow = nums[slow]fast = nums[fast]return slow

    说明:

    可能的解决方案:

    方法一:暴力法(哈希表)

    使用哈希表记录出现过的数字,遇到重复的直接返回。

    • 时间复杂度:O(n)。

    • 空间复杂度:O(n)(哈希表需要额外空间)。

    • 问题:不满足 O(1) 空间要求。

    方法二:排序后查找

    排序后,重复的数字会相邻出现。

    • 时间复杂度:O(n log n)。

    • 空间复杂度:O(1)(原地排序)。

    • 问题:修改了原数组,不满足“不修改数组”的要求。

    方法三:二分查找(基于值域)

    利用 [1, n] 的数字范围,统计数字 <= mid 的个数:

    1. 初始化 left = 1, right = n

    2. 计算 mid = (left + right) // 2

    3. 统计 nums<= mid 的数字个数 count

      • 如果 count > mid,说明重复数字在 [left, mid]

      • 否则,重复数字在 [mid + 1, right]

    4. 缩小范围,直到 left == right

    • 时间复杂度:O(n log n)(二分需要 log n 次,每次统计需要 O(n))。

    • 空间复杂度:O(1)。

    • 问题:时间复杂度不满足 O(n)。

    方法四:快慢指针(Floyd 判环法)(选择这个)

    nums 视为链表,其中 nums[i] 表示 i -> nums[i] 的边。由于数字在 [1, n] 且长度为 n + 1,必然存在环,重复的数字就是环的入口。

    步骤

    1. 初始化slow = nums[0], fast = nums[nums[0]]

    2. 相遇阶段

      • slow = nums[slow]

      • fast = nums[nums[fast]]

      • 直到 slow == fast(相遇)。

    3. 找入口阶段

      • slow = 0

      • slowfast 每次移动一步,直到 slow == fast(入口即重复数字)。

    原理

    • 类似链表环检测,重复数字会导致多个指针指向同一位置。

    • 数学证明:相遇点到环入口的距离等于起点到环入口的距离。


    总结

    对五种题型的技巧进行了学习,了解了部分有关python的相关知识,大家加油!

    http://www.dtcms.com/a/356854.html

    相关文章:

  • Azure Marketplace 和 Microsoft AppSource的区别
  • 订餐后台管理系统 -day03 登录模块
  • Linux操作系统Shell脚本-第一章
  • 数据防泄与最小可见:ABP 统一封装行级安全(RLS)+ 列级脱敏
  • 前端vue3入门学习
  • 数据分析编程第七步:分析与预测
  • 【MFC自动生成的文件详解:YoloClassMFC.cpp 的逐行解释、作用及是否能删除】
  • 科技赋能医疗:陪诊小程序系统开发,让就医不再孤单
  • cursor的setting設置換行
  • 舰用燃气机数字孪生:舰船动力智慧管控核心
  • 从0到1玩转 Google SEO
  • 循环高级(1)
  • Parasoft赋能测试:精准捕捉运行时缺陷
  • 深度学习入门Day10:深度强化学习原理与实战全解析
  • 彻底弄清URI、URL、URN的关系
  • 基于LangChain框架搭建AI问答系统(附源码)
  • 将2D基础模型(如SAM/SAM2)生成的2D语义掩码通过几何一致性约束映射到3D高斯点云
  • android 不同分辨图片放错对应文件夹会怎样?
  • Python 编码与加密全解析:从字符编码到 RSA 签名验证
  • (笔记)Android ANR检测机制深度分析
  • 【微知】如何撤销一个git的commit?以及撤销的3种方式?
  • 多代理系统架构:Supervisor 与 Swarm 架构详解
  • Java面试-MySQL事务
  • Word文档怎么打印?Word打印技巧?【图文详解】单面/双面/指定页面/逆序等Word打印选项
  • 微信小程序中蓝牙打印机中文编码处理:使用iconv-lite库
  • Java 大视界 -- Java 大数据在智能安防入侵检测系统中的多模态数据融合与检测精度提升(405)
  • 将数据赋值到多个文档里,并将多个word放入压缩包并下载
  • Elasticsearch 9.X 使用推理 API 进行语义搜索
  • JAVA 请求第三方接口,将JSON数据转为对象
  • 微软正在公开测试其首个完全自主训练的大语言模型——MAI-1-preview