优惠券使用规则引擎来计算优惠 (drools)

电商的促销花样越来越多,规则也也越来越复杂,因此,规则的频繁变更可能会带来频繁的版本开发上线,因此,业务希望能够快速上线,这就要求产品能够做到不修改代码快速上线。

平心而论,优惠券目前的几种玩法已经比较固定,通常都是通用券,折扣券,满减券,满赠券,即使不用规则引擎,大部分优惠券的设计都能够支撑业务侧的需求。对于业务侧的一些比较复杂的规则, 例如叠加规则,互斥规则,通常也是在优惠券可配置的一部分,在优惠券的价格计算中,已经实现了互斥,叠加。

其实,优惠券的计算逻辑非常复杂,尤其是可以使用多张优惠券的情况下,还要考虑不同级别的优惠券,在规则引擎中去实现,还是非常麻烦的。此外,由于 drools 的表达能力只能是 when-then 的方式, 并没有实现完整的编程语言的范式,因此,drools 脚本中很难实现复杂的业务逻辑。

我们还对 groovy 脚本进行了调研,在下一篇文章中,我们用 groovy 来实现优惠券的业务逻辑,在优惠券的场景中,能够做到比 drools 更加灵活。

规则引擎

规则引擎的核心包括两部分:

  1. 规则脚本;
  2. 规则脚本的编译,解释执行;

通常,规则脚本都是独立的语言实现,大部分规则引擎都是使用 java 的开源库 antlr 。antlr 是开源的语法解析器,规则脚本语法虽然简单,但也是一门独立的语言,因此,语法解析,词法解析是 必须要有的,此外,大部分规则引擎都可以做到和 JVM 相互调用,这部分的处理应该还是比较复杂的,有兴趣的可以研究下源代码。

drools 规则引擎

drools 规则引擎主要是应用于风控、反欺诈、智能营销、网点监控、智能核保、业务流自动化等场景中,核心是将业务的逻辑代码由 java 代码移到 drools 脚本,如果需要修改业务逻辑,只需要修改 drools 脚本,而不需要修改后台代码。

通常在实际中,我们把脚本保存在数据库中,大部分时候,不需要修改 drools 脚本。如果业务逻辑发生变化,可以通过修改 drools 脚本,然后 java 代码重新从数据库中 load 脚本,这样,就实现了

通过将业务逻辑代码与后台代码的分离,做到了可以随时修改

一个 drools 规则引擎的基本流程是:

rule rule001
when
	条件
then
	执行结果
end

drools 有几个重要的概念,分别是:

Facts

drools 中的 Facts,可以简单的理解为输入

Working memory

working memory 可以简单的理解为 drools 的运行环境

LHS RHS

LHS:条件部分,即 When

RHS:结果部分,即 then

与 java 的交互

drools 的强大之处在于,可以和 java 深度结合,引用 java 的代码,调用 java 的方法。规则在执行的过程中,经常需要与 java 交互,传递参数,判断条件,更新结果等。

KieServices, kieSession, KieContainer, KieFileSystem, KieModule

  • KieServices: kie 整体的入口,可以用来创建 Container,resource,fileSystem 等
  • KieContainer:KieContainer 就是一个 KieBase 的容器,通过 KieContainer 来获取具体的 KieSession
  • KieFileSystem:Kie 的虚拟文件系统,包括资源和组织结构,drools 脚本可以通过 KieFileSystem 来加载
  • KieModule:是一个包含了多个 kiebase 定义的容器。
  • KieRepository:是一个 KieModule 的仓库,包含了所有的 KieModule 描述,用一个 ReleaseId 做区分

概念很多,很难理解,我想这也是为什么很多人说 drools 很重的原因吧。

java 使用流程

其实,我们暂时不用关心这么多宏观的概念,先从 hello world 搞起。

通常,java 的使用流程是:

  1. 获取 kieSession;
  2. 将变量插入 kieSession 中
  3. 调用 kieSession.fireAllRules()

假设我们把 drools 脚本放在 resource/rules 目录下,获取 kieSession 的代码如下:

    private static Resource[] getRuleFiles() throws IOException {
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        return resourcePatternResolver.getResources("classpath*:rules/"  + "**/*.drl");
    }

    private static KieSession getSession() throws Exception {
        KieServices kieServices = KieServices.Factory.get();
        KieFileSystem kfs = kieServices.newKieFileSystem();

        for (Resource file : getRuleFiles()) {
            log.info("rule file: " + file.getFilename());
            try {
                kfs.write(ResourceFactory.newClassPathResource("rules/" + file.getFilename(), "UTF-8"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
        Results results = kieBuilder.getResults();
        if (results.hasMessages(Message.Level.ERROR)) {
            for (Message msg : results.getMessages()) {
                log.error("drools script error info : " + msg.getText());
            }
            throw new Exception("drools script error");
        }
        return kieServices.newKieContainer(KieServices.Factory.get().getRepository().getDefaultReleaseId()).newKieSession();
	}

执行 rule 的代码:

        KieSession kieSession = getSession();
        kieSession.insert(order);
        kieSession.insert(coupon);
        kieSession.insert(result);
        int hit = kieSession.fireAllRules(); // hit 是所有规则被命中的规则数

代码讲解

代码基于 spring boot,该项目仅为演示项目,因此,并未涉及数据库部分,在实际中可以细化这部分实现。

代码已开源:http://github.com/guotie/drools

核心流程

优惠券的核心在于计算价格的接口,也就是常说的询价接口。

因此,我们写了这么几个 drools 脚本:

  • 折扣类优惠计算脚本
  • 满减类优惠计算脚本
  • 满赠类优惠计算脚本
  • 支付类优惠计算脚本
  • 其他

例如,折扣类优惠计算脚本的内容如下:

package com.mall.coupon.drools.rules;

// 折扣型

import com.mall.coupon.drools.model.Coupon
import com.mall.coupon.drools.model.Order
import com.mall.coupon.drools.model.OrderItem
import com.mall.coupon.drools.model.EnquiryResult

global com.mall.coupon.drools.service.CouponBatchService couponBatchService
global com.mall.coupon.drools.service.UserCouponService userCouponService
//global com.mall.coupon.drools.service.UserCouponService userCouponService
global com.mall.coupon.drools.service.UserService userService

// 折扣类优惠券

// order 对整个订单打折
rule "rule-discount-order"
when
    $result: EnquiryResult()
    $order: Order()
    $coupon: Coupon(couponType == "5" && subCouponType == "1" &&
        (minBuyAmount == 0 || $order.totalAmount >= minBuyAmount))
then
    System.out.println("命中 discount-order");
    $result.setTotalDiscount($order.getTotalAmount() * $coupon.getNominal() / 100);
end


// sku 对特定的sku商品打折
rule "rule-discount-sku"
when
    $item: OrderItem()
    $result: EnquiryResult()
    $coupon: Coupon(couponType == "5" && subCouponType == "2" &&
        (minBuyAmount == 0 || $item.totalAmount >= minBuyAmount) &&
        couponBatchService.skuUsable($coupon.getCouponBatchCode(), $item.getProductSkuId()))
then
    System.out.println("coupon code: " + $coupon.getCouponBatchCode());
    System.out.println("couponBatchService: " + couponBatchService);
    System.out.println("命中 discount-sku");
    $result.setTotalDiscount($item.getTotalAmount() * (100 - $coupon.getNominal()) / 100);
end

总结

如果我们需要新增一种优惠券,那么我们只需要新增该类型优惠券的 drools 脚本,测试无误后,让后台代码重新加载即可,也就实现了业务规则的快速部署。

本文来自博客园,作者:IT随笔,转载请注明原文链接:http://www.cnblogs.com/binyue/p/17428268.html

本文转载于网络 如有侵权请联系删除

相关文章

  • Mysql怎样控制replace替换的次数?

    我想把“ABC是ABC”替换成“123是ABC”,也就是找出第一个ABC替换成123,MYSQL命令应该怎么写?UPDATEdataSETbody=REPLACE(body,‘ABC’,‘123’);我用这个命令时会把所有ABC都替换成123,不知道怎么控制替换次数,请高人指教。hemu780924大哥的代码虽然能用,但是有个致命的缺陷, 比如"123是ABC",如果想找出XYZ并替换成OPQ,因为在"123是ABC"找不到XYZ,然后命令就会在"123是ABC"前面插入XYZ,这个不是我想要的啊!复制updatetable1setbody= concat( SUBSTRING(body,1,position('ABC'inbody)-1), '123', substring(body,position('ABC'inbody)+length('ABC')))wherebodylike'%ABC%' 这里替换第一次的ABC,没

  • 「R」使用gt包创建表格入门

    神奇的RStudio,提供了出版级的表格解决方案gt包!安装:remotes::install_github("rstudio/gt") 复制gt包所做的一切都是为了更简单地生成好看的展示表格。展示表格?是的,我们正在尝试将数据表格(如tibbles、data.frame)和你在网页、期刊文章或者杂志中的表格区分开来。后面这种表格可以称为展示表格、汇总表格或者真实的表格。下面是一些网站上的例子:我们可以认为展示表格仅是输出,我们不想要把它作为输入(数据)。其他包含注释、表格元素风格以及文本转换的特征用于更好更清楚地表达主题。使用简单的表格展示gt基础让我们使用一个Rdatasets包中不是很流行的数据集islands:它是一个命名向量。我们使用dplyr根据它准备一个tibble:#获取世界10个最大的大陆 islands_tbl<- dplyr::tibble( name=names(islands), size=islands )%>% dplyr::arrange(desc(size))%>% dplyr::slice(1:10) #显示表

  • 美团外卖Flutter动态化实践

    总第400篇2020年第23篇动态化是Flutter无法避开的话题。本文从Flutter的特点讲起,阐述了美团外卖团队在整个Flutter动态化上探索的心路历程,还有设计理念、核心原理以及业务应用的经验。本文的视角也不局限于框架本身,更多思考了在解决问题的过程中技术团队需要做的事情,希望能对大家有所启发和帮助。 一、前言Flutter跨端技术一经推出便在业内赢得了不错的口碑,它在“多端一致”和“渲染性能”上的优势让其他跨端方案很难比拟。虽然Flutter的成长曲线和未来前景看起来都很好,但不可否认的是,目前Flutter仍处在发展阶段,很多大型互联网企业都无法毫无顾虑地让全线App接入,而其中最主要的顾虑是包大小与动态化。动态化代表着更短的需求上线路径,代表着大大压缩了原始包的大小,从而获得更高的用户下载意向,也代表着更健全的线上质量维护体系。当明白这些意义后,我们也就不难理解,在Flutter的应用与适配趋近完善时,动态化自然就成为了一个无法避开的话题。RN和Weex等成熟技术甚至让大家认为动态化是跨端技术的标配。美团外卖MTFlutter团队从2019年9月开始对动态化进行研究,目

  • Prometheus监控系列-部署篇

    Prometheus是继kubernetes第二个从CNCF中毕业的项目,个人也是非常的喜欢这款通过数据指标发现和预测告警的开源监控平台,官方的话就不多说了,根据官网的介绍有以下功能,但是有些简短的概括了你也不一定知道,所以加了一些个人的白话Prometheus之白话文一段 实现高纬度的数据模型时间序列数据通过metric名和键值对来区分,这里你可以区分多(隔离)环境的监控指标。所有的metrics都可以设置任意的多维标签,可以自定义添加多个,比如这个服务的监控属于哪个团队的。数据模型更随意,不需要刻意设置为以点分隔的字符串;可以对数据模型进行聚合,切割和切片操作;支持双精度浮点类型,标签可以设为全unicode;看到这可能你还是不知道啥意思,那就等接下来用到的时候就恍然大悟了...强大的PromQL语句支持查询语句,可以通过PromSQL进行数值之间的比较可以通过PromSQL内嵌的函数计算指标的变化,比如平均值,增长率等等...出色的可视化个人觉得一点都不咋出色,哈哈,还是结合Grafana使用吧,毕竟人家专业啊~高效的存储可以根据需求设置指标数据的存储天数,也可以持久化存储,比如

  • Spring Cloud异常系列-集成Eureka启动报错

    异常一日志2018-06-2218:01:06.654[main]ERRORcom.sun.jersey.spi.inject.Errors-Thefollowingerrorsandwarningshavebeendetectedwithresourceand/orproviderclasses: SEVERE:Missingdependencyforfield:javax.ws.rs.core.UriInfocom.alibaba.fastjson.support.jaxrs.FastJsonProvider.uriInfo 2018-06-2218:01:06.657[main]ERRORo.s.c.n.e.s.EurekaRegistration-errorgettingCloudEurekaClient org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname'scopedTarget.eurekaClient'definedinclasspathre

  • mysql各种join连接查询

    最近项目用到了几次sqljoin查询来满足银行变态的需求;正好晚上自学时,看到了相关视频,所以记录下相关知识,下次再用时,根据如下图片,便可知道怎么写sql;注意点:在join操作中的on...where... 应该放哪些条件;目前理解on后放2表关联部分;where后放最终数据筛选部分;1.下图为各种join操作的图表解释及sql语句2.自测  建表:分别为分数表(sc),及学生表(student);关系为student.student_id=sc.id;语句如下:DROPTABLEIFEXISTS`student`; CREATETABLE`student`( `id`int(11)NOTNULL, `student_id`int(11)NULLDEFAULTNULL, `name`varchar(255)CHARACTERSETlatin1COLLATElatin1_swedish_ciNULLDEFAULTNULL, PRIMARYKEY(`id`)USINGBTREE )ENGINE=InnoDBCHARACTERSET=latin1COLLATE=latin1_swedis

  • Linux下使用 SSHFS 挂载远程文件系统到本地

    在Windows平台上进行RDP远程桌面时可以将本地驱动器挂载到远程服务器上,在远程桌面时进行文件共享传输 那么Linux下呢,是否有与之相类似的功能,答案是肯定的Linux下借助SSHFS就可以实现将远程主机的文件系统挂到本地的目录进行文件交互传输SSHFS(SecureShellFileSystem)是一个客户端,可以让我们通过SSH文件传输协议(SFTP)挂载远程的文件系统并且在本地机器上和远程的目录和文件进行交互,下面介绍SSHFS的安装与使用 1、yum安装sshfs 先安装EPEL源yuminstallepel-release然后再安装yuminstallsshfs2、sshfs的使用1)先本地主机上创建一个目录作为挂载点,例如mkdir/remote_server 2)sshfs-p8222root@101.132.116.99:/backup_folder/remote_server/将远程主机的/backup_folder目录挂载到本地的/remote_server3)输入远程主机的root密码,成功登录后,cd/remote_server目录就可以看到远程主机该目录

  • TensorFlow实战:验证码识别

    项目地址:https://github.com/kerlomz/captcha_trainer1.前言本项目适用于Python3.6,GPU>=NVIDIAGTX1050Ti,原master分支已经正式切换为CNN+LSTM+CTC的版本了,是时候写一篇新的文章了。长话短说,开门见山,网络上现有的代码以教学研究为主,本项目是为实用主义者定制的,只要基本的环境安装常识,便可很好的训练出期望的模型,重定义几个简单的参数任何人都能使用机器学习技术训练一个商业化成品。最新更新(2019/01/21):如果对于DLL调用感兴趣或是其他语言的TensorFlowAPI感兴趣的移步以下两个项目:1.https://github.com/kerlomz/captchalibraryc2.https://github.com/kerlomz/captchademocsharp笔者选用的时下最为流行的CNN+BLSTM+CTC进行端到端的不定长验证码识别,代码中预留了DenseNet+BLSTM+CTC的选项,可以在配置中直接选用。首先,介绍个大概吧。网格结构predict-CPUpredict-G

  • 使用Maven构建JavaFX程序(HelloWorld示例)

    如何使用Maven构建JavaFX程序呢?下面给出一个简单的示例!本工程包含一个main入口函数类,一个controller类,资源文件包括一个fxml文件,一个css样式文件。 工程目录如下: 利用命令行或者IDE创建一个Maven工程;在源码目录下新建包,新建一个MainApp类。MainApp类继承Application类,是程序的入口函数。在源码目录下新建resources文件夹,然后在该文件夹下面新建Main.fxml文件和application.css文件。FXML文件用于描述界面布局,CSS文件用于设置UI样式。修改maven工程的pom.xml文件,如下:<projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd

  • 浅谈JVM及原理

    1、什么是JVM?JVM,中文名是Java虚拟机,正如它的名字,是一个虚拟机器,来模拟通用的物理机。JVM是一个标准,一套规范,规定了.class文件在其内部运行的相关标准和规范。及其相关的内部构成。比如:所有的JVM都是基于栈结构的运行方式。那么不符合这种要求的,不算是JVM,如Android中所使用的Dalvik虚拟机就不能称作是JAVA虚拟机,因为它是基于寄存器(最新的Android系统据说已经放弃了DalvikVM,而是使用ART)。JVM相关的产品有很多,通常最有名的莫过于现在Oracle公司所有的HotSpot虚拟机。因此,这里讨论的都是HotSpot虚拟机,如果没有特别说明。2、类加载? 类加载,是通过JVM的类加载器从JVM外部以二进制字节流的方式加载到JVM中。但JVM本身有至少三种类加载器:BootStrap(根类加载器,C++实现,加载位于jre/lib/rt.jar)、Extension(扩展类加载器,主要用于加载jre/lib/ext/下的jar)、System(加载classpath环境变量所指定的class);当然还有,自定义的类加载器(用于实现自己的类加

  • 客户数据分析带来巨大利润

    客户关系管理(CRM)项目能产生一些信息,对这些信息加以有效的利用,将提高企业的实力。但是从哪里着手,如何分辨出最有价值的数据以便跟踪呢?  答案涉及到Web分析,这是成长中的一个CRM分支,能帮助你发现客户数据中所包含的秘密。例如,可以确定一个客户访问你网站的频率,与能产生购买的访问频率进行比较。有了这些信息,你们单位就能了解客户需要和喜欢什么东西。当然,发现并利用客户数据中的赢利潜力并非易事,各单位必须根据公司目标和客户群,确定最有效的分析类型。IT经理经常要做分析,因为做报告和整理数据通常是IT部门的任务。本文提供一些建议,帮助你从Web分析中获利,帮助你提高投资回报率(ROI)。CRM的一种新用法根据美国康耐提格州斯坦福德的咨询公司Gartner的报告,许多单位都在利用分析来保持市场竞争优势。Gartner分析人士WalterJanowski说,对分析越来越重视是CRM前进中的自然产物。他说早期采用CRM都是围绕运营问题的,而不是要改善客户的使用感受。随着CRM的成熟,拥有CRM架构的企业已经能够专注于客户身上。Janowski说:“分析和个性化能带你进入更高的层面,在此你可以

  • MySQL数据库实践学习(十三)

    3.5.1.5全局表对于省、市、区/县表tb_areas_provinces,tb_areas_city,tb_areas_region,是属于数据字典表,在多个业务模块中都可能会遇到,可以将其设置为全局表,利于业务操作。修改schema.xml中的逻辑表的配置,修改tb_areas_provinces、tb_areas_city、tb_areas_region三个逻辑表,增加type属性,配置为global,就代表该表是全局表,就会在所涉及到的dataNode中创建给表。对于当前配置来说,也就意味着所有的节点中都有该表了。<tablename="tb_areas_provinces"dataNode="dn1,dn2,dn3"primaryKey="id" type="global"/> <tablename="tb_areas_city"dataNode="dn1,dn2,dn3"primaryKey="id" type=&q

  • 腾讯云云数据库SQLServer删除手动备份api接口

    1.接口描述接口请求域名:sqlserver.tencentcloudapi.com。 本接口(RemoveBackups)可以删除用户手动创建的备份文件。待删除的备份策略可以是实例备份,也可以是多库备份。 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:RemoveBackups。 Version 是 String 公共参数,本接口取值:2018-03-28。 Region 是 String 公共参数,详见产品支持的地域列表。 InstanceId 是 String 实例ID,形如mssql-j8kv137v BackupNames.N 否 ArrayofString 待删除的备份名称,备份名称可通过DescribeBack

  • 找不到工作?!请确认你投简历的姿势对了么?

    感觉每次逛测试群,或者逛贴吧,总会看到一些关于投递简历找工作的消极声音: 找测试工作好难,投了好多简历,都没有HR给我回复... 感觉xx这个城市的招聘都被我投完了,极少的面试,投出去都石沉大海了... 互联网寒冬来了,有跳槽想法的哥们在当前公司好好呆着吧,不然像我一样,等着在家喝西北风吧... 看完我就诧异了,现在不是互联网的“金九银十”么?!按理说找工作的热潮还在持续中啊?! 随意在百度搜索一个二线城市发布的软件测试职位,就这发布职位数量,如果你还在哭着说找不到工作?那么希望你好好看完我接下来的内容,分享下我个人求职路上的一些经验,或许对正在找工作的你有所帮助。     一、投递简历多渠道 1.网上招聘平台 如果想要一家招聘企业录用你,首先你得先让招聘公司HR通过简历认识到你,我们大部分的应聘者主选的投递简历渠道是招聘网站,像主流的智联招聘、前程无忧、boss直聘、拉钩网、猎聘;其实还有大家听得相对来说较少的,例OFweek人才网、中国英才网、58同城。投递简历需要多个平台投递,切忌单个平台,多个平台多个被邀请面试的机会,注意下平台间简历不要重复投递即可。

  • C语言基础语法之指向函数的指针

    指针是C语言的精髓,对于初学者来讲,指针是C语言语法学习中比较难的知识点,而这里面指向函数的指针更是不太容易理解。 下面给大家讲下怎样学习理解C语言中指向函数的指针及编程方法和使用例子。 注意:这是一篇关于C语言编程的基础语法内容,C语言大神请绕过。 基本概念 首先,先不要把指向函数的指针认为太难了,它和普通的指针区别也不是太大,只是定义形式上有所区别。 比如,对于一个指向整形的普通指针,定义形式如下: int*p; 在定义中,指针变量的名称是p,符号“*”说明了p是一个指针,int说明这个指针指向的是整形变量。 那么,如果我们定义一个指向函数的指针,假设变量名称为p,比如它指向这样的一个函数,这个函数需要两个整形参数,其返回值也是整形参数,其定义如下: int(*p)(int,int); 对这个定义分解一下,其中,p是变量的名称,符号“*”说明了p是一个指针,由于这个指针指向的是一个函数,所以在定义中必须体现函数的输入输出参数信息,那么最前面的int指的就是函数的返回值为int类型,后面的(int,int)则定义了该函数需要两个整形的输入参数。另外,必须将“*”与“p”必须用括号写成

  • 8、sort排序中比较函数的几种应用方式

    1、待排序中的元素作数组的下标或map的键值 例题:PAT甲级_1141PATRankingofInstitutions   #include<bits/stdc++.h> usingnamespacestd; constintmaxn=100010; structNode{ intpersonNum=0; intscoreB=0,scoreA=0,scoreT=0; intscore; }; map<string,Node>mp; vector<string>ansSchoolName; boolcmp(stringa,stringb){ if(mp[a].score!=mp[b].score)returnmp[a].score>mp[b].score; elsereturnmp[a].personNum<mp[b].personNum; } intmain(){ intn; scanf("%d",&n); intscore; stringid,schoolName; for(inti=0;i<n;i++

  • pandas 常用统计方法

    统计方法 pandas对象有一些统计方法。它们大部分都属于约简和汇总统计,用于从Series中提取单个值,或从DataFrame的行或列中提取一个Series。 比如DataFrame.mean(axis=0,skipna=True)方法,当数据集中存在NA值时,这些值会被简单跳过,除非整个切片(行或列)全是NA,如果不想这样,则可以通过skipna=False来禁用此功能: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 >>>df     one two a 1.40 NaN b 7.10-4.5 c  NaN NaN d 0.75-1.3   [4rowsx2columns] >>>df.mean() one   3.083333 two  -2.900000 dtyp

  • BFS问题-LeetCode 55、45、5297、127、433、434(BFS)

    【LeetCode#55】跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 示例1: 输入:[2,3,1,1,4] 输出:true 解释:我们可以先跳1步,从位置0到达位置1,然后再从位置1跳3步到达最后一个位置。 classSolution{ public: boolcanJump(vector&nums){ intmaxReach=nums[0]; for(inti=0;i<=maxReach&&i<nums.size();i++){ maxReach=max(maxReach,i+nums[i]); } if(maxReach<nums.size()-1)returnfalse;//最远的元素 elsereturntrue; } }; 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/jump-game 【LeetCode#45】跳跃游戏II 给定一个非负整数数组,你最初位于数组的第一个位

  • 数据库为什么不用红黑树而用B+树

    得分点磁盘IO标准回答首先,红黑树是一种近似平衡二叉树(不完全平衡),结点非黑即红的树,它的树高最高不会超过2*log(n),因此查找的时间复杂度为O(log(n)),无论是增删改查,它的性能都十分稳定;但是,红黑树本质还是二叉树,在数据量非常大时,需要访问+判断的节点数还是会比较多,同时数据是存在磁盘上的,访问需要进行磁盘IO,导致效率较低;而B+树是多叉的,可以有效减少磁盘IO次数;同时B+树增加了叶子结点间的连接,能保证范围查询时找到起点和终点后快速取出需要的数据。加分回答红黑树做索引底层数据结构的缺陷试想一下,以红黑树作为底层数据结构在面对在些表数据动辄数百万数千万的场景时,创建的索引它的树高得有多高?索引从根节点开始查找,而如果我们需要查找的数据在底层的叶子节点上,那么树的高度是多少,就要进行多少次查找,数据存在磁盘上,访问需要进行磁盘IO,这会导致效率过低;那么红黑树作为索引数据结构的弊端即是:树的高度过高导致查询效率变慢。   参考牛客

  • 使用adb shell dumpsys检测Android的Activity任务栈

    谈起Android程序开发,就需要了解其四个主要的部件:Activity、Service、ContentProvider、 BroadcastReceiver。而其中Activity是唯一直接控制程序界面呈现,直面用户操作的部件(当然BrowadCastReceiver也能通过桌面控件(AppWidgets)来呈现有限的操作界面)。Android对于Activity有严格的生命周期控制,以限制开发者在适当的回调函数里的放上合适的代码。对于多个Activity的转换,Android也有非常好的管理和流畅的切换,对此Android还引入了任务栈(TaskStack)的概念,这个概念对于Android设备上得返回按键有极其重要的联系。 (大部分文档都将其表述为TasksandBackStack,但从官方文档的描述来看,Android的相对于Activity讲到的Task都视为一个存放Activities的Stack,所以将其称为TaskStack也不为过。) 在AndroidManifest中申明所要用到的Activity时可以设置不同的launchMode来得到不同的Activi

  • uni-app实现图片和视频上传功能

    使用uni-app实现点击上传,既可以上传视频,有可以上传图片,图片预览,删除图片和视频功能,最终效果如下。uni-app里面没有提供同时上传视频和图片这个插件,只能靠自己手写,      1.页面布局 通过uni-app提供的标签,进行页面布局,这里就不多讲了,uni-app提供的有这个案例,可以直接把他们的样式拷贝过来修改一下就行。 <viewclass="uni-uploader-body"> <viewclass="uni-uploader__files"> <!--图片--> <blockv-for="(image,index)inimageList":key="index"> <viewclass="uni-uploader__file"> <viewclass="iconiconfonticon-cuo"@tap="delect(index)"></view> <imageclass="uni-uploader__img":src="image":d

相关推荐

推荐阅读