Python题解Leetcode Hot100之技巧

1. 只出现一次的数字

  • 题目描述
    给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

  • 解题思路
    使用异或运算符。因为相同的数异或后为 0,任何数与 0 异或是其本身,所以将所有元素进行异或操作,最终结果即为只出现一次的元素。
    时间复杂度:O(n), 空间复杂度O(1)

  • 代码

    python 复制代码
    class Solution:
        def singleNumber(self, nums: List[int]) -> int:
            n = len(nums)
            res = 0
            for i in nums:
                res = res ^ i
            return res

2. 多数元素

  • 题目描述
    给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊n / 2⌋ 的元素。

  • 解题思路
    根据提议可知,多数元素出现的次数大于其他所有元素出现次数之和。使用摩尔投票算法(Boyer-Moore Voting Algorithm)。遍历数组,维护一个候选多数元素和计数器,遇到相同元素则计数加一,不同则减一,计数为零时更换候选元素。最终的候选元素即为多数元素。
    时间复杂度:O(n), 空间复杂度O(1)

  • 代码

    python 复制代码
    class Solution:
        def majorityElement(self, nums: List[int]) -> int:
            res = nums[0]
            count = 1
            for i in nums[1:]:
                if i == res:
                    count += 1
                else:
                    count -= 1
                if count == 0:
                    res = i
                    count = 1
            return res

3. 颜色分类

  • 题目描述
    给定一个包含红色、白色和蓝色、共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。这里使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

  • 解题思路
    使用双指针方法,一个指针用于扫描数组,另两个指针分别维护红色区域的边界和蓝色区域的边界,遍历数组时,根据当前元素调整指针和元素的位置。
    只要是0就把他移动到最左边的区域,是2就把他移动到最右边的区域,最后中间区域一定剩下的是1;
    注意用于扫描数组的指针i在nums[i] = 0或者nums[i] = 1时会+1,因为从左边被交换过来的元素一定是已经遍历的过的,而nums[i] = 2时,交换完之后i不会加1,因为从右边交换过来的元素时全新的没有见过;
    时间复杂度:O(n), 空间复杂度O(1)

  • 代码

    python 复制代码
    class Solution:
        def sortColors(self, nums: List[int]) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            
            n = len(nums)
            zero = -1
            two = n
            i = 0
            while i < two:
                if nums[i] == 1:
                    i += 1
                elif nums[i] == 0:
                    zero += 1
                    nums[zero], nums[i] = nums[i], nums[zero]
                    i += 1
                else:
                	# 注意nums[i] = 2时,i不加1
                    two -= 1
                    nums[two], nums[i] = nums[i], nums[two]

4. 下一个排列

  • 题目描述
    实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。如果不存在下一个更大的排列,则将其排列成最小的排列(即升序排列)。

  • 解题思路

    • 数字倒序排列组成的数字,字典序最大;正序排列的数字序列,字典序最小
    • 从后向前查找第一个正序对,倒序排列的部分字典序已经是最大了,没有调整的余地了
    • 在右边倒序的部分中找到大于nums[i]的最小数字,和nums[i]进行交换
    • 此时i右边仍是倒序,翻转成正序,正序是字典序最小的排列方式
  • 代码

    python 复制代码
    class Solution:
        def nextPermutation(self, nums: List[int]) -> None:
            """
            Do not return anything, modify nums in-place instead.
            """
            # 数字倒序排列组成的数字,字典序最大
    
            def reverse(nums, left, right):
                l = left
                r = right
                while l <= r:
                    nums[l], nums[r] = nums[r], nums[l]
                    l += 1
                    r -= 1
            n = len(nums)
            if n <= 1:
                return nums
            # 从后向前查找第一个正序对,倒序排列的部分字典序已经是最大了,没有调整的余地了
            for i in range(n - 2, -1, -1):
                if nums[i] < nums[i + 1]:
                    j = n - 1
                    # 在右边倒序的部分中找到大于nums[i]的最小数字,和nums[i]进行交换
                    while j > i:
                        if nums[j] > nums[i]:
                            nums[i], nums[j] = nums[j], nums[i]
                            # 此时i右边仍是倒序,翻转成正序,正序是字典序最小的排列方式
                            reverse(nums, i + 1, n - 1)
                            return 
                        j -= 1
            # 如果到了这一步说明整个序列都是倒序,那么直接翻转即可
            reverse(nums, 0, n - 1)

5. 寻找重复数

  • 题目描述
    给定一个包含 n + 1 个整数的数组,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

  • 解题思路
    原地哈希,将第i个数放到第nums[i]位置上,如果发现nums[i]位置上的数已经是nums[i]了,那么就说明这个数是重复数

  • 代码

    python 复制代码
    class Solution:
        def findDuplicate(self, nums: List[int]) -> int:
            n = len(nums)
            i = 0
            while i < n:
                cur_num = nums[i]
                if cur_num != i:
                	# 如果nums[nums[i]]处不是nums[i],那么交换nums[nums[i]]和nums[i]
                    if nums[cur_num] != cur_num:
                        nums[cur_num], nums[i] = nums[i], nums[cur_num]
                    else:
                        return cur_num
                else:
                    i += 1
相关推荐
yuanbenshidiaos1 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习1 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA2 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo2 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
黄公子学安全2 小时前
Java的基础概念(一)
java·开发语言·python
jackiendsc2 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
姚先生972 小时前
LeetCode 54. 螺旋矩阵 (C++实现)
c++·leetcode·矩阵
程序员一诺2 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
小木_.2 小时前
【Python 图片下载器】一款专门为爬虫制作的图片下载器,多线程下载,速度快,支持续传/图片缩放/图片压缩/图片转换
爬虫·python·学习·分享·批量下载·图片下载器
游是水里的游3 小时前
【算法day20】回溯:子集与全排列问题
算法