LeetCode从入门到超凡(一)枚举算法

news2024/11/13 9:56:50

前言

大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的LeetCode学习总结文档;本文主要讲解枚举算法。💕💕😊

一、基本概念

1.定义

  • 定义枚举算法通过**列举所有可能的解来找到满足条件的解**。它是一种“暴力搜索”方法,通过逐一检查每个可能的解,判断其是否满足问题的要求。
  • 核心思想:枚举算法的核心思想是“穷举”,即通过系统地列举所有可能的情况,并逐一验证这些情况是否满足问题的条件。这种思想适用于那些解空间较小且可以预先确定的问题。

2. 优缺点

  • 优点
    • 容易编程实现:枚举算法通常逻辑简单,易于编写和调试。
    • 调试简单:由于算法逻辑清晰,调试过程中容易定位问题。
    • 正确性容易证明:通过逐一验证所有可能的解,可以确保找到的解是正确的。
  • 缺点
    • 效率较低:在大规模问题中,枚举所有可能的解会导致计算量巨大,效率低下。
    • 空间复杂度高:在某些情况下,枚举算法可能需要大量的存储空间来存储所有可能的解。

3.适用场景

  • 问题规模较小:当问题的规模较小,枚举所有可能的解不会导致计算量过大时,枚举算法是一个有效的选择。
  • 问题解空间有限:当问题的解空间有限且可以预先确定时,枚举算法可以有效地找到所有满足条件的解。
  • 需要验证所有可能的解:当需要确保找到所有可能的解,或者问题的解空间较小且易于列举时,枚举算法是一个合适的选择。

二、解题思路

思路

① 确定枚举对象、范围和判断条件
  • 确定枚举对象
    • 明确需要枚举的变量或对象:在解题过程中,首先需要明确哪些变量或对象是需要枚举的。例如,在寻找两个数的和等于某个目标值的问题中,需要枚举两个数。
  • 确定枚举范围
    • 确定每个枚举对象的取值范围:在确定枚举对象后,需要明确每个枚举对象的取值范围。例如,如果枚举对象是整数,需要确定其最小值和最大值。
  • 确定判断条件
    • 设定判断条件以筛选出满足要求的解:在枚举过程中,需要设定一个或多个判断条件,以筛选出满足问题的解。例如,判断两个数的和是否等于目标值。
② 列举并验证
  • 逐一列举所有可能的情况,并验证是否满足问题的解
    • 列举所有可能的情况:根据确定的枚举对象和范围,列举所有可能的情况。
    • 验证是否满足问题的解:对每个列举的情况,使用设定的判断条件进行验证,筛选出满足条件的解。
③ 提高效率
  • 缩小问题状态空间的大小
    • 减少枚举对象的数量:通过分析问题的特性,减少需要枚举的对象数量,从而缩小状态空间的大小。
    • 减少枚举对象的取值范围:通过设定合理的上下界,减少枚举对象的取值范围,从而提高效率。
  • 加强约束条件,缩小枚举范围
    • 增加额外的约束条件:通过增加额外的约束条件,进一步缩小枚举范围,减少不必要的计算。
    • 利用对称性或其他数学性质:通过利用问题的对称性或其他数学性质,减少需要枚举的情况。
  • 利用问题特有性质,避免重复求解
    • 避免重复计算:通过记录已经计算过的结果,避免重复求解相同的情况。
    • 利用问题的特有性质:通过分析问题的特有性质,减少需要枚举的情况,提高效率。例如对称性等。

案例:百钱买百鸡问题

① 问题描述

给定 100 块钱,要求买 100 只鸡。已知公鸡每只 5 块钱,母鸡每只 3 块钱,小鸡每 3 只 1 块钱。问公鸡、母鸡、小鸡各买了多少只?

② 解题思路
  1. 确定枚举对象、范围和判断条件
    • 枚举对象:公鸡、母鸡、小鸡的只数,分别用变量 xyz 表示。
③ 流程图

lct

④ 代码实现
class Solution:
    def buyChicken(self):
        for x in range(21):
            for y in range(34):
                z = 100 - x - y
                if z % 3 == 0 and 5 * x + 3 * y + z // 3 == 100:
                    print("公鸡 %s 只,母鸡 %s 只,小鸡 %s 只" % (x, y, z))

# 示例
solution = Solution()
solution.buyChicken()

输出示例:

公鸡 0 只,母鸡 25 只,小鸡 75 只
公鸡 4 只,母鸡 18 只,小鸡 78 只
公鸡 8 只,母鸡 11 只,小鸡 81 只
公鸡 12 只,母鸡 4 只,小鸡 84 只

三、题目案例

1.两数之和

1. 两数之和 - 力扣(LeetCode)

① 问题描述

给定一个整数数组 nums 和一个目标值 target,找出数组中两个数的和等于目标值的所有组合。

② 解题思路
  1. 确定枚举对象、范围和判断条件
    • 枚举对象:数组中的两个数 nums[i]nums[j]
    • 枚举范围ij 的取值范围分别是 0n-1,其中 n 是数组的长度。
    • 判断条件nums[i] + nums[j] == target
  2. 列举并验证
    • 使用两层循环,外层循环遍历 i,内层循环遍历 j,逐一列举所有可能的数对 (nums[i], nums[j])
    • 对每个数对,验证其和是否等于目标值 target
  3. 提高效率
    • 减少枚举对象的数量:通过设定 j 的起始值为 i+1,避免重复枚举相同的数对。
    • 减少枚举对象的取值范围:通过设定合理的上下界,减少需要枚举的数对数量。
③ 流程图

在这里插入图片描述

④ 代码实现
class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        result = []
        n = len(nums)
        
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    result.extend([i, j])
                    return result  # 假设你只想要第一个匹配的结果
        
        return result


调用测试:

2. 计数质数

204. 计数质数 - 力扣(LeetCode)

① 问题描述

给定一个整数 n,统计小于 n 的所有质数的数量。

质数是大于 1 的自然数,除了 1 和它本身外,不能被其他自然数整除的数。

② 解题思路
  1. 枚举区间内的每一个数,判断其是否为质数
    • 对于每个数 i(从 2 到 n-1),判断其是否为质数。
    • 判断质数的方法:从 2 到 sqrt(i) 之间的每个数,检查 i 是否能被整除。如果能被整除,则 i 不是质数;否则,i 是质数。
  2. 优化判断质数的方法以提高效率
    • 使用埃拉托斯特尼筛法(Sieve of Eratosthenes)来标记非质数,从而减少判断次数。
    • 初始化一个布尔数组 is_prime,大小为 n,初始值为 True。将 is_prime[0]is_prime[1] 设为 False(因为 0 和 1 不是质数)。
    • 从 2 开始,将每个质数的倍数标记为 False
③ 流程图

在这里插入图片描述

④ 代码实现
class Solution(object):
    def countPrimes(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n < 2:
            return 0
        
        is_prime = [True] * n
        is_prime[0] = is_prime[1] = False
        
        for i in range(2, int(n**0.5) + 1):
            if is_prime[i]:
                for j in range(i*i, n, i):
                    is_prime[j] = False
        
        return sum(is_prime)

# 调用测试
solution = Solution()
print(solution.countPrimes(10))  # 输出: 4 (2, 3, 5, 7)

执行通过!

3. 统计平方和三元组的数目

1925. 统计平方和三元组的数目 - 力扣(LeetCode)

① 问题描述

给定一个整数 n,统计所有满足以下条件的三元组 (a, b, c) 的数量:

  • a, b, c 都是小于等于 n 的正整数。
  • a^2 + b^2 = c^2
② 解题思路
  1. 枚举区间内的每一对数,判断其平方和是否为完全平方数
    • 对于每一对 (a, b)(从 1 到 n),计算 a^2 + b^2
    • 判断 a^2 + b^2 是否为完全平方数:计算 sqrt(a^2 + b^2),并检查其平方是否等于 a^2 + b^2
  2. 优化枚举范围以提高效率
    • 由于 c 必须小于等于 n,因此 ab 的枚举范围可以缩小到 sqrt(n) 以内。
③ 流程图

在这里插入图片描述

④ 代码实现
import math

class Solution(object):
    def countTriples(self, n):
        """
        :type n: int
        :rtype: int
        """
        count = 0
        
        for a in range(1, n + 1):
            for b in range(a, n + 1):
                c_squared = a**2 + b**2
                c = int(math.sqrt(c_squared))
                if c <= n and c**2 == c_squared:
                    if a == b:
                        count += 1  # (a, b, c) 和 (b, a, c) 是同一个三元组
                    else:
                        count += 2  # (a, b, c) 和 (b, a, c) 是两个不同的三元组
        
        return count

运行通过!

4. 统计公因子数目

2427. 公因子的数目

① 问题描述

给定两个正整数 a a a b b b

要求:返回 a a a b b b 的公因子数目。

说明

  • 公因子:如果 x x x 可以同时整除 a a a b b b,则认为 x x x a a a b b b 的一个公因子。
  • 1 ≤ a , b ≤ 1000 1 \le a, b \le 1000 1a,b1000

示例

  • 示例 1:
输入:a = 12, b = 6
输出:4
解释:126 的公因子是 1236
  • 示例 2:
输入:a = 25, b = 30
输出:2
解释:2530 的公因子是 15
② 解题思路
  1. 枚举法
    • 对于每个可能的因子 x x x(从 1 到 min(a, b)),检查 x x x 是否能同时整除 a a a b b b
    • 如果 x x x 能同时整除 a a a b b b,则 x x x a a a b b b 的一个公因子。
  2. 优化
    • 由于 x x x 的最大值为 min(a, b),因此枚举范围可以缩小到 min(a, b)。
③ 流程图

在这里插入图片描述

④ 代码实现
class Solution(object):
    def commonFactors(self, a, b):
        """
        :type a: int
        :type b: int
        :rtype: int
        """
        count = 0
        for x in range(1, min(a, b) + 1):
            if a % x == 0 and b % x == 0:
                count += 1
        return count

运行通过!


5. 和为s的连续正数序列

剑指 Offer 57 - II. 和为s的连续正数序列

① 问题描述

给定一个正整数 target

要求:输出所有和为 target 的连续正整数序列(至少含有两个数)。序列中的数字由小到大排列,不同序列按照首个数字从小到大排列。

说明

  • 1 ≤ t a r g e t ≤ 1 0 5 1 \le target \le 10^5 1target105

示例

  • 示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
  • 示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
② 解题思路
  1. 滑动窗口法
    • 使用两个指针 leftright 表示当前窗口的左右边界。
    • 计算当前窗口内数字的和 sum
    • 如果 sum 等于 target,则记录当前窗口的序列。
    • 如果 sum 小于 target,则右移 right 指针扩大窗口。
    • 如果 sum 大于 target,则右移 left 指针缩小窗口。
  2. 优化
    • 由于序列至少包含两个数,因此 left 的最大值为 target // 2
③ 流程图

在这里插入图片描述

④ 代码实现
class Solution(object):
    def fileCombination(self, target):
        """
        :type target: int
        :rtype: List[List[int]]
        """
        result = []
        left, right = 1, 2
        
        while left < right:
            sum = (left + right) * (right - left + 1) // 2
            if sum == target:
                result.append(list(range(left, right + 1)))
                left += 1
            elif sum < target:
                right += 1
            else:
                left += 1
        
        return result

运行通过!


6. 统计圆内格点数目

2249. 统计圆内格点数目

① 问题描述

给定一个二维整数数组 circles。其中 circles[i] = [xi, yi, ri] 表示网格上圆心为 (xi, yi) 且半径为 ri 的第 $ i $ 个圆。

要求:返回出现在至少一个圆内的格点数目。

说明

  • 格点:指的是整数坐标对应的点。

  • 圆周上的点也被视为出现在圆内的点。

  • 1 ≤ c i r c l e s . l e n g t h ≤ 200 1 \le circles.length \le 200 1circles.length200

  • c i r c l e s [ i ] . l e n g t h = = 3 circles[i].length == 3 circles[i].length==3

  • 1 ≤ x i , y i ≤ 100 1 \le xi, yi \le 100 1xi,yi100

  • 1 ≤ r i ≤ m i n ( x i , y i ) 1 \le ri \le min(xi, yi) 1rimin(xi,yi)
    示例

  • 示例 1:

输入:circles = [[2,2,1]]
输出:5
解释:
给定的圆如上图所示。
出现在圆内的格点为 (1, 2)(2, 1)(2, 2)(2, 3)(3, 2),在图中用绿色标识。
像 (1, 1)(1, 3) 这样用红色标识的点,并未出现在圆内。
因此,出现在至少一个圆内的格点数目是 5
  • 示例 2:

输入:circles = [[2,2,2],[3,4,1]]
输出:16
解释:
给定的圆如上图所示。
共有 16 个格点出现在至少一个圆内。
其中部分点的坐标是 (0, 2)(2, 0)(2, 4)(3, 2)(4, 4)
② 解题思路
  1. 枚举法
    • 对于每个圆,枚举其范围内的所有格点。
    • 使用圆的方程 (x - xi)^2 + (y - yi)^2 <= ri^2 判断格点是否在圆内。
    • 使用集合存储所有在圆内的格点,避免重复计数。
  2. 优化
    • 由于圆的半径最大为 100,因此格点的范围可以从 -100200
③ 流程图

在这里插入图片描述

④ 代码实现
class Solution(object):
    def countLatticePoints(self, circles):
        """
        :type circles: List[List[int]]
        :rtype: int
        """
        lattice_points = set()
        
        for circle in circles:
            xi, yi, ri = circle
            for x in range(xi - ri, xi + ri + 1):
                for y in range(yi - ri, yi + ri + 1):
                    if (x - xi) ** 2 + (y - yi) ** 2 <= ri ** 2:
                        lattice_points.add((x, y))
        
        return len(lattice_points)

运行通过!


四、总结

枚举算法虽然在大规模问题中效率较低,但在小规模问题和解空间有限的情况下,它是一种简单且有效的解决方案。通过本文的学习,希望读者能够掌握枚举算法的基本思想和应用方法,并在实际问题中灵活运用。

在下一篇文章中,我们将介绍递归算法与分治算法。递归算法通过将问题分解为更小的子问题来解决,而分治算法则通过将问题分解为独立的子问题并分别解决,最后合并结果。这两种算法在解决复杂问题时具有重要的应用价值。敬请期待!


相关链接

  • 项目地址:LeetCode-CookBook
  • 相关文档:专栏地址
  • 作者主页:GISer Liu-CSDN博客

thank_watch

如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.

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

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

相关文章

记录小数点

记录data frame小数点后面省略掉0的问题 iloc得到的series .to_list() 0被省略掉 to_list() 可能会将浮点数转换为默认格式。先将数据转换为字符串以保留格式 df_2708.iloc[2,:].apply(lambda x: f{x:.3f}).to_list()自定义保留小数点后几位 def formatter(value):return &q…

【工作流集成】springboot+vue工作流审批系统(实际源码)

前言 activiti工作流引擎项目&#xff0c;企业erp、oa、hr、crm等企事业办公系统轻松落地&#xff0c;一套完整并且实际运用在多套项目中的案例&#xff0c;满足日常业务流程审批需求。 一、项目形式 springbootvueactiviti集成了activiti在线编辑器&#xff0c;流行的前后端…

Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 垃圾回收算法

文章目录 垃圾回收机制垃圾判断算法引用计数法可达性分析算法虚拟机栈中的引用&#xff08;方法的参数、局部变量等&#xff09;本地方法栈中 JNI 的引用类静态变量运行时常量池中的常量 垃圾收集算法Mark-Sweep&#xff08;标记-清除&#xff09;算法Copying&#xff08;标记-…

电脑右击没有txt文件

文本文档是一个好工具&#xff0c;小而快&#xff0c;比word快多&#xff0c;一般情况下&#xff0c;记录都会先用txt文本&#xff0c;但是今天发现右击菜单新建里面没有&#xff0c;怎么回事&#xff1f; 这个需要打开注册编辑表修改 一、打开注册编辑表 win R 输入regedi…

JetLinks物联网学习(前后端项目启动)

前后端项目启动 1、后端1.1 pgsql改mysql报错2、elasticSearch7.0版本以上_doc格式取消 2、前端 1、后端 环境准备&#xff1a; 1、window系统7,8&#xff0c;10 。 硬件资源最低要求4c8G&#xff0c;硬盘40G 2、JDK 1.8.0_2xx (需要小版本号大于200) 3、Maven3.6.3 4、Redis …

专题四_位运算( >> , << , , | , ^ )_算法详细总结

目录 位运算 常见位运算总结 1.基础位运算 2.给一个数 n ,确定它的二进制表示中的第 x 位是 0 还是 1 3.运算符的优先级 4.将一个数 n 的二进制表示的第 x 位修改成 1 5.将一个数n的二进制表示的第x位修改成0 6.位图的思想 7.提取一个数&#xff08;n&#xff09;二进…

解决使用阿里云DataV Geo在线地图路径访问403问题

文章目录 1. DataV Geo在线地图路径访问403问题2. 解决方法3. 重启生效 1. DataV Geo在线地图路径访问403问题 最近在写一个省市下钻的demo&#xff0c;用到的是 阿里云DataV Geo在线地图 去动态获取GeoJSON 省市的数据&#xff0c;如下代码 axios.get("https://geo.dat…

Ubuntu24.04 安装opencv4.10

Ubuntu24.04 安装opencv4.10 一、下载OpenCV二、更新系统&#xff0c;安装必要的包1、“E: unable to locate libjasper-dev"的解决方法2、没有公钥&#xff0c;无法验证下列签名 :NO_PUBKEY 的解决方法 三、配置&#xff0c;使用cmake工具1、新建build目录2、在build中&a…

计算机毕业设计 玩具租赁系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

智能 Uber 发票 PDF 合并工具

在现代商务出行中&#xff0c;尤其是在跨国出差中&#xff0c;处理和整合大量 Uber 发票已成为一项不小的挑战。手动整理和合并这些发票不仅耗时&#xff0c;还容易出错。作为开发者&#xff0c;为什么不开发一个自动化工具&#xff0c;将这些任务交给代码来完成呢&#xff1f;…

【AI学习笔记】初学机器学习西瓜书概要记录(一)机器学习基础知识篇

初学机器学习西瓜书的概要记录&#xff08;一&#xff09;机器学习基础知识篇(已完结) 初学机器学习西瓜书的概要记录&#xff08;二&#xff09;常用的机器学习方法篇(待更) 初学机器学习西瓜书的概要记录&#xff08;三&#xff09;进阶知识篇(待更) 文字公式撰写不易&#x…

基于代理的分布式身份管理方案

目的是使用分布式的联合计算分发去替换掉区块链中原有的类第三方可信中心的证书机制&#xff0c;更加去中心化。 GS-TBK Group Signatures with Time-bound Keys. CS-TBK 算法 Complete subtree With Time-bound Keys&#xff0c;该算法是用来辅助检测用户的签名是否有效&…

新手学习Python第十天-新手笔记(速学)

一、特殊方法和特殊属性 1.1 特殊属性 __dict__:获得类对象或实例对象所绑定的所有属性和方法的字典 1.2 特殊方法&#xff1a; 1.2.1 .__len__:通过重写__len__()方法&#xff0c;让内置函数len()的参数可以是自定义类型 长度 1.2.2 __add__():通过重写__add__()方法&…

ICMP

目录 1. 帧格式2. ICMPv4消息类型(Type = 0,Code = 0)回送应答 /(Type = 8,Code = 0)回送请求(Type = 3)目标不可达(Type = 5,Code = 1)重定向(Type = 11)ICMP超时(Type = 12)参数3. ICMPv6消息类型回见TCP/IP 对ICMP协议作介绍 ICMP(Internet Control Messag…

HTTP中的Cookie与Session

一、背景 HTTP协议是无状态无连接的。 无状态&#xff1a;服务器不会保存客户端历史请求记录&#xff0c;每一次请求都是全新的。 无连接&#xff1a;服务器应答后关闭连接&#xff0c;每次请求都是独立的。 无状态就导致服务器不认识每一个请求的客户端是否登陆过。 这时…

TCP并发服务器的实现

一请求一线程 问题 当客户端数量较多时&#xff0c;使用单独线程为每个客户端处理请求可能导致系统资源的消耗过大和性能瓶颈。 资源消耗&#xff1a; 线程创建和管理开销&#xff1a;每个线程都有其创建和销毁的开销&#xff0c;特别是在高并发环境中&#xff0c;这种开销…

计算机三级网络技术总结(一)

RPR环中每一个节点都执行SRP公平算法IEEE 802.11a和g将传输速率提高到54Mbps一个BGP发言人与其他自治系统中的BGP发言人要交换路由信息就要先建立TCP连接在一个区域内的路由器数一般不超过200个进入接口配置模式&#xff1a;Router(config)#interface <接口名> 封装ppp协…

CentOS上使用Mosquitto实现Mqtt主题消息发布和订阅mqtt主题消息连同时间戳记录到文件

场景 CentOS上使用rpm离线安装Mosquitto(Linux上Mqtt协议调试工具)附资源下载&#xff1a; CentOS上使用rpm离线安装Mosquitto(Linux上Mqtt协议调试工具)附资源下载-CSDN博客 上面介绍了mosquitto的离线安装。 如果业务场景中需要订阅某mqtt主题的消息并将收到消息的时间以…

婚礼弹幕上墙阳光正好,爱意正浓,打造一场出圈的唯美婚礼!

原文地址 婚礼现场的弹幕功能可以给整个场景增添温暖和喜庆的氛围。通过手机发送祝福&#xff0c;让亲友可以即时将祝福传达给新人&#xff0c;同时这些祝福以弹幕的形式在大屏幕上滚动展示&#xff0c;增加了现场互动的乐趣。墙上新闻搭配的功能则更加抢眼&#xff0c;不仅可…

idea插件推荐之Cool Request

Cool Request是一款基于IDEA的HTTP调试工具&#xff0c;可以看成是轻量版的postman&#xff0c;它会自动扫描项目代码中所有API路径&#xff0c;按项目分组管理。一个类被定义为Controller且其中的方法被RequestMapping或者XXXMapping注解标注以后就会被扫描到。 对应方法左侧会…