算法初级杂谈

本文档的主要目的是:本接口设计规范(IDS)的目的是详细描述VAP和VA引擎之间的软件接口。
VAP提供了2种方式生成VA引擎到VAP上: 1.通过VA Plugin 2.通过VA提供的接口
VAP与不同的VA供应商集成,允许 通过标准化的API 使用他们自己的 analytics
VAP有2个集成点:1.VA Plugin SDK 2.VA网关提供的接口

VA Plugin:一个VA Plugin 代表一个VA引擎 每一个VA plugin 通过一个唯一的APP ID进行定义,还有一个 PLugin name. APP ID的前缀是供应商的ID

VA Plugin是一个共享的库,它实现了Simple Analytic Interface,VA插件可以包含VA引擎的实现,
也可以作为一个适配器,将VA处理委托给VA供应商控制的一些外部子系统。

VA Plugin 是由C++实现的。
VA插件的基本功能是处理输入数据流,并为每个输入流生成一个输出数据流。每个数据流是一个数据帧序列,
而VA插件将按数据帧执行数据处理——每个输入数据帧有一个输出数据帧。

                             c++ interface 

VAP和VA Plugin之间的通信: VAP <-----------------> VA PLugin

VA Plugin将由VA Executable或VA PLugin server 执行,这两者都是默认VA网关的组成部分。

VA Plugin可以在与VA Executable相同的进程中本地执行
VA Plugin可以由VA Plugin Server在远程位置执行,其功能公开为微服务
VA Plugin为这两种方案公开的API是相同的
VA Executable和VA Plugin Server统称为VA Framework

VA Plugin 文件目录结构:
/acv_plugin_info.yaml the Plugin information file
/lib VA Plugin 共享库和依赖的共享库
/data 可选的 任何数据文件

VA Plugin Package:是一个.tar.gz的文件类型,包含了上述所有的文件。

在VA Framework中,有analytic和instance的概念。每个VA Plugin包含一个Analytic。对数据流进行分析的应用称为instance。

当VA插件作为服务执行时,VA插件服务器将提前启动分析。然后VA插件可以在其生命周期中处理任意数量的数据流,其中每个数据流由数据消息序列组成)。
每个数据流都是一个具有自己唯一标识符的实例。实例可能在不同的时间被启动和停止,并且VA插件必须能够同时处理多个实例

VA Plugin典型的生命周期如下:
1.VA框架请求对VA插件进行初始化。在初始化期间,VA插件向VA框架注册它的分析。
2.VA框架请求VA插件创建分析
3.VA框架要求分析的初始化和设置,在过程中提供分析范围的选项
4.每当VA过程框架有一个实例:
a.框架请求VA插件实例进行设置,提供特定选项。
b.VA框架发送输入数据流到VA插件,一次一个数据消息。
c.VA插件以输出数据流的形式将输出发送回VA框架,一次发送一条数据消息。通常,VA插件输出一个或多个数据消息来响应从VA框架接收到的一个或多个输入数据消息。
d.当到达数据流的末尾时,VA框架请求VA插件执行
5.VA框架请求VA插件销毁分析

Simple analytic interface:
VA Framework将通过 Simple Analytic Interface与VA Plugin通信,VA Plugin must implements these :Simple Analytic Interface

Data Stream 和Data Message
Data Stream 是一系列 Data Message,组织成了 Data Frame, Date Frame 可以有任意的数据格式
每个Data Message 都有以下的相关元素:Type, nam,e Frame index, Frame time.

Memory Management :
分配消息内存的一方就是取消分配消息内存的一方。分配消息内存的一方也必须提供一个销毁函数,这是一个回收消息内存的回调函数。
数据消息必须与它的销毁功能一起传递。使用数据消息的最后一方必须调用伴随的销毁函数以使其内存被释放。
数据消息使用的内存必须通过调用它的销毁函数来释放。不能通过调用c++删除程序来释放它

Manageing unserialized Data Message:
为了方便管理VA Plugin实现中的数据消息,VA Plugin SDK提供了acv:: SDK::PMessage类,它是一个唯一的指针,
指向google::protobuf::Message的子类,带有一个销毁函数作为自定义删除器:

Quick Start Guide:
创建一个 VA Plugin的推荐方法是 使用Python 脚本

Simple Analytic Interface:
在使用Simple Analytic Interface 时,消息的序列化和反序列化已经由VA Plugin SDK管理,因此插件的实现者不需要处理序列化问题。
此外,Simple Analytic Interface的实现者不需要处理哨兵消息

在Simple Analytic Interface中,VA供应商必须实现两个c++类SSimpleAnalyticImpl和SSimpleInstanceImpl。实现其中的方法。

Options descriptors:
VA插件接受分析范围的选项和特定于实例的选项。VA框架可以对分析程序进行函数调用,以获得VA插件所接受选项的信息。该信息以选项描述符的形式出现,
每个描述符提供关于一个选项的信息。 说白了就是命令行参数

License Management:

VAP支持需要这种功能的VA插件的许可证管理。对于这样一个VA插件,VAP管理提供给VAP的许可证池。
许可证是每个实例的,并且是可重用的。也就是说,当实例启动时,VAP从池中为实例的运行分配一个许可证。
当实例停止时,许可证被返回到池中,可以分配给另一个实例。
换句话说,一个VA插件许可池的大小限制了该VA插件在任何时候可以执行的实例总数。

以上参考线程池原理

以下类型的许可证密钥是支持的:
None
String
File

Inputs to VA Plugin:
一些VA插件需要用户指定的输入才能正常工作. command Line 的形式

Regions: 使用–regions选项指定一个或多个区域的集合
Lines: :使用–lines选项指定一个或多个行的集合
Binary Mask: 使用–mask选项指定一个或多个二进制掩码的集合
Model: 一些VA算法,如人脸检测,通常需要一个或多个模型文件形式的模型 --model 来指定model文件的路径
Configration file: 和model一样的语义 – config_file来指定路径

Event Interval(事件间隔)
一些VA用例需要VA插件来持续产生输出事件消息,比如持续监测人物的数量

这样的VA插件应该接受可选的特定于实例的–event_interval选项(command Line)

Visualization Images(可视化图像)
为了协助(辅助,协助)在VA Plugin 的开发和优化,通常是VA Plugin 生产和输出一个或多个命名为每个输入视频帧可视化图像.这些可视化图像是特定于VA插件的

GPU Selection:
执行VA插件的机器包含多个gpu,如果VA插件使用GPU并允许VAP直接使用哪个GPU,那么它应该接受可选的分析范围选项–gpu_id:

variables:
VA Framework支持以下变量,这允许VA Plugin获得关于其环境的额外信息:

Pipeline of VA Plugins (Advanced)

 VAP支持在管道架构中链接多个VA插件.

Analytic Pipeline Plugin :
对管道架构的支持是通过Analytic Pipeline Plugin提供的,它是VA Framework的一部分。Analytic Pipeline Plugin本身就是一个VA Plugin ,
可以作为一个instance与VA Executable启动,
也可以作为一个服务与VA Plugin server启动。Analytic Pipeline Plugin的副本将始终部署在VAP中。 VAP的用户不允许在VAP中添加或修改这个VA插件。

Pipeline Configration file:
管道的结构是通过管道配置文件描述的,该文件采用YAML格式,文件名扩展名为”.yaml”或“.yml”

Deliverables(可交付成果):
一个供应商希望提供一个管道VA插件必须提供下列事项:
• One VA Plugin per plugin node in the pipeline.
• One Pipeline Configuration File.

今日工作内容: 看VAP的文档,文档内容基本看完了,后面一部分主要都是具体的数据结构接口实现定义,
大致的看了,没有很细看,将前面的概念介绍内容梳理了一遍,做了一个简单的总结,但是还有一些内容不是能够很清楚的理解。
结合了VAP的文档上次对于benchmark的理解有了更进一步的了解,对benchmark的任务目标更加清楚了。

  1. 本篇文章主要讲的是 VAP和VA Engin之间软件接口

  2. VAP提供了2种方法去集成VA Engin 到VAP:
    a.第一种是通过VA Plugin。
    b.第二种是通过VA 提供的接口。

  3. VAP集成不同的VA提供者提供的VA,允许他们通过标准的接口去使用他们自己的实现。 我们为什么需要一个adapter和converter的原因。 adapter为了适配不同厂商提供的VA Plugin,converter为了处理不同厂家进行VA 之后的输出结果进行统一格式。

  4. 这里有2个集成点到VAP:
    a.第一种是:VA Plugin SDK: 这是通过使用官方插件SDK打包VA算法的集成。这些实现的插件包变成了可以通过默认的VA网关动态安装到VAP上的应用程序。
    b.第二种是:VA Gateway提供的接口:这是直接集成到作为外部网关的主平台。根据外部网关提供的内容,功能可能会受到限制。因此,此集成不能保证具有与VAP默认网关相同的完整功能集。

  5. VA Plugin:
    a.一个VA Plugin代表的就是一个 VA Engin
    b.每一个VA Plugin 通过一个唯一的APP ID识别,还有一个人类可读的Plugin Name. APP ID是一个前缀为唯一供应商ID的字符串,它是由VA供应商自行选择的.
    c.VA Plugin是一个共享库(.so文件),它实现了简单分析接口。VA插件可以包含VA引擎的实现,也可以作为一个适配器,将VA处理委托给VA供应商控制的一些外部子系统。
    d.VA Plugin必须用c++编程语言实现,并使用支持c++ 11标准或更新版本的编译器构建。
    e.VA Plugin的基本功能是处理输入数据流,并为每个输入流生成一个输出数据流。
    f.VA Plugin 和VAP之间的通信是通过c++ 接口实现的。
    g.VA Plugin 将由VA可执行文件或VA插件服务器执行,这两者都是默认VA网关的组成部分。

      VA插件可以在与VA可执行文件相同的进程中本地执行,这种方式VA Executable直接消费Video资源文件,并产生输出结果。
        VA插件也可以由VA插件服务器在远程位置执行,其功能公开为微服务。这种方式通过客户端将数据帧发送给VA Plugin  Server 
        VA Plugin 为这两种方案公开的API是相同的。
      h.VA Executable和VA Plugin服务器统称为VA框架。VA可执行文件和VA插件服务器将与VA插件SDK一起提供
    

6.文件目录结构:
从VA供应商的角度来看,有一些应用程序目录,各种VA插件将被安装在其中。对于每个VA插件,必须将VA插件及其相关数据文件安装到App目录中
目录如下:
/acv_plugin_info.yaml 定义了Plugin 信息的文件
/lib VA Plugin共享的库和它依赖的共享库
/data 这个文件是可选的,存放数据文件的目录

  1. 部署VA Plugin 到VAP,VA Plugin 必须打成一个.tar.gz的包,包含上述的文件。最后生成的VA 插件包被上传到VAP中,然后VAP将会把VA 插件包部署到符合VA 插件信息文件的服务器上

  2. 在VA框架中,有一个Analytic和Instance的概念。每个VA Plugin包含一个Analytic。对数据流进行分析的应用称为Instance。

  3. 在一个Aanlytic的生命周期内,可以并发的执行多个Instance

GPI SDK包括用于实现提供者客户机的接口,提供者客户机本质上是一个适配器,用于将调用转换为外部网关可以接受的格式。
提供者客户机实现主要包括关于提供者工厂(VaGatewayProviderFactory)和客户机(VaGatewayProviderClient)的指定信息。

VaGatewayProviderFactory(Interface) --> ProviderFactory
BaseProviderClient(abstract) --> VaGatewayProviderClient

1.client: 我们可以通过以下获取到 Client:
private ACVClient client;

public BaseAcvAgent() {
	VaConfig vaConfig = VamApplication.applicationContext.getBean(VaConfig.class);
	this.client = new ACVClient(vaConfig.getServiceHost(), vaConfig.getServicePort());
}

然后通过:Client.getXXClient获取到具体的Client,然后通过GRPC方式调用ACV Gateway的方法。

2.ACV Gateway主要划分以下几个模块: Analytic Management Bundle Management Instance Management Service Management
License Management
File Store Management General

Analytic Management: VA,首先我们需要有 vA 文件,通过Analytic Management 我们可以对分析插件包进行管理,对分析包进行CRUD操作。

Instance Management: 管理 ACV 可执行文件。提供管理ACV可执行文件的执行的功能,例如启动和停止实例,以及运行实例的分析输出流。
运行的实例指的是ACV可执行文件在一个输入视频流上的执行。 VA在 ACV Executable上的一次执行。

License Management : 为每个需要许可证管理的分析插件管理许可证池,例如从许可证池中添加或删除许可证,以及分配给运行实例的许可证列表。

File Store Management : 供管理文件存储集合的功能,包括添加或删除文件存储、从单个文件存储中添加或删除单个目录和文件,
以及在启动实例或服务时授予特定文件存储读写访问权。这个文件存储集合存储在ACV服务外部的文件系统目录中,例如网络文件系统或共享驱动器。

Bundle Management : 提供管理分析包的功能,例如添加或删除分析包,以及启动包服务。
addBundle
removeBundle
startBundleService
stopBundleService

General : 关于ACV服务的一般信息。

Service Management : 提供功能来管理ACV插件服务器的执行,如启动和停止插件服务,启动和停止每个服务的实例,并调用一个服务来处理一个数据帧(图片)。
每个实例引用一个单独的输入数据流。
startService
stopService
startServiceInstance
stopServiceInstance
callService

提供功能来管理ACV插件服务器的执行,如启动和停止插件服务,启动和停止每个服务的实例,并调用一个服务来处理一个数据帧。在这个上下文中,每个实例引用一个单独的输入数据流。

给我一个VA 如何去跑:
1.验证VA
2.上传到 系统 addAnalytic()
3.启动Service startService
4.启动instance

if(是bundle){
startBundleService();
startBundleInstance();
getBundleStatus(); //是否启动成功

Object b=getBundleStatus();   //是否跑完这个bundle
if(b==跑完了){
    
}

}if(是VA){
startInstance()
}



今日工作内容:上午过了以下ACVgateway的内容
下午搭建了rabbitmq的环境,其中遇到了一些问题,花了一些时间都顺利解决了。
fastDFS的搭建过程比较复杂,目前还在继续搭建中。
以下是搭建rabbitmq的步骤:
rabbitmq的安装:

  1. 先安装一些库 不安装这些库 好像没办法安装erlang ,这个不确定
  2. 安装erlang apt-get install erlang-nox
  3. 安装rabbitmq apt-get install rabbitmq-server
    service rabbitmq-server start # 启动
    service rabbitmq-server stop # 停止
    service rabbitmq-server restart # 重启
    service rabbitmq-server status # 显示rabbitmq的状态
  4. 添加rabbitmq的配置文件 rabbitmq.config,在里面添加: [{rabbit, [{loopback_users, []}]}]. //注意这个点
    cd /etc/rabbitmq/
    vi rabbitmq.config
  5. rabbitmq-plugins enable rabbitmq_management # 启用可视化插件
  6. service rabbitmq-server restart # 重启
  7. 浏览器输入192.168.3.185:15672 username:guest password:guest 登录即可

MQ地址: 192.168.3.185:15672 guest/guest

eat^tsotofu

/etc/fasfdfs

/home/node/benchmarkfile

今日工作内容:总结了ACV Gateway的内容。看了GPI的介绍,只知道它可以用于将调用转换为外部网关可以接受的格式,是什么意思理解不了,下面给的接口也不知道啥意 思,确实感觉这一部分内容有点难以理解。还研究了一点堆。

今日工作内容:搭建FastDFS的环境,其中遇到了很多的问题,总算是磕磕绊绊的搭建成功了。以下是搭建过程记录

fastdfs 搭建记录:
版本:ubuntu 16.04
fasfdfs-6.06

1.安装git
fastdfs依赖libfastcommon ,需要从github克隆到本地安装,因此需要先安装git
apt-get install git
2.克隆libfastcommon库:
libfastcommon的源在项目: https://github.com/happyfish100/libfastcommon,需要使用git克隆到本地安装。
git clone https://github.com/happyfish100/libfastcommon.git

3.安装libfastcommon:
进入 libfasfcommon目录,依次执行脚本:
./make.sh
./make.sh install

4.设置环境变量和软连接:
在/usr/lib64 目录下依次执行如下命令:
export LD_LIBRARY_PATH=/usr/lib64/
ln -s /usr/lib/libfastcommon.so /usr/local/lib/libfastcommon.so

5.下载,解压,并安装fastdfs:
下载地址:https://github.com/happyfish100/fastdfs/releases
下载完成后通过SFTP 上传到linux。
在/etc下创建目录: mkdir fasfdfs, 将fastdfs的压缩包复制到该目录下: cp fastdfs-6.06.tar.gz /etc/fasfdfs
解压fastdfs包: tar xzf fastdfs-6.06.tar.gz

进入解压的目录依次执行:
./make.sh
./make.sh install 

6.修改配置文件
在默认安装路径:/etc/fdfs下有三个配置文件
client.conf.sample
storage.conf.sample
tracker.conf.sample
将以上三个配置文件的名称去掉后面的sample,改为:
client.conf
storage.conf
tracker.conf

 对上述三个文件进行配置:
 vi tracker.conf,  修改 tracker.conf 文件中的日志存放路径 和 tracker server HTTP端口号:

 # the base path to store data and log files
 base_path=/etc/fastdfs/log   ## 注意,这个路径是自定义的,文件路径需要手动创建,否则后面可能会报 路径不存在的错误。下同。
 # HTTP port on this tracker server
 http.server_port=8090

 vi storage.conf   修改storage.conf配置文件:
 group_name=group1
 store_path0=/etc/fastdfs/storage0
 base_path=/etc/fastdfs/log
 tracker_server=192.168.3.185:22122
 http.server_port=8888


 vi client.conf  修改client.conf:
 base_path=/etc/fastdfs/log
 tracker_server=192.168.3.185:22122
 http.tracker_server_port=8888
 #include http.conf        注意,#include http.conf 这句,原配置文件中有2个#,删掉一个。


 最后,修改 http.conf 文件。http.conf 文件在解压目录的conf目录下,里面有个默认图片路径。
  vi http.conf:
  http.anti_steal.token_check_fail=/home/fastdfs/image

7.启动服务:
依次执行如下命令:
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf

8.测试上传:
fdfs_test /etc/fdfs/client.conf upload 1.jpg

至此:fastdfs配置成功

今日工作内容:在springboot中集成了fastdfs,并写了fastdfs的common工具类.
在这期间遇到了一个问题:加入fastdfs的依赖之后会和spring的logback冲突,产生了依赖冲突。
解决办法:在fastdfs的依赖中排除自身的logback依赖。
具体做法如下:
未解决的情况:

com.github.tobato
fastdfs-client
1.26.1-RELEASE

已经解决的情况:

com.github.tobato
fastdfs-client
1.26.1-RELEASE


ch.qos.logback
logback-classic



虽然解决的办法很简单,只是加了几行代码,但是毕竟我也是第一次遇到这种问题,查了很多博客文章,解决办法都是在spring-starter依赖里面排除,试了很多都没有效果,最后慢慢的了解到了依赖冲突的原理,根据maven依赖最短路径原理定位到问题的关键就解决了。收获:虽然只是遇到了一个问题,添加了几行代码解决了,但是解决问题的关键绝对不是添加几行代码,而是要理解为什么会有这个问题,问题产生的原因,以及迅速定位到问题的方法。

安装了 fastdfs后生成的图片路径 需要安装nginx 和 fastdfs-nginx-module 才可以访问

https://github.com/happyfish100/fastdfs-nginx-module.git

今日工作内容:发现了fastdfs上传文件之后,通过浏览器地址没办法访问,后来发现需要安装fastdfs-nginx-module模块,但是发现nginx是源安装的,网上找的文章都是源码包安装的,要安装fastdfs-nginx-module,目前还没有找到具体的方法。现在也不敢随便改nginx的配置,这个问题不清楚会不会对后面的开发造成影响。如果可以的话,我的想法是将源安装的nginx卸载掉,然后使用源码包从新安装。如果不影响后面的业务,那其实也无所谓。

1200+4100+280

–with-cc-opt=’-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2’ --with-ld-opt=’-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now’ --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_v2_module --with-http_sub_module --with-http_xslt_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads --with-ngx_fastdfs_module

   1 4 2 2
     3 8 1

   1 8 0 3
  •    3 0 0
    

   1 5 0 0
     5 0 0 

   2 0 0 0
  •  1 0 0 0 
    

   1 0 0 0 

今日工作内容:解决nginx+fastdfs+fastdfs-nginx-module集成实现文件下载功能。在不修改原来nginx的基础上搭建新的nginx与fastdfs-nginx-module集成。

ngx_http_fastdfs_module

今日工作内容:了解了benchmark的设计,看了设计图。关于ngx_fastdfs_module这块,能尝试的方法都尝试过了,还是没有配置好,一些问题,照着网上说的方法尝试做了,还是会有问题。

今日工作内容:了解benchmark的流程图;研究了堆排序;摩尔投票算法;写了几道算法题。
执行:nvidia-smi
出现以下:
Command ‘nvidia-smi’ not found, but can be installed with:

sudo apt install nvidia-340
sudo apt install nvidia-utils-390

按照文档解决方案 做如下操作:

执行:sudo add-apt-repository ppa:graphics-drivers/ppa
Cannot add PPA: ‘ppa:~graphics-drivers/ubuntu/ppa’.
ERROR: ‘~graphics-drivers’ user or team does not exist.

配置好了代理,仍然还是上述错误
执行: ubuntu-drivers devices 出现了:Command ‘ubuntu-drivers’ not found, but can be installed with:
sudo apt install ubuntu-drivers-common

执行:sudo apt install ubuntu-drivers-common 完成后,再次执行 ubuntu-drivers devices,正常
再次执行:sudo add-apt-repository ppa:graphics-drivers/ppa 还是出现同样的错误

执行sudo apt install nvidia-340
再次执行: sudo add-apt-repository ppa:graphics-drivers/ppa 还是会报以下错误
执行 sudo reboot 会卡住不动了

以上问题没有能够解决,不知道是不是无法安装的ppa:graphics-drivers/ppa,实际不清楚

第二步:执行sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common成功

执行: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 成功

执行: sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable” 成功

执行: sudo apt-get install docker-ce docker-ce-cli containerd.io 成功

执行: sudo curl -L “https://github.com/docker/compose/releases/download/1.26.0/docker-compose-Linux-x86_64” -o /usr/local/bin/docker-compose 成功

执行: sudo chmod +x /usr/local/bin/docker-compose 成功
执行:sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose 成功

执行:docker login https://docker.artifactory.kaisquare.com/
失败 Connection refused

执行:tar -zxvf backend-master-docker-compose.tar.gz 成功

执行:sudo chmod +x init-persistence.sh 成功

执行: ./init-presistence.sh 成功

执行:sudo docker-compose up -d
出现错误:ERROR: Get https://registry-1.docker.io/v2/: dial tcp 18.213.137.78:443: connect: connection refused

执行:docker login https://docker.artifactory.kaisquare.com/
失败 Connection refused

203.126.56.28

今日工作内容: 准备部署脚本。

目前有以下三个问题:
执行:sudo add-apt-repository ppa:graphics-drivers/ppa
出现错误:
Cannot add PPA: ‘ppa:~graphics-drivers/ubuntu/ppa’.
ERROR: ‘~graphics-drivers’ user or team does not exist.
按照文档没能解决,不知道是不是没法安装这个驱动。

执行:docker login https://docker.artifactory.kaisquare.com/
失败 Connection refused

执行:sudo docker-compose up -d
出现错误:ERROR: Get https://registry-1.docker.io/v2/: dial tcp 18.213.137.78:443: connect: connection refused

test.sh
#! /bin/bash

Update index of apt

sudo apt-get update

Install dependencies of apt to get HTTPS repository

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

Add GPG key of Docker

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Set a stable version of docker repository

sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable”

Update OS and install docker CE

sudo apt-get update

install docker ce

sudo apt-get install docker-ce docker-ce-cli containerd.io

install docker-compose

sudo -i
curl -L “https://github.com/docker/compose/releases/download/1.26.0/docker-compose- ( u n a m e − s ) − (uname -s)- (unames)(uname -m)” -o /usr/local/bin/docker-compose

su cloud
cd …

Give current user the executive rights on docker-compose

sudo chmod +x /usr/local/bin/docker-compose

Check docker-compose is installed successfully

docker-compose -v

Add docker-compose again

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

login into docker-registry

sudo docker login https://docker.artifactory.kaisquare.com/

Get ‘backend-master-docker-compose.tar.gz’ package from FTP server

tar -zxvf backend-master-docker-compose.tar.gz

into the docker-compose folder

cd cd backend-master-docker-compose/docker-compose/

Grant file execution permission

sudo chmod +x init-persistence.sh

exxcute init-persistence.sh

./init-persistence.sh

Finally execute this command to pull images from docker registry

sudo docker-compose up -d

distribution=$(. /etc/os-release;echo I D ID IDVERSION_ID)

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo -i
apt-get update

To install nvidia-container-toolkit

apt-get install -y nvidia-container-toolkit

To install nvidia-container- runtime

apt-get install -y nvidia-container-runtime

restart docker

systemctl restart docker
cd …

Add or modify /etc/docker/daemon.json as follows:

echo "{
“runtimes”: {
“nvidia”: {
“path”: “/usr/bin/nvidia-container-runtime”,
“runtimeArgs”: []
}
},
“default-runtime”: “nvidia”
}
" > /etc/docker/daemon.json

cd /etc/docker
systemctl restart docker

=========================================================================================================================

#! /bin/bash

Update index of apt

sudo apt-get update

Install dependencies of apt to get HTTPS repository

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

Add GPG key of Docker

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Set a stable version of docker repository

sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable”

Update OS and install docker CE

sudo apt-get update

install docker ce

sudo apt-get install docker-ce docker-ce-cli containerd.io

install docker-compose

sudo -i <<EOF

curl -L “https://github.com/docker/compose/releases/download/1.26.0/docker-compose- ( u n a m e − s ) − (uname -s)- (unames)(uname -m)” -o /usr/local/bin/docker-compose
EOF
su cloud <<EOF
cd …

Give current user the executive rights on docker-compose

sudo chmod +x /usr/local/bin/docker-compose

Check docker-compose is installed successfully

docker-compose -v

su cloud <<EOF
echo “++++++++++++++++++++++++++++++++++++++++++++”
EOF
sudo rm -rf /usr/bin/docker-compose

sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

echo “-------------------------------------------------------------------------------”

login into docker-registry

sudo docker login https://docker.artifactory.kaisquare.com/

Get ‘backend-master-docker-compose.tar.gz’ package from FTP server

tar -zxvf backend-master-docker-compose.tar.gz

into the docker-compose folder

cd backend-master-docker-compose/docker-compose/

Grant file execution permission

sudo chmod +x init-persistence.sh

exxcute init-persistence.sh

./init-persistence.sh

Finally execute this command to pull images from docker registry

sudo docker-compose up -d

在这之前都是正常的此处是分界线===============================================

distribution=$(. /etc/os-release;echo I D ID IDVERSION_ID)

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo -i << EOF
#apt-get update

To install nvidia-container-toolkit

apt-get install -y nvidia-container-toolkit

To install nvidia-container- runtime

apt-get install -y nvidia-container-runtime

restart docker

systemctl restart docker
cd …
EOF

Add or modify /etc/docker/daemon.json as follows:

sudo rm -rf /etc/docker/daemon.json
echo "{
“runtimes”: {
“nvidia”: {
“path”: “/usr/bin/nvidia-container-runtime”,
“runtimeArgs”: []
}
},
“default-runtime”: “nvidia”
}
" > /etc/docker/daemon.json

cd /etc/docker
systemctl restart docker

华丽的分割线==

今日工作内容:写自动化部署的shell脚本,基本完成脚本的功能。

问题:
执行:nvidia-smi
显示:NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
按照文档步骤:
执行: sudo add-apt-repository ppa:graphics-drivers/ppa 正常
执行: sudo apt update 正常
执行: ubuntu-drivers devices 正常
执行: sudo apt install nvidia-340 正常
执行: sudo reboot 正常
再次执行:nvidia-smi
显示:NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

{
“runtimes”: {
“nvidia”: {
“path”: “/usr/bin/nvidia-container-runtime”,
“runtimeArgs”: []
}
},
“default-runtime”: “nvidia”
}

{
“runtimes”: {
“nvidia”: {
“path”: “/usr/bin/nvidia-container-runtime”,
“runtimeArgs”: []
}
},
“default-runtime”: “nvidia”
}

{
“runtimes”: {
“nvidia”: {
“path”: “/usr/bin/nvidia-container-runtime”,
“runtimeArgs”: []
}
},
“default-runtime”: “nvidia”
}

做了一次自动化部署脚本的总结:
几个命令的使用:
apt-get install 从网络上下载安装软件
apt-get update 更新软件源
修改软件源: vi etc/apt/sources.list

使用ssh连接机器:前提是被连接的机器必须要有ssh server
ssh ncs-chengdu-02@192.168.3.74

利用ssh进行文件传输:

1、从服务器上下载文件
scp ncs-chengdu-02@192.168.3.74:/home/ncs-chengdu-02/test.txt /home/cloud

2、上传本地文件到服务器
scp /home/cloud/test.txt ncs-chengdu-02@192.168.3.74:/home/ncs-chengdu-02

上传和下载目录 添加参数 -r
设置全局代理:

vim /etc/profile

add proxy into profile

export http_proxy=http://192.168.3.3:9999
export https_proxy=http://192.168.3.3:9999
export no_proxy=“localhost,127.0.0.1,localaddress,192.168.3.74”

#refresh profile to effective
source /etc/profile

设置docker 代理:

Add docker proxy if docker image repository is not accessible:

$ sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf

Then past the follow configuration to http-proxy.conf.

[Service]

一定不要换行,下面的代码一行写完,千万不要换行

Environment=“HTTP_PROXY=http://192.168.3.3:9999” “HTTPS_PROXY=http://192.168.3.3:9999” “NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com”

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

在编辑shell的时候,往文件里面写json的时候一定要注意双引号要加转义字符:
echo “{
“runtimes”: {
“nvidia”: {
“path”: “/usr/bin/nvidia-container-runtime”,
“runtimeArgs”: []
}
},
“default-runtime”: “nvidia”
}” > /etc/docker/daemon.json

有些时候没办法访问外部网络,但是代理也是配置好的,那么有可能是防火墙的问题:
我们尝试着可以关闭防火墙:

sudo ufw status # 查看防火墙的状态
sudo ufw enable # 开启防火墙

sudo ufw disable # 关闭防火墙

今日工作内容:
完成自动化部署脚本的测试,对这次编写脚本过程做了一个总结:
这次写脚本有3个很重要的错误:

  1. 在root用户下面能够使用 apt-get xx 命令,但是在ncs-chengdu-02用户下面使用 sudo apt-get xxx却一直提示连接不到网络,目前仍然不明白
  2. 在使用shell往文件添加json的时候,使用echo “xxx” > /path/daemo.json,没有使用转义字符\将双引号转义
  3. 安装NVIDIA Driver的时候,执行ubuntu-drivers devices,没有显示信息,不知道为什么,这就是后来产生问题的原因,由于不知道需要安装哪一个版本的nvidia driver,于是安装了一个 nvidia-340,导致后面报了错,后面再次尝试安装了其他的nvidia-driver,还是不行。知道是版本的问题,但是不知道要安装哪一个版本的驱动。最后全部重新从头到尾执行了一遍文档的流程,发现执行:ubuntu-drivers devices,下面有了信息,在nvidia-driver-450 后面显示 recommond(推荐),于是下载了这个驱动,成功解决问题。

关于何袁辉同学提前返校的函
学生姓名: 专业学号: 学生打卡: 造成当前情况的具体原因:
到校具体时间: 学院是否同意:

今日工作内容:熟悉benchmark的前端页面设计,做算法题。

Dataset Management:
folder_name
folder_type
va_type
description
file_name
file_path
create table dataSet(
id INT NOT NULL AUTO_INCREMENT,
createdDate DATETIME,
createdId VARCHAR(255),
lastUpdatedDate DATETIME,
lastUpdatedId VARCHAR(255),
folderName VARCHAR(50) NOT NULL,
folderType VARCHAR(25) NOT NULL,
vaType VARCHAR(25) NOT NULL,
description VARCHAR(100) NOT NULL,
fileName VARCHAR(50) NOT NULL,
filePath VARCHAR(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

MySQL,SpringData JPA,

DataSetRepository:
DataSetEntity findByfolderNameAndvaTyp(String folderType,String vaType);

 DataSetEntity getById(String  id);


 List<DataSetEntity> findAll();


 void deleteById(String  id);

 

 
 void createFolder(String folderName,String folderType,String vaType,String description);



 void uploadDataToFolder(File file,String folderName);



 File downLoadDataSet(String id);

function:

   detailes   parame: id;
              return: DataSet

   delete     parame: id
              return: void

   findAll    parame: null
              return List<DataSet>

   search     parame:folderName,folderType,VAType;
              return:List<DataSet>



   Dowload    parame:  id,   targetPath
              return void

createFolder parame: folderName,folderType,VAType,description
return: void
uploadDataToFolder parame:file ,folderName
return void

http://localhost:8788/dataSetManagement/upLoadDataToFolder?folderName=zs&folderType=ls&vaType=ww&description=desc

dataSetManagement这部分我抽象出了7个http接口,但是我只写了4个,还有createFolder,upLoadDataToFolder,dowload这三个我没有理解到

登录MySql的command:
mysql -u demo -p vam

alter table file add [constraint folderId_id] foreign key(folderId) references dataSet(id);

http://localhost:8788/dataSetManagement/upLoadDataToFolder?folderName=zs222&folderType=ls&vaType=ww&description=desc

./configure --add-module=…/fastdfs-nginx-module-master/src/

/usr/local/nginx3/sbin

http://192.168.3.185:8888/group1/M00/00/00/wKgDuV9i01eAMtmQAAGtVAH3_1c07.jpeg

C:\Users\P1332227\Downloads\backend-master-docker-compose.tar.gz

group1/M00/00/00/wKgDuV9kITaASAbhAAGtVAH3_1c87.jpeg

create table vaFile(
id varchar(255) not null ,
folderId varchar(255) not null,
fileName varhcar(255) not null,
filePath varchar(255) not null,
primary key (id)
)engine=InnoDB default charset=utf8;

create table dataSet(
id INT NOT NULL AUTO_INCREMENT,
createdDate DATETIME,
createdId VARCHAR(255),
lastUpdatedDate DATETIME,
lastUpdatedId VARCHAR(255),
folderName VARCHAR(50) NOT NULL,
folderType VARCHAR(25) NOT NULL,
vaType VARCHAR(25) NOT NULL,
description VARCHAR(100) NOT NULL,
fileName VARCHAR(50) NOT NULL,
filePath VARCHAR(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

今日工作内容:基本完成DataSetManagement代码重构与数据库设计,还剩下downloadFile和downloadFolder这2个功能没有实现。

原子性:
持久性:
一致性:
隔离性:

事务并发造成的问题:
脏读: 读到了别人修改了但未确认提交的数据
不可重复读: 2次读取该数据,这之间数据被修改了。
幻读: 数据记录条数改变了
丢失更新:2个事务都访问到了该数据,后提交的把先提交的数据覆盖了。

read uncommit: 读未提交
read commit: 读已提交 解决脏读
repeatableread: 可重复读 默认 解决可重复度 但是有幻读
serializable: 串行化 解决所有问题,但是性能很低

局部变量表: 存放局部标量
操作数栈: 栈,先进先出,数据计算操作
动态连接: 连接到常量池的符号引用
方法出口: 记录方法出口的字节码指令

对象的内存布局:
对象头: markword和类型指针
实例数据:对象真正存储的有效信息
对齐填充:对象起始地址必须是8的整数倍字节,因此需要填充。

markword:hash码,GC分代年龄,锁状态标志,线程持有的锁,偏向锁线程ID,偏向时间戳。
类型指针:指向类元数据的指针,确定这个对象是哪一个类的实例。

对象访问:本地遍量表中存放的是对象地址。

垃圾收集: 引用计数法(循环引用),GCRoot根(虚拟机栈中引用的对象,方法区中静态属性引用的对象,方法区中常量引用的对象,本地方法栈中引用的对象)

eden----> from <—> to ----> old
Object 复制算法 15岁 清除标记,整理

垃圾收集器:Serial CMS G1
Serial: 单线程,stop-the-word
CMS: 标记清除,最短时间stop-the-word

      1.初始标记      STW   标记GCRoot能直接关联的对象。
      2.并发标记            对GCRoots 溯源的过程
      3.重新标记      STW   修正并发标记区间标记的对象产生的变动
      4.并发清除             

1.CPU敏感,占用一部分线程,导致应用程序变慢,总吞吐量降低
2.无法清除浮动垃圾:由于在并发清理阶段,应用程序还在运行,会产生新的垃圾,只能在下一次垃圾回收进行回收。
3.标记清除会产生内存碎片。

G1: 将堆内存划分为多个regine区域,在每一个regine上实现标记整理算法,在多个regine之间实现复制算法

强软弱虚引用:
强:只要强引用存在,则永远不会被回收
软:还有用但非必须的对象,GC回收之后内存还是不够,才会回收
弱:遇到GC就会被回收
虚:对象被回收时收到一个系统通知。

垃圾回收算法:
清除标记:内存碎片
标记整理:
复制算法:浪费一半的空间,大批对象存活,复制操作效率较低

年轻代:一般对象存活率低,使用复制算法,复制的很少,代价低
老年代:存活率高,没有额外内存分配,使用标记清除或者标记整理

垃圾收集器:

io流:
字节流: 能够处理任意形式的文件
inPutStream : 从磁盘到内存 FileInputStream()
outPutStream: 从内存到磁盘 FileOutputStream()

字符流:只能处理纯文本文件
reader: 从磁盘到内存 FileReader()
writer: 从内存带磁盘 FileWriter()

1.建立关联
2.选择流
3.操作,读取,写入
4.释放资源

fodlder:
视频1,
视频2,
视频3,
。。。
视频n。

/**
	 * 
	 * @description Converts byte binary data to a file
	 * @author yuanhui.he
	 * @param
	 * @return void
	 * @date Sep 25, 2020 3:21:05 PM
	 */
	public void byteToFile(byte[] bfile, String filePath, String fileName) {
		BufferedOutputStream bos = null;
		FileOutputStream fos = null;
		File file = null;
		try {
			File dir = new File(filePath);
			if (!dir.exists() && dir.isDirectory()) {
				dir.mkdirs();
			}
			file = new File(filePath + "\\" + fileName);
			fos = new FileOutputStream(file);
			bos = new BufferedOutputStream(fos);
			bos.write(bfile);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}

	}
/*  
* =========================================================================  
* Copyright 2020 NCS Pte. Ltd. All Rights Reserved  
*  
* This software is confidential and proprietary to NCS Pte. Ltd. You shall  
* use this software only in accordance with the terms of the licence  
* agreement you entered into with NCS.  No aspect or part or all of this  
* software may be reproduced, modified or disclosed without full and  
* direct written authorisation from NCS.  
*  
* NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO  
* REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE  
* SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE  
* FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,  
* MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  
* =========================================================================  
*/

package com.ncs.vitg.benchmarking.common.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.springframework.web.multipart.MultipartFile;

/**
 * @description   
 * @author        yuanhui.he
 * @createDate    Sep 25, 2020 10:30:19 AM
 */
public class FileUtils {
	
	/**
     * MultipartFile 转 File
     *
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file)  {
 
        File toFile = null;
        if (file.equals("") || file.getSize() <= 0) {
            file = null;
        } else {
            InputStream ins = null;
            try {
				ins = file.getInputStream();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            toFile = new File(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            try {
				ins.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        }
        return toFile;
    }
 
    
    
    //获取流文件
    private static void inputStreamToFile(InputStream ins, File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 删除本地临时文件
     * @param file
     */
    public static void delteTempFile(File file) {
    if (file != null) {
        File del = new File(file.toURI());
        del.delete();
    }
}


}

 */
@Configuration
@EnableSwagger2
public class Swagger2 {
	@Bean
    public Docket createRestApi() {
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<Parameter>();
        tokenPar.name("Authorization").description("Token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
        pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.ncs.vitg.benchmarking.vam.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars);
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("benchmark vam API")
                .version("1.0")
                .description("vam Control Server API")
                .build();
    }
}```



```java
在这里插入代码片package com.ncs.vitg.benchmarking.vam.conf;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
    public static final String EXCHANGE_ACV_OUTPUT = "acv-output";
    public static final String QUEUE_ACV_EVENT = "ncs-vitg-event";
    private static final String ROUTINGKEY_ACV_EVENT = "#.event";

    @Bean("queue_event")
    public Queue eventEvent() {
        return new Queue(QUEUE_ACV_EVENT, true);
    }

    @Bean("exchange_output")
    public Exchange exchangeOutPut() {
        return new TopicExchange(EXCHANGE_ACV_OUTPUT);
    }

    @Bean
    public Binding bindEvent(@Qualifier("queue_event") Queue queue, @Qualifier("exchange_output") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_ACV_EVENT).noargs();
    }
}
/*  
* =========================================================================  
* Copyright 2020 NCS Pte. Ltd. All Rights Reserved  
*  
* This software is confidential and proprietary to NCS Pte. Ltd. You shall  
* use this software only in accordance with the terms of the licence  
* agreement you entered into with NCS.  No aspect or part or all of this  
* software may be reproduced, modified or disclosed without full and  
* direct written authorisation from NCS.  
*  
* NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO  
* REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE  
* SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE  
* FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,  
* MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  
* =========================================================================  
*/

package com.ncs.vitg.benchmarking.vam.conf;

import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * @description   
 * @author        yuanhui.he
 * @createDate    Sep 21, 2020 11:06:29 AM
 */

@Configuration
@EnableAsync//开启异步
public class ThreadPoolConfig {
	
	//指定线程池的名称
    @Bean("jobThread")
   
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(4);
        // 设置最大线程数
        executor.setMaxPoolSize(8);
        // 设置队列容量
        executor.setQueueCapacity(100);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("home.bus.logThread-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池

        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

package com.ncs.vitg.product.benchmarking.demo.util;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

/**
 * 
 *
 * Title: WebUtil
 *
 * Description:
 *
 * @author xingfu.wang@ncsi.com.cn
 *
 * @date Jun 18, 2020
 *
 */
public class IpAddressUtil {

	/**
	 * 
	 *
	 * Title: getLocalIP
	 *
	 * Description:
	 * 
	 * @return
	 * @throws UnknownHostException
	 * @throws SocketException
	 *
	 */
	public static String getLocalIP() throws UnknownHostException, SocketException {
		if (isWindowsOS()) {
			return InetAddress.getLocalHost().getHostAddress();
		} else {
			return getLinuxLocalIp();
		}
	}

	/**
	 * 
	 *
	 * Title: isWindowsOS
	 *
	 * Description:
	 * 
	 * @return
	 *
	 */
	public static boolean isWindowsOS() {
		boolean isWindowsOS = false;
		String osName = System.getProperty("os.name");
		if (osName.toLowerCase().indexOf("windows") > -1) {
			isWindowsOS = true;
		}
		return isWindowsOS;
	}

	/**
	 * 
	 *
	 * Title: getLocalHostName
	 *
	 * Description:
	 * 
	 * @return
	 * @throws UnknownHostException
	 *
	 */
	public static String getLocalHostName() throws UnknownHostException {
		return InetAddress.getLocalHost().getHostName();
	}

	/**
	 * 
	 *
	 * Title: getLinuxLocalIp
	 *
	 * Description:
	 * 
	 * @return
	 * @throws SocketException
	 *
	 */
	private static String getLinuxLocalIp() throws SocketException {
		String ip = "";
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
				NetworkInterface intf = en.nextElement();
				String name = intf.getName();
				if (!name.contains("docker") && !name.contains("lo")) {
					for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
						InetAddress inetAddress = enumIpAddr.nextElement();
						if (!inetAddress.isLoopbackAddress()) {
							String ipaddress = inetAddress.getHostAddress().toString();
							if (!ipaddress.contains("::") && !ipaddress.contains("0:0:")
									&& !ipaddress.contains("fe80")) {
								ip = ipaddress;
							}
						}
					}
				}
			}
		} catch (SocketException ex) {
			ip = "127.0.0.1";
			ex.printStackTrace();
		}
		System.out.println("IP:" + ip);
		return ip;
	}

	/**
	 * 
	 *
	 * Title: getIpAddress
	 *
	 * Description: Get IP after proxy.
	 * 
	 * @param request
	 * @return
	 *
	 */
	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

}
package com.ncs.vitg.product.benchmarking.demo.util;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class LocalIpMac {

    /**
     * set system field
     *
     * @author song jian
     * @date Aug 20, 2019 10:05:20 AM
     */
    public static void setSystemField() throws Exception {
        System.setProperty("ip", getIpAddress());
        System.setProperty("mac", getMacAddress());
    }

    /**
     * get local ip address
     *
     * @author song jian
     * @date Aug 20, 2019 10:05:24 AM
     */
    public static String getIpAddress() throws Exception {
        Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
        InetAddress ip = null;
        while (allNetInterfaces.hasMoreElements()) {
            NetworkInterface netInterface = allNetInterfaces.nextElement();
            if (netInterface.isLoopback() || netInterface.isVirtual() || netInterface.isPointToPoint() || !netInterface.isUp()) {
                continue;
            } else {
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    ip = addresses.nextElement();
                    if (ip != null && ip instanceof Inet4Address) {
                        return ip.getHostAddress();
                    }
                }
            }
        }
        return "";
    }

    /**
     * get local mac address
     *
     * @author song jian
     * @date Aug 20, 2019 10:05:27 AM
     */
    public static String getMacAddress() throws Exception {
        Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
        byte[] mac = null;
        while (allNetInterfaces.hasMoreElements()) {
            NetworkInterface netInterface = allNetInterfaces.nextElement();
            if (netInterface.isLoopback() || netInterface.isVirtual() || netInterface.isPointToPoint() || !netInterface.isUp()) {
                continue;
            } else {
                mac = netInterface.getHardwareAddress();
                if (mac != null) {
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < mac.length; i++) {
                        sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? ":" : ""));
                    }
                    if (sb.length() > 0) {
                        return sb.toString().toLowerCase();
                    }
                }
            }
        }
        return "";
    }

}

package com.ncs.vitg.product.benchmarking.demo.conf;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
    public static final String EXCHANGE_ACV_OUTPUT = "acv-output";
    public static final String QUEUE_ACV_EVENT = "ncs-vitg-event";
    private static final String ROUTINGKEY_ACV_EVENT = "#.event.#";

    @Bean("queue_event")
    public Queue eventEvent() {
        return new Queue(QUEUE_ACV_EVENT, true);
    }

    @Bean("exchange_output")
    public Exchange exchangeOutPut() {
        return new TopicExchange(EXCHANGE_ACV_OUTPUT);
    }

    @Bean
    public Binding bindEvent(@Qualifier("queue_event") Queue queue, @Qualifier("exchange_output") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_ACV_EVENT).noargs();
    }
}

package com.ncs.vitg.product.benchmarking.demo.conf;

public class BaseException extends Exception {

    private static final long serialVersionUID = 1L;
    /**
     * The error code must return to frontend
     */
    private Object errorCode;

    /**
     * Frontend will display the message
     */
    private String[] msgs;

    private Integer statusCode;

    public BaseException() {
        super();
    }

    public BaseException(Object errorCode) {
        this.errorCode = errorCode;
    }

    public BaseException(Throwable cause) {
        super(cause);
    }

    public BaseException(Object errorCode, String... msgs) {
        this.errorCode = errorCode;
        this.msgs = msgs;
    }

    public BaseException(Object errorCode, String msg) {
        super(msg);
        this.errorCode = errorCode;
    }

    public BaseException(String message, Throwable cause) {
        super(message, cause);
    }

    public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,
                         Object errorCode) {
        super(message, cause, enableSuppression, writableStackTrace);
        this.errorCode = errorCode;
    }

    public BaseException(int statusCode, String message, Throwable cause) {
        super(message, cause);
        this.statusCode = statusCode;
    }

    public BaseException(Object errorCode, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }

    public BaseException(Object errorCode, int statusCode, Throwable cause) {
        super(cause);
        this.errorCode = errorCode;
        this.statusCode = statusCode;
    }

    public BaseException(Object errorCode, int statusCode, String message, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
        this.statusCode = statusCode;
    }


    public BaseException(int statusCode, String message) {
        super(message);
        this.statusCode = statusCode;
    }

    public Object getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(Object errorCode) {
        this.errorCode = errorCode;
    }

    public String[] getMsgs() {
        return msgs;
    }

    public void setMsgs(String[] msgs) {
        this.msgs = msgs;
    }


    public Integer getStatusCode() {
        return statusCode;
    }


    public void setStatusCode(Integer statusCode) {
        this.statusCode = statusCode;
    }

}

package com.ncs.vitg.product.benchmarking.demo.conf;

import com.ncs.vitg.product.benchmarking.demo.util.PropertyUtil;

public class BaseResponse {

	protected int status = 200; // The response status code, it's mandatory field
	private String message; // The response error message, it's mandatory field

	private static final String MESSAGE_500 = "Internal Error"; // Default error msg for system return code = 500
	private static final String MESSAGE_400 = "Missing input"; // Default error msg for system return code = 400

	/**
	 * Implement the return info body
	 */
	public BaseResponse(int status) {
		this.status = status;
		switch (status) {
		case 400:
			this.message = MESSAGE_400;
			break;
		case 500:
			this.message = MESSAGE_500;
			break;
		default:
			this.message = "Success";
			break;
		}
	}

	public static BaseResponse success() {
		return new BaseResponse(200, "Success");
	}

	public static BaseResponse error() {
		return new BaseResponse(400, "Failed");
	}

	/**
	 * @return the status
	 */
	public int getStatus() {
		return status;
	}

	/**
	 * @param status the status to set
	 */
	public void setStatus(int status) {
		this.status = status;
	}

	/**
	 * @return the message
	 */
	public String getMessage() {
		return message;
	}

	/**
	 * the message to set
	 *
	 * @param message message
	 */
	public void setMessage(String message) {
		this.message = message;
	}

	public BaseResponse(int status, String message) {
		this.status = status;
		this.message = message;
	}

	public BaseResponse(String message) {
		this.message = message;
	}

	public BaseResponse() {
		this.message = "success";
	}

	/**
	 * @description setCodeAndMessage.
	 * @author chenglin.zhang@ncsi.com.cn
	 * @param errorCode error code in message/error_message.properties
	 * @param msg       message
	 * @date 8/2/2019 16:50
	 */
	protected void setCodeAndMessage(String errorCode, Object... msg) {
		String[] splitCodeMsg = PropertyUtil.getFormatProperty(errorCode, msg);
		this.status = Integer.parseInt(splitCodeMsg[0]);
		this.message = splitCodeMsg[1];
	}
}

/*
 * =========================================================================
 * Copyright 2019 NCS Pte. Ltd. All Rights Reserved
 *
 * This software is confidential and proprietary to NCS Pte. Ltd. You shall
 * use this software only in accordance with the terms of the licence
 * agreement you entered into with NCS.  No aspect or part or all of this
 * software may be reproduced, modified or disclosed without full and
 * direct written authorisation from NCS.
 *
 * NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO
 * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE
 * SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE
 * FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 * =========================================================================
 */
package com.ncs.vitg.product.benchmarking.demo.conf;

/**
 * @author chenglin.zhang@ncsi.com.cn
 * @version 1.0
 * @description
 * @createDate 8/2/2019
 */
public class ErrorResponse<T> extends BaseResponse {

    private T data;

    /**
     * @description getData.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      T
     * @date        8/2/2019 18:31
     */
    public T getData() {
        return data;
    }

    /**
     * @description setData.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       data T
     * @date        8/2/2019 18:31
     */
    public void setData(T data) {
        this.data = data;
    }
    /**
     * @description error message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @return      BaseRespone
     * @date        8/2/2019 16:37
     */
    public static BaseResponse error(String errorCode) {
        return error(errorCode, "");
    }

    /**
     * @description error message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @param       msg       message
     * @return      BaseRespone
     * @date        8/2/2019 16:37
     */
    public static BaseResponse error(String errorCode, String msg) {
        return errors(errorCode, msg);
    }

    /**
     * @description errors message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode errorCode
     * @param       msg       Object[]
     * @return      BaseRespone
     * @date        8/8/2019 14:10
     */
    public static BaseResponse errors(String errorCode, Object... msg) {
    	BaseResponse response = new BaseResponse();
        response.setCodeAndMessage(errorCode, msg);
        return response;
    }

    /**
     * @description success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       <T> This is the type parameter
     * @param       data data
     * @return      ErrorResponse
     * @date        8/2/2019 16:37
     */
    public static <T> ErrorResponse<T> data(T data) {
        ErrorResponse<T> res = new ErrorResponse<>();
        res.setData(data);
        return res;
    }


    /**
     * @description msgCode.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @return      ErrorResponse<T>
     * @date        8/2/2019 18:32
     */
    public ErrorResponse<T> msgCode(String errorCode) {
        return msgCode(errorCode, "");
    }

    /**
     * @description msgCode.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @param       msg       message
     * @return      ErrorResponse<T>
     * @date        8/2/2019 18:32
     */
    public ErrorResponse<T> msgCode(String errorCode, String msg) {
        setCodeAndMessage(errorCode, msg);
        return this;
    }    
}

package com.ncs.vitg.product.benchmarking.demo.conf;

public class ObjectRestResponse<T> extends BaseResponse {


    T data;


    boolean rel;

    /**
     * @return : ObjectRestResponse<T>
     * @author : yq
     * @date : Jun 21, 2019 10:55:15 AM
     */
    public static <T> ObjectRestResponse<T> success(T data) {
        ObjectRestResponse<T> response = new ObjectRestResponse<>();
        response.data(data).status(200).msg("Success");
        return response;
    }

   
    public boolean isRel() {
        return rel;
    }

    /**
     * @return the data
     */
    public T getData() {
        return data;
    }

    /**
     * @param data the data to set
     */
    public void setData(T data) {
        this.data = data;
    }

    /**
     * @param rel the rel to set
     */
    public void setRel(boolean rel) {
        this.rel = rel;
    }

    public ObjectRestResponse<T> rel(boolean rel) {
        this.setRel(rel);
        return this;
    }

    public ObjectRestResponse<T> msg(String msg) {
        this.setMessage(msg);
        return this;
    }

    public ObjectRestResponse<T> status(int status) {
        this.setStatus(status);
        return this;
    }

    public ObjectRestResponse<T> data(T data) {
        this.setData(data);
        return this;
    }

}
package com.ncs.vitg.product.benchmarking.demo.conf;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
    public static final String EXCHANGE_ACV_OUTPUT = "acv-output";
    public static final String QUEUE_ACV_EVENT = "ncs-vitg-event";
    private static final String ROUTINGKEY_ACV_EVENT = "#.event.#";

    @Bean("queue_event")
    public Queue eventEvent() {
        return new Queue(QUEUE_ACV_EVENT, true);
    }

    @Bean("exchange_output")
    public Exchange exchangeOutPut() {
        return new TopicExchange(EXCHANGE_ACV_OUTPUT);
    }

    @Bean
    public Binding bindEvent(@Qualifier("queue_event") Queue queue, @Qualifier("exchange_output") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_ACV_EVENT).noargs();
    }
}

package com.ncs.vitg.product.benchmarking.demo.conf;

public class ServiceException extends BaseException {

    private static final long serialVersionUID = 1L;

    public ServiceException() {
    }

    public ServiceException(Object errorCode) {
        super(errorCode);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    public ServiceException(Object errorCode, String message) {
        super(errorCode, message);
    }

    public ServiceException(Object errorCode, String... msgs) {
        super(errorCode, msgs);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    public ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,
                            Object errorCode) {
        super(message, cause, enableSuppression, writableStackTrace, errorCode);
    }


    public ServiceException(int statusCode, String message, Throwable cause) {
        super(statusCode, message, cause);
    }

    public ServiceException(Object errorCode, String message, Throwable cause) {
        super(errorCode, message, cause);
    }

    public ServiceException(Object errorCode, int statusCode, Throwable cause) {
        super(errorCode, statusCode, cause);
    }

    public ServiceException(Object errorCode, int statusCode, String message, Throwable cause) {
        super(errorCode, statusCode, message, cause);
    }

    public ServiceException(int statusCode, String message) {
        super(statusCode, message);
    }

}


/*
 * =========================================================================
 * Copyright 2019 NCS Pte. Ltd. All Rights Reserved
 *
 * This software is confidential and proprietary to NCS Pte. Ltd. You shall
 * use this software only in accordance with the terms of the licence
 * agreement you entered into with NCS.  No aspect or part or all of this
 * software may be reproduced, modified or disclosed without full and
 * direct written authorisation from NCS.
 *
 * NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO
 * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE
 * SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE
 * FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 * =========================================================================
 */
package com.ncs.vitg.product.benchmarking.demo.conf;

/**
 * @description SuccessResponse
 * @author chenglin.zhang@ncsi.com.cn
 * @createDate 8/2/2019
 * @version 1.0
 */
public class SuccessResponse<T> extends BaseResponse {
    private static final String SUCCESS = "SUCCESS";
    private static final String XX_SUCCESS = "XX_SUCCESS";

    private T data;

    /**
     * @description getData.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      T
     * @date        8/2/2019 18:31
     */
    public T getData() {
        return data;
    }

    /**
     * @description setData.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       data T
     * @date        8/2/2019 18:31
     */
    public void setData(T data) {
        this.data = data;
    }

    /**
     * @description success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      BaseResponse
     * @date        8/2/2019 16:37
     */
    public static BaseResponse success() {
        return success(SUCCESS, "");
    }

    /**
     * @description save success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      BaseResponse
     * @date        8/2/2019 16:37
     */
    public static BaseResponse saveSuccess() {
        return success(XX_SUCCESS, "Save");
    }

    /**
     * @description update success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      BaseResponse
     * @date        8/2/2019 16:37
     */
    public static BaseResponse updateSuccess() {
        return success(XX_SUCCESS, "Update");
    }

    /**
     * @description delete success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      BaseResponse
     * @date        8/2/2019 16:37
     */
    public static BaseResponse deleteSuccess() {
        return success(XX_SUCCESS, "Delete");
    }

    /**
     * @description success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @param       msg       message
     * @return      BaseResponse
     * @date        8/2/2019 16:37
     */
    public static BaseResponse success(String errorCode, String msg) {
        BaseResponse response = new BaseResponse();
        response.setCodeAndMessage(errorCode, msg);
        return response;
    }

    /**
     * @description success message.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       <T> This is the type parameter
     * @param       data data
     * @return      BaseResponse
     * @date        8/2/2019 16:37
     */
    public static <T> SuccessResponse<T> data(T data) {
        SuccessResponse<T> res = new SuccessResponse<>();
        res.setData(data);
        return res;
    }

    /**
     * @description msgCode.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @return      SuccessResponse<T>
     * @date        8/2/2019 18:32
     */
    public SuccessResponse<T> msgCode(String errorCode) {
        return msgCode(errorCode, "");
    }

    /**
     * @description msgCode.
     * @author      chenglin.zhang@ncsi.com.cn
     * @param       errorCode error code in message/error_message.properties
     * @param       msg       message
     * @return      SuccessResponse<T>
     * @date        8/2/2019 18:32
     */
    public SuccessResponse<T> msgCode(String errorCode, String msg) {
        setCodeAndMessage(errorCode, msg);
        return this;
    }

    /**
     * @description saveSuccessfully.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      SuccessResponse<T>
     * @date        8/2/2019 18:32
     */
    public SuccessResponse<T> saveSuccessfully() {
        return msgCode(XX_SUCCESS, "Save");
    }

    /**
     * @description deleteSuccessfully.
     * @author      chenglin.zhang@ncsi.com.cn
     * @return      SuccessResponse<T>
     * @date        8/2/2019 18:32
     */
    public SuccessResponse<T> deleteSuccessfully() {
        return msgCode(XX_SUCCESS, "Delete");
    }
}

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.ncs.vitg</groupId>
		<artifactId>benchmark</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>common</artifactId>
	<name>common</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<dependencies>
	
	
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<scope>test</scope>
		</dependency>



		
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>11</source>
					<target>11</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
				<configuration>
					<skipTests>true</skipTests>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.ncs.vitg</groupId>
		<artifactId>benchmark</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>vam</artifactId>
	<name>vam</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<dependencies>
		<dependency>
			<groupId>com.ncs.vitg</groupId>
			<artifactId>common</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>net.jodah</groupId>
			<artifactId>expiringmap</artifactId>
			<version>0.5.9</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-compress</artifactId>
			<version>1.19</version>
		</dependency>
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-inline</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-core</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-stub</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-protobuf</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-netty-shaded</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-api</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-context</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>io.grpc</groupId>
			<artifactId>grpc-protobuf-lite</artifactId>
			<version>1.28.1</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- Add form WangXingFu -->
		<dependency>
			<groupId>org.bytedeco</groupId>
			<artifactId>javacv-platform</artifactId>
			<version>1.5.3</version>
		</dependency>
		<dependency>
			<groupId>org.openpnp</groupId>
			<artifactId>opencv</artifactId>
			<version>4.3.0-2</version>
		</dependency>
		<!-- Add form WangXingFu -->
		<dependency>
			<groupId>acv</groupId>
			<artifactId>acv-service-api</artifactId>
			<version>1.1.12</version>
			<scope>system</scope>
			<systemPath>${pom.basedir}/lib/acv-service-api-1.1.12.jar</systemPath>
		</dependency>
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-impl</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-core</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>org.javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.23.1-GA</version>
		</dependency>
		<dependency>
			<groupId>com.google.protobuf</groupId>
			<artifactId>protobuf-java-util</artifactId>
			<version>3.11.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>
		<dependency>
			<groupId>com.rabbitmq</groupId>
			<artifactId>amqp-client</artifactId>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.6</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

		<!-- Add form YuanFeiFei -->
		<dependency>
			<groupId>com.github.tobato</groupId>
			<artifactId>fastdfs-client</artifactId>
			<version>1.26.1-RELEASE</version>
			<exclusions>
				<exclusion>
					<groupId>ch.qos.logback</groupId>
					<artifactId>logback-classic</artifactId>
				</exclusion>
			</exclusions>
		</dependency>




	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>11</source>
					<target>11</target>
				</configuration>
			</plugin>
			<plugin>

				<groupId>org.apache.maven.plugins</groupId>

				<artifactId>maven-jar-plugin</artifactId>

				<configuration>

					<classesDirectory>${project.build.directory}/classes</classesDirectory>

					<archive>
						<manifest>
							<addClasspath>true</addClasspath>
							<classpathPrefix>lib/</classpathPrefix>
							<mainClass>com.ncs.vitg.benchmarking.vam.VamApplication</mainClass>
							<useUniqueVersions>false</useUniqueVersions>
						</manifest>
						<manifestEntries>
							<Class-Path>lib/acv-service-api-1.1.12.jar
							</Class-Path>
						</manifestEntries>

					</archive>

				</configuration>

			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<configuration>
					<outputDirectory>${project.build.directory}/lib</outputDirectory>
					<excludeTransitive>false</excludeTransitive>
					<stripVersion>false</stripVersion>
				</configuration>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<outputDirectory>${project.build.directory}/lib</outputDirectory>
							<excludeTransitive>false</excludeTransitive>
							<stripVersion>false</stripVersion>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.ncs.vitg</groupId>
	<artifactId>benchmark</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.RELEASE</version>
	</parent>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
			<exclusions>
				<exclusion>
					<groupId>*</groupId>
					<artifactId>*</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.yaml</groupId>
			<artifactId>snakeyaml</artifactId>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.47</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.15</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.15</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-slf4j-impl</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		
	
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-compress</artifactId>
    <version>1.18</version>
</dependency>

		
		<!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.25</version><!--$NO-MVN-MAN-VER$-->
</dependency>
		
		

		
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.SR3</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	
	<modules>
		<module>vam</module>
		<module>common</module>
	</modules>
</project>
/*  
* =========================================================================  
* Copyright 2020 NCS Pte. Ltd. All Rights Reserved  
*  
* This software is confidential and proprietary to NCS Pte. Ltd. You shall  
* use this software only in accordance with the terms of the licence  
* agreement you entered into with NCS.  No aspect or part or all of this  
* software may be reproduced, modified or disclosed without full and  
* direct written authorisation from NCS.  
*  
* NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO  
* REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE  
* SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE  
* FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,  
* MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  
* =========================================================================  
*/

package pointOffer;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;

import javax.management.Query;

/**
 * @description
 * @author yuanhui.he
 * @createDate Sep 10, 2020 4:11:29 PM
 */
public class Solution {

	// 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。
	public String reverseLeftWords(String s, int n) {
		/*
		 * StringBuilder stringBuilder = new StringBuilder(); int x=s.length(); for (int
		 * i = n; i < x + n; i++) { stringBuilder.append(s.charAt(i % x)); }
		 * 
		 * return stringBuilder.toString();
		 */
		return (s + s).substring(n, n + s.length()); // 一行代码解决问题
	}

	// 求二叉树的深度
	public int maxDepth(TreeNode root) {
		if (root == null) {
			return 0;
		}
		return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
	}

	// 返回链表的倒数第k个节点
	public ListNode getKthFromEnd(ListNode head, int k) {
		// 先让快指针走x,然后快指针慢走
		int i = 0;
		ListNode low = head;
		ListNode high = head;
		while (high != null) {
			if (i >= k) {
				low = low.next;
			}
			high = high.next;
			i++;
		}

		// 更加直观 明显
		/*
		 * for(int j=0;j<k;j++) { high=high.next; }
		 * 
		 * while(high!=null) { high=high.next; low=low.next; }
		 */

		return low;
	}

	// 输出二叉树的镜像 借助栈 这个方法效率贼低(力扣时间击败9%)
	public TreeNode mirrorTree(TreeNode root) {
		if (root == null)
			return null;
		Stack<TreeNode> stack = new Stack<TreeNode>();
		stack.add(root);
		while (!stack.isEmpty()) {
			TreeNode node = stack.pop();
			if (node.left != null)
				stack.add(node.left);
			if (node.right != null)
				stack.add(node.right);
			// 左右子树交换 左右子树互为镜像
			TreeNode temp = node.left;
			node.left = node.right;
			node.right = temp;
		}
		return root;
	}

	// 输出二叉树的镜像 递归法
	public TreeNode mirrorTree1(TreeNode root) {

		if (root == null)
			return null;

		// 左右子树互相交换 左子树是右子树的镜像 右子树是左子树的镜像
		TreeNode temp = root.left;
		root.left = mirrorTree(root.right);
		root.right = mirrorTree(temp);

		return root;
	}

	// 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数 说白了就是求出最大的n位数
	public int[] printNumbers(int n) {

		int sum = 9;
		for (int i = 1; i < n; i++) {
			sum = sum * 10 + 9;
		}

		// sum 也可以以下方式求出
		// sum=(int)Math.pow(10, n)-1;

		int[] a = new int[sum];
		for (int i = 1; i <= sum; i++) {
			a[i - 1] = i;
		}
		return a;

	}

	// 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
	public String replaceSpace(String s) {
		char[] chars = s.toCharArray();

		StringBuilder str = new StringBuilder();
		for (int i = 0; i < chars.length; i++) {
			if (chars[i] == ' ') {
				str.append("%20");
			} else {
				str.append(chars[i]);
			}
		}

		return str.toString();
	}

	// 使用双指针 效率较高
	public ListNode reverseList(ListNode head) {
		if (head == null)
			return null;
		ListNode pre = null;
		ListNode curr = head;
		while (curr != null) {

			// 相当于2个数据交换位置,需要临时保存数据
			ListNode temp = curr.next;

			curr.next = pre;
			pre = curr;
			curr = temp;
		}
		return curr;
	}

	// 反转链表 栈 效率很低
	public ListNode reverseList1(ListNode head) {
		if (head == null)
			return null;
		Stack<ListNode> stack = new Stack<ListNode>();

		ListNode p = head;
		while (p != null) {
			stack.add(p);
			p = p.next;
		}

		ListNode re = stack.pop();
		// 这个地方一定要注意,我们必须定义一个节点来保存原始链表的头节点
		// 如果没有这一步操作,那么我们最后返回的就是最后一个链表节点
		ListNode result = re;
		while (!stack.isEmpty()) {
			re.next = stack.pop();
			re = re.next;
		}

		// 因为这个节点就是原始链表的第一个节点 现在这个链表的下一个节点指向的是原来的第二个节点,这个链并没有断;
		// 现在反转后的链表倒数第二个节点的下一个指针指向该元素,如果没有这一步操作,那么就会形成环,比如:1.next==2 2.next==1
		re.next = null;
		return result;
	}

	// 求二叉搜索树的第k大的元素
	// 利用二叉树的性质,二叉树的中序遍历是递增序列,中序便利的倒叙是递减序列,那我们只需要中序遍历二叉搜索树,得到这个递增序列,那么就很简单了
	int count = 0, res = 0; // count:第几个,res:记录结果

	public int kthLargest(TreeNode root, int k) {
		count = k;
		getMiddleSequence(root);
		return res;
	}

	public void getMiddleSequence(TreeNode root) {
		if (root == null || count == 0)
			return;
		getMiddleSequence(root.right); // 右
		if (--count == 0)
			res = root.val; // 根
		getMiddleSequence(root.left); // 左
	}

	
	// 合并2个递增的链表
	public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
		ListNode p = l1, q = l2, listNode = new ListNode(0), curr = listNode;
		while (q != null && p != null) {
			if (q.val < p.val) {
				curr.next = q;
				q = q.next;
			} else {
				curr.next = p;
				p = p.next;
			}
			curr = curr.next;
		}
		curr.next = q == null ? p : q;
		return listNode.next;
	}

	// 统计一个数的二进制中1的个数:
	// x&1:如果x最右边是1,那么结果是1,否则结果是0,那么依次将x右移一位&1,则可以统计出有多少个1
	public int hammingWeight(int n) {
		int count = 0;
		while (n != 0) {
			count += n & 1;
			n >>>= 1;
		}
		return count;
	}

	// 上述方法虽然很好,但是需要遍历每一位
	// 此方法不需要遍历每一位,只要遍历1的个数那么多次
	// 举个例子:
	/*
	 * n= 1 0 0 1 0 1 0 1 0 0 1 & n-1= 1 0 0 1 0 1 0 1 0 0 0
	 * ----------------------------------- 1 0 0 1 0 1 0 1 0 0 0 去掉了最右边的1
	 * 那么我们依次做这个操作就可以每次消除一个1,那么最后就能够消除所有的1
	 * 
	 */
	public int hammingWeight1(int n) {
		int count = 0;
		while (n != 0) {
			count++;
			n = n & (n - 1);
		}
		return count;
	}

	// 二叉树的最近公共祖先
	public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
		if (root == null || root == p || root == q)
			return root;
		// 递归左子树
		TreeNode left = lowestCommonAncestor(root.left, p, q);
		// 递归右子树
		TreeNode right = lowestCommonAncestor(root.right, p, q);
		if (left == null)
			return right;
		if (right == null)
			return left;
		return root; // left!=null && right!=null
	}

	// 输入一个正整数 target ,输出所有和为 target 的连续正整数序列
	// 滑动窗口
	public int[][] findContinuousSequence(int target) {
		List<int[]> res = new ArrayList<int[]>();

		int left = 1, right = 1, sum = 0;

		while (left <= target / 2) {
			if (sum < target) {
				sum += right;
				right++;
			} else if (sum > target) {
				sum -= left;
				left++;
			} else {

				int[] a = new int[right - left];
				for (int i = left; i < right; i++) {
					a[i - left] = i;
				}
				res.add(a);
				sum -= left;

				left++;
			}
		}
		return res.toArray(new int[res.size()][]);
	}

	// 二叉搜索树的最近公共祖先 二叉搜索树:左子树的节点都比根节点小,右子树的值都比根节点大
	public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) {
		while (root != null) {
			if (root.val > p.val && root.val > q.val) {
				root = root.left; // 遍历左子树
			} else if (root.val < p.val && root.val < q.val) {
				root = root.right; // 遍历右子树
			} else {
				break;
			}
		}
		return root;
	}

	// 从上到下打印二叉树 说白了就是层次遍历
	public List<List<Integer>> levelOrder(TreeNode root) {
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		Queue<TreeNode> queue = new LinkedList<>();
		if (root != null)
			queue.add(root);
		while (!queue.isEmpty()) {
			List<Integer> temp = new ArrayList<Integer>();
			int size = queue.size(); // 关键点在于这里 二叉树的层次遍历
			for (int i = 0; i < size; i++) {
				TreeNode node = queue.poll();
				temp.add(node.val);
				// 关键点在于这里 二叉树的层次遍历
				if (node.left != null)
					queue.add(node.left);
				if (node.right != null)
					queue.add(node.left);
			}
			result.add(temp);
		}
		return result;
	}

	// 二叉树的中序遍历 递归解法
	public List<Integer> inorderTraversal(TreeNode root) {
		List<Integer> res = new ArrayList<Integer>();
		getMiddleSequence1(root, res);
		return res;

	}

	public void getMiddleSequence1(TreeNode root, List<Integer> res) {
		if (root == null) {
			return;
		}
		getMiddleSequence1(root.left, res);
		res.add(root.val);
		getMiddleSequence1(root.right, res);
	}

	// 使用栈进行中序遍历
	public List<Integer> inorderTraversal1(TreeNode root) {
		List<Integer> res = new ArrayList<Integer>();
		Stack<TreeNode> stk = new Stack<TreeNode>();
		while (root != null || !stk.isEmpty()) {
			while (root != null) {
				stk.push(root);
				root = root.left;
			}
			root = stk.pop();
			res.add(root.val);
			root = root.right;
		}
		return res;
	}

	public List<List<Integer>> levelOrder2(TreeNode root) {
		if (root == null)
			return new ArrayList<List<Integer>>();
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		List<List<Integer>> res = new ArrayList<List<Integer>>();
		queue.add(root);
		while (!queue.isEmpty()) {
			List<Integer> temp = new ArrayList<Integer>();
			int size = queue.size();
			for (int i = 0; i < size; i++) {
				TreeNode node = queue.poll();
				temp.add(node.val);
				if (node.left != null)
					queue.add(node.left);
				if (node.right != null)
					queue.add(node.right);
			}
			res.add(temp);

		}
		return res;
	}

	// 数组中出现次数超过一半的数字 排序,hash表计数法,摩尔投票算法
	// 前2种算法太简单,且效率底下,此处写的是摩尔投票算法,这种算法只能求出超过一半的数,如果数组中可能不存在超过一半的数,那么最后需要验证
	// 求出的数是否满足条件
	public int majorityElement(int[] nums) {
		int count = 0;
		int res = 0;
		for (int i = 0; i < nums.length; i++) {
			if (count == 0)
				res = nums[i];
			count += nums[i] == res ? 1 : -1;
		}
		return res;
	}

	// 在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内,找出任意一个重读的数字。
	// HashMap法, 排序取对应索引法
	// 以上2种都太简单,效率也不高,此处使用原地交换法

	public int findRepeatNumber(int[] nums) {

		// 简单的说就是一个萝卜一个坑,在每一个萝卜进行交换,往自己坑位走的时候发现坑位被占了
		for (int i = 0; i < nums.length; i++) {
			while (nums[i] != i) {
				if (nums[i] == nums[nums[i]]) {
					return nums[i];
				}
				int temp = nums[i];
				nums[i] = nums[temp];
				nums[temp] = temp;
			}
		}
		return -1;
	}

	// 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,则输出任意一对即可。
	// 以下三种方法比较 双指针的效率是最高的

	// 双指针法
	public int[] twoSum(int[] nums, int target) {
		int i = 0, j = nums.length - 1;
		while (i < j) {
			int temp = nums[i] + nums[j];
			if (temp > target)
				j--;
			else if (temp < target)
				i++;
			else {
				return new int[] { nums[i], nums[j] };
			}
		}
		return new int[0];
	}

	// HashMap法
	public int[] twoSum1(int[] nums, int target) {
		Set<Integer> set = new HashSet<Integer>();
		for (int i = 0; i < nums.length; i++) {
			// 一边添加的时候就一边判断,可以减少循环次数 假如:target=9,nums[i]=4的时候,那么只需要nums[i]=5 就可以跳出循环了
			if (set.contains(target - nums[i])) {
				return new int[] { nums[i], target - nums[i] };
			}
			set.add(nums[i]);
		}
		return new int[0];
	}

	// 遍历二分法:
	public int[] twoSum2(int[] nums, int target) {
		for (int i = 0; i < nums.length; i++) {
			// 这个地方为什么是 left=i+1? 因为nums[i] 就是现在正在遍历的那个元素,我们需要二分的区间是它后面的区间
			int left = i + 1, right = nums.length - 1, temp = target - nums[i];
			while (left <= right) {
				int middle = left + (right - left) / 2;
				if (nums[middle] > temp) {
					right = middle - 1;
				} else if (nums[middle] < temp) {
					left = middle + 1;
				} else {
					return new int[] { nums[i], nums[middle] };
				}
			}
		}
		return new int[0];
	}

	// 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

	// 双指针法
	public int[] exchange(int[] nums) {
		int left = 0, right = nums.length - 1;
		// 奇数在前,偶数在后
		while (left < right) {
			// 找到偶数
			while (left < right && nums[left] % 2 != 0) { // nums[left]%2!=0 可以用nums[left]&1==1 替换
				left++;
			}
			// 找到奇数
			while (left < right && nums[right] % 2 == 0) { // nums[right]%2==0 可以用 nums[right]&1==0 替换
				right--;
			}
			// 奇偶交换
			int temp = nums[left];
			nums[left] = nums[right];
			nums[right] = temp;
		}
		return nums;
	}

	// 输入两个链表,找出它们的第一个公共节点。
	// 双指针法
	public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
		ListNode p = headA, q = headB;
		while (p != q) {
			p=p==null?headB:p.next;
			q=q==null?headA:q.next;
		}
		return p;
	}

	public static void main(String[] args) {
		Solution solution = new Solution();
		// String string = solution.reverseLeftWords("abcdefg", 2);
		System.out.println(solution.replaceSpace("We are happy."));
	}

}

/*  
* =========================================================================  
* Copyright 2020 NCS Pte. Ltd. All Rights Reserved  
*  
* This software is confidential and proprietary to NCS Pte. Ltd. You shall  
* use this software only in accordance with the terms of the licence  
* agreement you entered into with NCS.  No aspect or part or all of this  
* software may be reproduced, modified or disclosed without full and  
* direct written authorisation from NCS.  
*  
* NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO  
* REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE  
* SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE  
* FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,  
* MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  
* =========================================================================  
*/

package adpterService;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;

/**
 * @description
 * @author yuanhui.he
 * @createDate Aug 10, 2020 9:22:44 AM
 */
public class Solution {

	/**
	 * 
	 * @description 2020/8/10
	 * @author yuanhui.he
	 * @param
	 * @return int
	 * @date Aug 11, 2020 9:42:16 AM
	 */
	// 找出数组中重复的数据 原地交换
	public int findRepeatNumber(int[] nums) {
		for (int i = 0; i < nums.length; i++) {

			// 持续交换 最后达到 nums[i]==i
			while (nums[i] != i) {
				if (nums[i] == nums[nums[i]]) {
					return nums[i];
				}
				int temp = nums[i];
				nums[i] = nums[nums[i]];
				nums[nums[i]] = temp;
			}
		}
		return -1;
	}

	// 找出数组中重复的数据 使用HashSet
	public int findRepeatNumber1(int[] nums) {
		Set<Integer> set = new HashSet<Integer>();
		for (int i = 0; i < nums.length; i++) {
			if (!set.add(nums[i])) {
				return nums[i];
			}
		}
		return -1;
	}

	// 2数之和
	public int[] twoSum(int[] nums, int target) {
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (int i = 0; i < nums.length; i++) {
			int temp = target - nums[i];
			// 为何可以这么写 因为如果 temp=target-nums[i]存在,那么nums[i]=target-temp一定也存在
			if (map.containsKey(temp)) {
				return new int[] { i, map.get(temp) };
			}
			map.put(nums[i], i);
		}
		return new int[] { -1, -1 };
	}

	// 不含重复字符的最长字串 滑动窗口
	public int lengthOfLongestSubstring(String s) {
		Set<Character> set = new LinkedHashSet<Character>();
		int size = 0;
		char[] cs = s.toCharArray();
		int j = 0;
		int max = 0;
		for (int i = 0; i < cs.length; i++) {
			if (!set.contains(cs[i])) {
				set.add(cs[i]);
				size++;
				max = max > size ? max : size;
			} else {
				while (set.contains(cs[i])) {
					set.remove(cs[j]);
					j++;
					size--;
				}
				set.add(cs[i]);
				size++;
			}
		}
		return max;
	}

	// 连续子数组的最大和
	public int maxSubArray(int[] nums) {
		int n = nums.length;
		int[] dp = new int[n + 1];
		dp[0] = nums[0];
		int max = dp[0];
		for (int i = 1; i < n; i++) {
			if (dp[i - 1] < 0) {
				dp[i] = nums[i];
			} else {
				dp[i] = dp[i - 1] + nums[i];
			}
			max = max > dp[i] ? max : dp[i];
		}
		return max;
	}

	// 二位数组中查找一个数
	public boolean findNumberIn2DArray(int[][] nums, int target) {
		if (nums == null || nums.length == 0 || nums[0].length == 0)
			return false;
		// 行数 列数
		int i = nums.length;
		int j = nums[0].length;

		// 从右上角开始查找
		int row = 0;
		int colunm = j - 1;
		while (row < i && colunm >= 0) {
			if (target == nums[row][colunm])
				return true;
			else if (target > nums[row][colunm])
				row++;
			else
				colunm--;
		}
		return false;
	}

	// 斐波那契数列
	public int fib(int n) {
		if (n == 1)
			return 0;
		if (n == 2)
			return 1;
		int[] dp = new int[n + 1];
		dp[0] = 0;
		dp[1] = 1;
		for (int i = 2; i < n + 1; i++) {
			dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
		}
		return dp[n];
	}

	// 小青蛙跳台阶问题
	public int numWays(int n) {
		if (n == 0 || n == 1)
			return 1;
		if (n == 2)
			return 2;
		int a = 1, b = 2, c = 0;
		for (int i = 3; i <= n; i++) {
			c = (a + b) % 1000000007;
			a = b;
			b = c;
		}
		return c;
	}

	public boolean exist(char[][] board, String word) {
		char[] cs = word.toCharArray();
		for (int i = 0; i < board.length; i++) {
			for (int j = 0; j < board[i].length; j++) {
				if (dfs(board, cs, i, j, 0))
					return true;
			}
		}
		return false;
	}

	public boolean dfs(char[][] board, char[] word, int i, int j, int k) {
		// 剪枝
		if (i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k])
			return false;
		// dfs结束条件
		if (k == word.length - 1)
			return true;
		char temp = board[i][j];
		// 表示该位置已经访问过了 当前的位置在board[i][j] 下一步走之前 需要把当前位置标记为占有状态 当从这个点出发走完 回溯完之后需要将该位置标记为
		// 未占有状态。
		board[i][j] = '/';
		boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i, j + 1, k + 1)
				|| dfs(board, word, i - 1, j, k + 1) || dfs(board, word, i, j - 1, k + 1);
		// 还原
		board[i][j] = temp;
		return res;

	}

	// 最小的k个数
	public int[] getLeastNumbers(int[] arr, int k) {
		if (k == 0)
			return new int[] {};
		// 默认小顶堆 适合用来查找最大的k个数
		Queue<Integer> queue = new PriorityQueue<Integer>(k, (v1, v2) -> (v2 - v1));
		for (int i = 0; i < arr.length; i++) {
			if (queue.size() < k) {
				queue.add(arr[i]);
			} else if (queue.peek() > arr[i]) {
				queue.poll();
				queue.add(arr[i]);
			}
		}
		int[] a = new int[k];
		for (int i = 0; i < a.length; i++) {
			a[i] = queue.poll();
		}
		return a;
	}

	// 以下2个方法的巧妙之处在于 直接将原数组当成了dp数组,空间复杂度降为O(1)
	// 礼物的最大价值
	public int maxValue(int[][] grid) {
		int m = grid.length;
		int n = grid[0].length;
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (j == 0 && i == 0)
					continue;
				else if (j == 0)
					grid[i][j] += grid[i - 1][j];
				else if (i == 0)
					grid[i][j] += grid[i][j - 1];
				else
					grid[i][j] += Math.max(grid[i - 1][j], grid[i][j - 1]);
			}
		}
		return grid[m - 1][n - 1];
	}

	public int maxValue1(int[][] a) {
		// 行
		int m = a.length;
		// 列
		int n = a[0].length;
		// 初始化第一行
		for (int j = 1; j < n; j++) {
			a[0][j] += a[0][j - 1];
		}
		// 初始化第一列
		for (int i = 1; i < m; i++) {
			a[i][0] += a[i - 1][0];
		}
		for (int i = 1; i < m; i++) {
			for (int j = 1; j < n; j++) {
				a[i][j] += Math.max(a[i - 1][j], a[i][j - 1]);
			}
		}
		return a[m - 1][n - 1];
	}

	// 剪绳子
	public int cuttingRope(int n) {
		int[] dp = new int[n + 1];
		dp[0] = 1;
		for (int i = 1; i <= (n + 1) / 2; i++) {
			for (int j = i; j < n + 1; j++) {
				dp[j] = Math.max(dp[j], dp[j - i] * i);
			}
		}
		return dp[n];
	}

	// 机器人的运动范围

	public int movingCount(int m, int n, int k) {
		boolean[][] visited = new boolean[m][n];
		return dfs(m, 0, n, 0, k, visited);
	}

	// 如果是矩阵的话 可以使用改变这个位置的值 使其一定不满足 遍历条件 就省去了 O(n)的空间 变成了O(1)
	public int dfs(int m, int i, int n, int j, int k, boolean[][] visited) {
		if (i < 0 || i > m - 1 || j < 0 || j > n - 1 || !check(i, j, k) || visited[i][j])
			return 0;
		visited[i][j] = true;
		return 1 + dfs(m, i + 1, n, j, k, visited) + dfs(m, i, n, j + 1, k, visited);
	}

	public boolean check(int m, int n, int k) {
		int sum = 0;
		while (m != 0) {
			sum += m % 10;
			m = m / 10;
		}
		while (n != 0) {
			sum += n % 10;
			n = n / 10;
		}
		return sum <= k;
	}

	// 最长不重复子串
	public int lengthOfLongestSubstring1(String s) {
		char[] cs = s.toCharArray();
		int size = 0;
		Set<Character> set = new LinkedHashSet<Character>();
		int j = 0;
		int max = 0;
		for (int i = 0; i < cs.length; i++) {
			if (!set.contains(cs[i])) {
				set.add(cs[i]);
				size++;
			} else {
				// 其实这个删除操作比较耗费性能
				while (set.contains(cs[i])) {
					set.remove(cs[j]);
					j++;
					size--;
				}
				set.add(cs[i]);
				size++;
			}
			max = max > size ? max : size;
		}
		return max;
	}

	/**
	 * 
	 * @description 2020/8/11
	 * @author yuanhui.he
	 * @param
	 * @return int
	 * @date Aug 11, 2020 9:41:51 AM
	 */
	// 最长不重复子串 双指针的滑动窗口 效率更高
	public int lengthOfLongestSubstring2(String s) {
		if (s.length() == 0 || s == null)
			return 0;
		char[] cs = s.toCharArray();
		int size = 0;
		Map<Character, Integer> map = new HashMap<Character, Integer>();
		int index = 0;
		int max = 0;
		int start = -1;
		for (int i = 0; i < cs.length; i++) {
			if (map.containsKey(cs[i])) {
				index = map.get(cs[i]);
				if (index > start)
					start = index;
			}
			map.put(cs[i], i);
			max = Math.max(max, i - start);
		}
		return max;
	}

	// 输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
	public int[] printNumbers(int n) {
		int sum = 0;
		for (int i = 0; i < n; i++) {
			sum += 9 * Math.pow(10, i);
		}
		int[] a = new int[sum];
		for (int i = 0; i < sum; i++) {
			a[i] = i + 1;
		}
		return a;
	}

	LinkedList<String> list = new LinkedList<String>();
	StringBuilder sb = new StringBuilder();

	public String[] permutation(String s) {
		char[] cs = s.toCharArray();
		boolean[] visited = new boolean[cs.length + 1];
		Arrays.sort(cs);
		dfs(0, cs, visited, cs.length);
		return list.toArray(new String[list.size()]);
	}

	public void dfs(int step, char[] cs, boolean[] visited, int n) {
		if (step == n) {
			list.addLast(sb.toString());
			return;
		}
		for (int i = 0; i < n; i++) {
			if (visited[i] || (i > 0 && visited[i - 1] && cs[i] == cs[i - 1])) {
				continue;
			}
			// 将当前元素添加到结果
			sb.append(cs[i]);
			visited[i] = true;
			dfs(step + 1, cs, visited, n);
			// 回溯到未添加进 结果的时候
			sb.deleteCharAt(step);
			visited[i] = false;
		}
		return;

	}

	// 该算法超时间
	public int countDigitOne(int n) {
		int count = 0;
		for (int i = 1; i <= n; i++) {
			count += getCount(i);
		}
		return count;
	}

	public int getCount(int n) {
		int count = 0;
		int sum = 0;
		while (n != 0) {
			sum = n % 10;
			if (sum == 1)
				count++;
			n = n / 10;
		}
		return count;
	}

	// 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
	// 记住:任何一个丑数* 2 3 5都还是丑数
	// 此算法效率也不高 使用了堆排序
	public int nthUglyNumber(int n) {
		int[] a = new int[] { 2, 3, 5 };

		// 默认小顶堆
		Queue<Long> queue = new PriorityQueue<Long>();
		queue.add(1L);
		int count = 0;
		while (!queue.isEmpty()) {
			long cur = queue.poll();
			count++;
			if (count >= n)
				return (int) cur;
			for (int i = 0; i < a.length; i++) {
				if (!queue.contains(cur * a[i])) {
					queue.add(cur * a[i]);
				}
			}
		}
		return -1;
	}

	public void quickSort(int[] a, int low, int high) {
		if (low < high) {
			int index = getIndex(a, low, high);
			quickSort(a, index + 1, high);
			quickSort(a, low, index - 1);
		}
	}

	public int getIndex(int[] arr, int low, int high) {
		// 基准数据
		int tmp = arr[low];
		while (low < high) {
			// 当队尾的元素大于等于基准数据时,向前挪动high指针
			while (low < high && arr[high] >= tmp) {
				high--;
			}
			// 如果队尾元素小于tmp了,需要将其赋值给low
			arr[low] = arr[high];
			// 当队首元素小于等于tmp时,向前挪动low指针
			while (low < high && arr[low] <= tmp) {
				low++;
			}
			// 当队首元素大于tmp时,需要将其赋值给high
			arr[high] = arr[low];

		}
		// 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置
		// 由原理部分可以很清楚的知道low位置的值并不是tmp,所以需要将tmp赋值给arr[low]
		arr[low] = tmp;
		return low; // 返回tmp的正确位置
	}

	List<List<Integer>> ls = new ArrayList<List<Integer>>();
	boolean[] visited;
	int[] a;
	int n;

	public List<List<Integer>> permute(int[] nums) {
		n = nums.length;
		visited = new boolean[n + 1];
		a = new int[n + 1];
		dfs(0, nums);
		return ls;
	}

	public void dfs(int step, int[] nums) {
		if (step == n) {
			List<Integer> l = new ArrayList<Integer>();
			for (int i = 0; i < n; i++) {
				l.add(a[i]);
			}
			ls.add(l);
			return;
		}
		for (int i = 0; i < n; i++) {
			if (!visited[i]) {
				a[step] = nums[i]; // 保存结果
				visited[i] = true;
				dfs(step + 1, nums);
				visited[i] = false;
			}
		}
	}

	// 这是一个模板 要记住
	List<List<Integer>> list3 = new ArrayList<List<Integer>>();
	int[] ans;
	boolean[] visit;
	int n1;

	public List<List<Integer>> permuteUnique(int[] nums) {
		Arrays.sort(nums);
		n1 = nums.length;
		ans = new int[n1];
		visit = new boolean[n1];
		dfs1(0, nums);
		return list3;
	}

	public void dfs1(int step, int[] nums) {

		if (step == n1) {
			List<Integer> list = new ArrayList<Integer>();
			for (int i = 0; i < n1; i++) {
				list.add(ans[i]);
			}
			list3.add(list);
			return;
		}
		for (int i = 0; i < n1; i++) {
			// 为了去重 后一个数字和前一个数字相等的情况下,并且前一个数字已经被访问过了 这种就是就是重复的
			if (visit[i] || (i > 0 && visit[i - 1] && nums[i] == nums[i - 1]))
				continue;
			ans[step] = nums[i];
			visit[i] = true;
			dfs1(step + 1, nums);
			visit[i] = false;
		}
	}

	/**
	 * 
	 * @description 2020/8/12
	 * @author yuanhui.he
	 * @param
	 * @return TreeNode
	 * @date Aug 12, 2020 5:44:49 PM
	 */
	// 通过先序遍历和中序遍历构造出这个二叉树
	public TreeNode buildTree(int[] preorder, int[] inorder) {
		return buildTree(preorder, 0, preorder.length, inorder, 0, inorder.length);
	}

	public TreeNode buildTree(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end) {

		if (p_start == p_end)
			return null; // 递归出口 树为空的

		// 在先序遍历中找到根节点的值 p_star指针就是头节点的索引位置

		int root_val = preorder[p_start];
		// 根节点
		TreeNode root = new TreeNode(root_val);
		// 根节点的索引位置
		int i_root_index = 0;

		// 在中序遍历中找到根节点 这个地方 每一次递归都需要遍历 效率比较低 我们考虑使用一个HashMap将所有的节点数据存进去,那么每次获得根节点的时间复杂度为
		// O(1)
		for (int i = i_start; i < i_end; i++) {
			if (root_val == inorder[i]) {
				// 获取根节点的索引位置
				i_root_index = i;
				break;
			}
		}

		// 获取左子树节点的个数
		int leftNum = i_root_index - i_start;

		// 构造左子树
		root.left = buildTree(preorder, p_start + 1, p_start + 1 + leftNum, inorder, i_start, i_root_index);

		// 构造右子树
		root.right = buildTree(preorder, p_start + 1 + leftNum, p_end, inorder, i_root_index + 1, i_end);
		return root;

	}

	// 优化
	public TreeNode buildTree1(int[] preorder, int[] inorder) {
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (int i = 0; i < inorder.length; i++) {
			map.put(inorder[i], i);
		}
		return buildTree1(preorder, 0, preorder.length, inorder, 0, inorder.length, map);
	}

	public TreeNode buildTree1(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end,
			Map<Integer, Integer> map) {

		if (p_start == p_end)
			return null;

		int root_val = preorder[p_start];

		TreeNode root = new TreeNode(root_val);

		int i_root_index = map.get(root_val);

		int leftNum = i_root_index - i_start;

		root.left = buildTree1(preorder, p_start + 1, p_start + 1 + leftNum, inorder, i_start, i_root_index, map);
		root.right = buildTree1(preorder, p_start + 1 + leftNum, p_end, inorder, i_root_index + 1, i_end, map);

		return root;

	}

	// 螺旋矩阵1 给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

	public int[] spiralOrder(int[][] matrix) {
		if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
			return new int[0];
		}
		int rows = matrix.length, columns = matrix[0].length;
		int[] order = new int[rows * columns];
		int index = 0;
		int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
		while (left <= right && top <= bottom) {
			for (int column = left; column <= right; column++) {
				order[index++] = matrix[top][column];
			}
			for (int row = top + 1; row <= bottom; row++) {
				order[index++] = matrix[row][right];
			}
			//
			if (left < right && top < bottom) {
				for (int column = right - 1; column > left; column--) {
					order[index++] = matrix[bottom][column];
				}
				for (int row = bottom; row > top; row--) {
					order[index++] = matrix[row][left];
				}
			}
			left++;
			right--;
			top++;
			bottom--;
		}
		return order;
	}

	// 螺旋矩阵
	public int[] spiralOrder1(int[][] matrix) {
		if (matrix.length == 0)
			return new int[0];
		int left = 0, right = matrix[0].length - 1;
		int top = 0, bottom = matrix.length - 1;
		int[] a = new int[(right + 1) * (bottom + 1)];
		int index = 0;
		while (true) {
			for (int i = left; i <= right; i++)
				a[index++] = matrix[top][i];
			if (++top > bottom)
				break;

			for (int i = top; i <= bottom; i++)
				a[index++] = matrix[i][right];
			if (--right < left)
				break;

			for (int i = right; i >= left; i--)
				a[index++] = matrix[bottom][i];
			if (--bottom < top)
				break;

			for (int i = bottom; i >= top; i--)
				a[index++] = matrix[i][left];
			if (++left > right)
				break;
		}
		return a;
	}

	public List<Integer> spiralOrder2(int[][] matrix) {
		if (matrix.length == 0 || matrix[0].length == 0)
			return new ArrayList<Integer>();

		List<Integer> list = new ArrayList<Integer>();

		int left = 0, right = matrix[0].length - 1;
		int top = 0, bottom = matrix.length - 1;

		while (true) {
			for (int i = left; i <= right; i++)
				list.add(matrix[top][i]);
			if (++top > bottom)
				break;

			for (int i = top; i <= bottom; i++)
				list.add(matrix[i][right]);
			if (left > --right)
				break;

			for (int i = right; i >= left; i--)
				list.add(matrix[bottom][i]);

			if (top > --bottom)
				break;

			for (int i = bottom; i >= top; i--)
				list.add(matrix[i][left]);
			if (++left > right)
				break;
		}
		return list;

	}

	int[][] t;
	boolean[][] v;
	int count = 0;

	// 从网格的左上角走到右下角有多少种走法
	public int uniquePaths(int m, int n) {
		// m 列 n 行
		int[][] dp = new int[n][m];
		// 左边界
		for (int i = 0; i < m; i++) {
			dp[0][i] = 1;
		}
		for (int i = 0; i < n; i++) {
			dp[i][0] = 1;
		}
		for (int i = 1; i < n; i++) {
			for (int j = 1; j < m; j++) {
				dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
			}
		}
		return dp[n][m];
	}

	/**
	 * 
	 * @description 2020/08/18
	 * @author yuanhui.he
	 * @param
	 * @return boolean
	 * @date Aug 18, 2020 2:27:57 PM
	 */
	// 栈的压入/弹出序列
	public boolean validateStackSequences(int[] pushed, int[] popped) {
		Stack<Integer> stack = new Stack<Integer>(); // 辅助栈
		int i = 0;
		for (Integer index : pushed) {
			stack.push(index);
			while (!stack.isEmpty() && stack.peek() == popped[i]) {
				stack.pop();
				i++;
			}
		}
		return stack.empty();
	}

	// 二叉树的层次遍历 BFS一般借助队列来实现
	public int[] levelOrder(TreeNode root) {
		if (root == null)
			return new int[0];
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		List<TreeNode> list = new ArrayList<TreeNode>();
		while (!queue.isEmpty()) {
			TreeNode node = queue.poll();
			list.add(node);
			if (node.left != null)
				queue.add(node.left);
			if (node.right != null)
				queue.add(node.right);
		}
		int[] a = new int[list.size()];
		for (int i = 0; i < list.size(); i++) {
			a[i] = list.get(i).val;
		}
		return a;
	}

	// 层次打印二叉树 每一层打印一行
	public List<List<Integer>> levelOrder1(TreeNode root) {

		if (root == null)
			return new ArrayList<>();
		List<List<Integer>> result = new ArrayList<>();

		Queue<TreeNode> queue = new LinkedList<TreeNode>();

		queue.add(root);

		while (!queue.isEmpty()) {
			LinkedList<Integer> list = new LinkedList<Integer>();

			int i = queue.size();
			for (; i > 0; i--) {

				TreeNode node = queue.poll();
				list.add(node.val);
				if (node.left != null)
					queue.add(node.left);

				if (node.right != null)
					queue.add(node.right);

			}

			result.add(list);

		}

		return result;

	}

	public List<List<Integer>> levelOrder2(TreeNode root) {
		if (root == null)
			return new ArrayList<>();
		List<List<Integer>> result = new ArrayList<>();
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		queue.add(root);
		int j = 1;
		while (!queue.isEmpty()) {
			LinkedList<Integer> list = new LinkedList<>();
			int i = queue.size();
			for (; i > 0; i--) {
				TreeNode node = queue.poll();
				if (result.size() % 2 == 0) { // 判断奇偶 这个方法是真的牛批
					list.addLast(node.val); // addLast方法 等价于 add方法 从队列左边开始添加,从右边开始出去: 队列
				} else {
					list.addFirst(node.val); // 奇数层的话 会倒置 ,添加到队列头部 从队列右边开始添加,从右边开始出去: 栈
				}
				if (node.left != null)
					queue.add(node.left);
				if (node.right != null)
					queue.add(node.right);
			}
			result.add(list);
		}
		return result;
	}

	// 根据输入的前序遍历和后续遍历的结果 重建该二叉树
	public TreeNode buildTree3(int[] preorder, int[] inorder) {
		if (preorder == null || preorder.length == 0)
			return null;
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		int length = preorder.length;

		for (int i = 0; i < length; i++) {
			map.put(inorder[i], i);
		}
		TreeNode root = helpTreeNode(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, map);
		return root;
	}

	public TreeNode helpTreeNode(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd,
			Map<Integer, Integer> map) {
		if (preStart > preEnd)
			return null;

		// 这个preStart指向的位置就是 先序遍历中 根节点的位置
		int rootVal = preorder[preStart];
		TreeNode root = new TreeNode(rootVal);

		// 我们在中序遍历中找到这个根节点的位置 那么它右边的就是一个右子树 左边的就是一个左子树
		int rootIndex = map.get(rootVal);
		int leftNodes = rootIndex - inStart;

		// 递归构建左子树 右子树0.
		TreeNode left = helpTreeNode(preorder, preStart + 1, preStart + 1 + leftNodes, inorder, inStart, rootIndex,
				map);
		TreeNode right = helpTreeNode(preorder, preStart + 1 + leftNodes, preEnd, inorder, rootIndex + 1, inEnd, map);
		root.left = left;
		root.right = right;
		return root;

	}

	// 找出数组中出现次数超过一半的元素

	// 排序法
	public int getHalfNum1(int[] a) {
		Arrays.sort(a);
		return a[a.length / 2];
	}

	// Hash表法
	public int getHalfNum2(int[] a) {
		Map<Integer, Integer> map = new HashMap<Integer, Integer>();
		for (int i = 0; i < a.length; i++) {
			map.put(a[i], map.getOrDefault(a[i], 0) + 1);
		}
		int num = 0;
		for (Map.Entry<Integer, Integer> map1 : map.entrySet()) {
			if (map1.getValue() > a.length / 2) {
				num = map1.getKey();
				break;
			}
		}
		return num;
	}

	// 摩尔投票法 最优的解法: O(n) O(1)
	public int getHalfNum4(int[] a) {
		int x = 0, vote = 0;
		for (Integer i : a) {
			if (vote == 0)
				x = i;
			vote += i == x ? 1 : -1;
		}
		return x;
	}

	// 求逆波兰表达式的值
	public int evalRPN(String[] tokens) {
		Stack<Integer> stack = new Stack<Integer>();
		Set<String> set = new HashSet<String>();
		set.add("+");
		set.add("-");
		set.add("*");
		set.add("/");
		for (int i = 0; i < tokens.length; i++) {
			if (set.contains(tokens[i])) {
				int x = stack.pop();
				int y = stack.pop();
				switch (tokens[i]) {
				case "+":
					stack.push(y + x);
					break;
				case "-":
					stack.push(y - x);
					break;
				case "*":
					stack.push(y * x);
					break;
				case "/":
					stack.push(y / x);
					break;
				}

			} else {
				stack.push(Integer.parseInt(tokens[i]));
			}
		}

		return stack.pop();

	}

	// 数组的动态和
	public int[] runningSum(int[] nums) {
		for (int i = 1; i < nums.length; i++)
			nums[i] = nums[i - 1] + nums[i];
		return nums;

	}

	// 根据给定的数组构建平衡二叉树,要求树的高度最小
	// 分析 树的高度最小,那么左子树和右子树的元素个数尽量相同 那么使用数组中间的元素作为划分点,分为左子树右子树,然后递归划分
	public TreeNode sortedArrayToBST(int[] nums) {

		return helpBuildTree(nums, 0, nums.length - 1);

	}

	public TreeNode helpBuildTree(int[] a, int low, int high) {
		if (high < low)
			return null;
		int midd = (high - low) / 2 + low;
		TreeNode root = new TreeNode(a[midd]);
		root.left = helpBuildTree(a, low, midd - 1);
		root.right = helpBuildTree(a, midd + 1, high);
		return root;
	}

	// 升序数组a中查找第一个 i=a[i]的元素

	// 一个个查找太费性能 二分查找并不能查到最小的

	// 假如nums[0]=100,假如是升序的,那么num[0]后面的值都不会比100小,所以i如果还是一步步的加,
	// 效率肯不高,我们直接让i从100开始,因为小于100的i肯定是查找不到的。

	public int findMagicIndex(int[] nums) {
		for (int i = 0; i < nums.length; i++) {
			if (nums[i] == i)
				return nums[i];
			if (nums[i] > i + 1) {
				i = nums[i] - 1;
			}
		}
		return -1;
	}

	// 判断一个字符串重排后能否变成第另一个
	public boolean CheckPermutation(String s1, String s2) {
		if (s1.length() != s2.length())
			return false;
		// 使用HashMap统计每个字符的个数
		Map<Character, Integer> map1 = new HashMap<Character, Integer>();
		Map<Character, Integer> map2 = new HashMap<Character, Integer>();
		char[] c1 = s1.toCharArray();
		char[] c2 = s2.toCharArray();
		for (int i = 0; i < s1.length(); i++) {
			map1.put(c1[i], map1.getOrDefault(c1[i], 0) + 1);
			map2.put(c2[i], map2.getOrDefault(c2[i], 0) + 1);
		}
		for (Map.Entry<Character, Integer> map : map1.entrySet()) {
			if (map.getValue() != map2.get(map.getKey()))
				return false;
		}
		return true;
	}

	// 消失的数字
	public int missingNumber(int[] nums) {
		int sum1 = 0;
		int sum2 = 0;
		for (int i = 0; i < nums.length; i++) {
			sum1 += nums[i];
			sum2 += i;
		}
		sum2 += nums.length;
		return sum2 - sum1;
	}
	
	public int missingNumber1(int[] nums) {
		//res=res^x^x
		int res=0;
		for(int i=0;i<nums.length;i++) {
			res=res^i^nums[i];
		}
		return res^nums.length;
	}
	
	
	
	//数组中占比超过一半的元素称之为主要元素。给定一个整数数组,找到它的主要元素。若没有,返回-1。
	//使用摩尔投票算法
	
	//使用简单的摩尔投票算法只能找到数列中出现次数大于一半的元素  对于数组中没有出现超过一半的元素,
	//摩尔算法不能求出出现次数最多的元素,因此我们只能假定数列中出现了超过一半的元素,求出这个元素  然后再验证是否真的出现了一半以上。
	public int majorityElement(int[] nums) {
	    int x=nums[0];
	    int vote=1;
	    for(int i=1;i<nums.length;i++) {
	    	if(vote==0) x=nums[i];
	    	vote+=x==nums[i]?1:-1;
	    }
	    int count=0;
	    for(int i=0;i<nums.length;i++) {
	    	if(x==nums[i]) {
	    		count++;
	    	}
	    }
	    return count>nums.length/2?count:-1;
    }
	
	

	public static void main(String[] args) {

		Solution solution = new Solution();

		
	}

}

/*  
* =========================================================================  
* Copyright 2020 NCS Pte. Ltd. All Rights Reserved  
*  
* This software is confidential and proprietary to NCS Pte. Ltd. You shall  
* use this software only in accordance with the terms of the licence  
* agreement you entered into with NCS.  No aspect or part or all of this  
* software may be reproduced, modified or disclosed without full and  
* direct written authorisation from NCS.  
*  
* NCS SUPPLIES THIS SOFTWARE ON AN AS IS BASIS. NCS MAKES NO  
* REPRESENTATIONS OR WARRANTIES, EITHER EXPRESSLY OR IMPLIEDLY, ABOUT THE  
* SUITABILITY OR NON-INFRINGEMENT OF THE SOFTWARE. NCS SHALL NOT BE LIABLE  
* FOR ANY LOSSES OR DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,  
* MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  
* =========================================================================  
*/

package adpterService;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.BlockingQueue;

/**
 * @description
 * @author yuanhui.he
 * @createDate Aug 19, 2020 10:45:27 AM
 */
public class Solution2 {
	


	// 判断B是不是A的子结构
	public boolean isSubStructure(TreeNode A, TreeNode B) {
		if (A == null || B == null)
			return false;
		// 先从根节点判断B是不是A的子节点,如果不是则递归分别从A的左子树,右子树判断
		// 只要有一个为true,那么就说明B是A的子节点
		return isSb(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
	}

	public boolean isSb(TreeNode A, TreeNode B) {
		// 如果B为空,那么就说明B已经访问完了而且没有返回false,B是A的子节点
		if (B == null)
			return true;
		// 如果A已经访问完了B还没有访问完,或者A的节点值和B的节点值不等,那么B则不是A的子节点 直接返回false
		if (A == null || A.val != B.val)
			return false;
		// 当前节点判断成功 没有返回false,那么则继续判断左子节点与右子节点
		return isSb(A.left, B.left) && isSb(A.right, B.right);

	}

	// 二叉树的镜像 递归交换 法 感觉递归看着很简单 但是要自己写出来真的就不容易了。
	public TreeNode mirrorTree(TreeNode root) {
		if (root == null)
			return null;
		// 递归的交换左子树和又子树
		TreeNode tempNode = root.left;
		root.left = mirrorTree(root.right);
		root.right = mirrorTree(tempNode);
		return root;
	}

	// 二叉树的镜像 遍历二叉树 交换左右子树
	public TreeNode mirrorTree1(TreeNode root) {
		if (root == null)
			return null;
		Stack<TreeNode> stack = new Stack<TreeNode>();
		stack.add(root);
		while (!stack.isEmpty()) {
			TreeNode pop = stack.pop();
			if (pop.left != null)
				stack.add(pop.left);
			if (pop.right != null)
				stack.add(pop.right);

			TreeNode temp = pop.left;
			pop.left = pop.right;
			pop.right = temp;
		}
		return root;
	}

	// 判断一个二叉树而否为对称二叉树
	public boolean isSymmetric(TreeNode root) {
		if (root == null)
			return true;
		return recur(root.left, root.right);
	}

	public boolean recur(TreeNode left, TreeNode right) {
		// 左子树和右子树同时越过叶节点 说明是对称的
		if (left == null && right == null)
			return true;
		if (left == null || right == null || left.val != right.val)
			return false;

		// 左节点的左子节点和右节点的右子节点比较 左节点的右子节点和右节点的左子节点比较
		return recur(left.left, right.right) && recur(left.right, right.left);
	}

	public boolean isSymmetric1(TreeNode root) {
		if (root == null)
			return true;
		Queue<TreeNode> queue = new LinkedList<TreeNode>();
		if (root == null)
			return true;
		queue.add(root.left);
		queue.add(root.right);
		while (!queue.isEmpty()) {
			// 每一次出队列2个节点 中2个节点就是位置对称的那2个节点
			TreeNode left = queue.poll();
			TreeNode right = queue.poll();
			// 说明对称位置没有节点 那么则继续循环
			if (left == null && right == null)
				continue;
			if (left == null || right == null)
				return false;
			if (left.val != right.val)
				return false;
			queue.add(left.left);
			queue.add(right.right);
			queue.add(left.right);
			queue.add(right.left);
		}
		return true;
	}

	// 判断一个序列是否为二叉搜索树的后续遍历序列
	// 二叉搜索树,左子树节点的值都小于根节点的值 右子树节点 的值都大于根节点的值 没有重复的值
	public boolean verifyPostorder(int[] postorder) {

		return isBinarySearchTree(postorder, 0, postorder.length - 1);
	}

	public boolean isBinarySearchTree(int[] a, int i, int j) {
		// 说明只有一个节点
		if (i >= j)
			return true;
		int p = i;
		while (a[p] < a[j])
			p++;
		int m = p;
		while (a[p] > a[j])
			p++;

		return p == j && isBinarySearchTree(a, i, m - 1) && isBinarySearchTree(a, m, j - 1);

	}

	LinkedList<List<Integer>> result = new LinkedList<>();
	LinkedList<Integer> path = new LinkedList<>();

	// 打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
	public List<List<Integer>> pathSum(TreeNode root, int sum) {

		recur(root, sum);
		return result;

	}

	public void recur(TreeNode root, int target) {
		if (root == null)
			return;
		path.add(root.val);
		target -= root.val;
		if (target == 0 && root.left == null && root.right == null) {
			result.add(new LinkedList(path));
		}
		recur(root.left, target);
		recur(root.right, target);
		path.removeLast();

	}

	// 从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0
	// ,可以看成任意数字
	//
	// 最大牌-最小牌<5 就OK(王除外) 这TM不是coding能力 这是智商呀 只要明白了这一点 代码随便都写得出来 也可以用 min 和
	// max记录最大和最小值
	public boolean isStraight(int[] nums) {
		int joker = 0;
		Arrays.sort(nums);
		for (int i = 0; i < 4; i++) {
			if (nums[i] == 0)
				joker++;
			else if (nums[i] == nums[i + 1])
				return false;
		}
		return nums[4] - nums[joker] < 5;
	}

	public boolean isStraight1(int[] nums) {

		int max = Integer.MIN_VALUE;
		int min = Integer.MAX_VALUE;

		Set<Integer> set = new HashSet<Integer>();

		for (int i = 0; i < nums.length; i++) {
			if (nums[i] == 0)
				continue;
			max = Math.max(max, nums[i]);
			min = Math.min(min, nums[i]);
			if (set.contains(nums[i]))
				return false;
			else {
				set.add(nums[i]);
			}
		}

		return max - min < 5;
	}

	// 約瑟夫环  此方法力扣勉强能通过
	public int lastRemaining(int n, int m) {
		List<Integer> list = new ArrayList<Integer>();
		for (int i = 0; i < n; i++) {
			list.add(i);
		}
		int index = 0;
		while (n > 1) {
			index = (index + m - 1) % n;
			list.remove(index);
			n--;
		}
		return list.get(0);
	}

	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	public static void main(String[] args) {
		Solution2 solution2 = new Solution2();
	}

}

public class TreeNode {

	int val;
	TreeNode left;
	TreeNode right;

	TreeNode(int val) {
		this.val = val;
	}

}

public class ListNode {
	int val;
	ListNode next;

	ListNode(int x) {
		val = x;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值