爬虫逆向实战(36)-某建设监管平台(RSA,魔改)
一、数据接口分析
主页地址:某建设监管平台
1、抓包
通过抓包可以发现网站首先是请求了一个/prod-api/mohurd-pub/vcode/genVcode的接口,用于获取滑块验证码的图片
滑块验证之后,请求了/prod-api/mohurd-pub/dataServ/findBaseEntDpPage这个接口,来获取数据
2、判断是否有加密参数
- 请求参数是否加密?
通过查看“载荷”模块可以发现,这两个接口都是只有一个params
的加密参数
- 请求头是否加密?
无 - 响应是否加密?
无 - cookie是否加密?
无
二、加密位置定位
1、看启动器
查看启动器发现里面包含异步,所以无法正确找到加密位置
2、搜索关键字
通过搜索关键字,发现可以搜出来很多位置,无法准确定位到加密位置
3、Hook
因为请求参数中只有一个params
参数,所以网站大概率会使用JSON.stringify
方法将明文数据转json之后再加密。
通过hook,我们可以找到加密位置
同时,可以发现params是进行了双重加密,首先使用W_e().encrypt
进行了一次加密(此处有点类似于AES或DES加密,但是通过测试,发现加密结果不一致,所以可能是魔改加密算法),然后将加密结果再使用X_e
进行二次加密(此处是标准RSA加密)。
三、扣js代码
将W_e().encrypt
方法扣出,缺啥补啥即可,X_e
方法可以扣网站代码,也可以直接使用标准模块。
注:
此网站的滑块验证码,仅需将缺口距离在第二次数据接口请求时带上即可
源代码:
const JSEncrypt = require('jsencrypt');
const G_e = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC29miF1Wp9XlhCECo+FYpCHad1ipEMgXf4IdgYjMIQwczzo9GXdcZ4eeV+9lkh6+aTqzzU843rdkMt0vrSnujU+GOuDPLfa5LZ6SfanAoysi6xxTX02Xizb3k+Z1USIzm9QAwE+SR1AQ78rGTRFHWFu7OGPkVNeF+vrX3inQTiawIDAQAB";function Jbe(e) {var t = n7(e), n = t[0], o = t[1];return (n + o) * 3 / 4 - o
}function exe(e) {var t, n = n7(e), o = n[0], r = n[1], s = new Xbe(Qbe(e, o, r)), a = 0, l = r > 0 ? o - 4 : o, i;for (i = 0; i < l; i += 4)t = oo[e.charCodeAt(i)] << 18 | oo[e.charCodeAt(i + 1)] << 12 | oo[e.charCodeAt(i + 2)] << 6 | oo[e.charCodeAt(i + 3)],s[a++] = t >> 16 & 255,s[a++] = t >> 8 & 255,s[a++] = t & 255;return r === 2 && (t = oo[e.charCodeAt(i)] << 2 | oo[e.charCodeAt(i + 1)] >> 4,s[a++] = t & 255),r === 1 && (t = oo[e.charCodeAt(i)] << 10 | oo[e.charCodeAt(i + 1)] << 4 | oo[e.charCodeAt(i + 2)] >> 2,s[a++] = t >> 8 & 255,s[a++] = t & 255),s
}
function txe(e) {return Vo[e >> 18 & 63] + Vo[e >> 12 & 63] + Vo[e >> 6 & 63] + Vo[e & 63]
}
function nxe(e, t, n) {for (var o, r = [], s = t; s < n; s += 3)o = (e[s] << 16 & 16711680) + (e[s + 1] << 8 & 65280) + (e[s + 2] & 255),r.push(txe(o));return r.join("")
}
function oxe(e) {for (var t, n = e.length, o = n % 3, r = [], s = 16383, a = 0, l = n - o; a < l; a += s)r.push(nxe(e, a, a + s > l ? l : a + s));return o === 1 ? (t = e[n - 1],r.push(Vo[t >> 2] + Vo[t << 4 & 63] + "==")) : o === 2 && (t = (e[n - 2] << 8) + e[n - 1],r.push(Vo[t >> 10] + Vo[t >> 4 & 63] + Vo[t << 2 & 63] + "=")),r.join("")
}var jc = {};
jc.byteLength = Jbe;
jc.toByteArray = exe;
jc.fromByteArray = oxe;
const O6 = jc;
var Vo = [], oo = [], Xbe = typeof Uint8Array != "undefined" ? Uint8Array : Array, Lu = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var js = 0, Zbe = Lu.length; js < Zbe; ++js)Vo[js] = Lu[js],oo[Lu.charCodeAt(js)] = js;
class V_e {static stringToArrayBufferInUtf8(t) {const n = typeof window == "undefined" ? yd.TextEncoder : window.TextEncoder;return new n().encode(t)}static utf8ArrayBufferToString(t) {const n = typeof window == "undefined" ? yd.TextDecoder : window.TextDecoder;return new n("utf-8").decode(t)}static arrayBufferToBase64(t) {return O6.fromByteArray(t)}static base64ToArrayBuffer(t) {return O6.toByteArray(t)}
}const Sr = V_e, to = 16, Di = Uint8Array.from([214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72]), L_e = Uint32Array.from([462357, 472066609, 943670861, 1415275113, 1886879365, 2358483617, 2830087869, 3301692121, 3773296373, 4228057617, 404694573, 876298825, 1347903077, 1819507329, 2291111581, 2762715833, 3234320085, 3705924337, 4177462797, 337322537, 808926789, 1280531041, 1752135293, 2223739545, 2695343797, 3166948049, 3638552301, 4110090761, 269950501, 741554753, 1213159005, 1684763257]), Oi = Uint32Array.from([2746333894, 1453994832, 1736282519, 2993693404]);class R_e {constructor(t) {let n = Sr.stringToArrayBufferInUtf8(t.key);if (n.length !== 16)throw new Error("key should be a 16 bytes string");this.key = n;let o = new Uint8Array(0);if (t.iv !== void 0 && t.iv !== null && (o = Sr.stringToArrayBufferInUtf8(t.iv),o.length !== 16))throw new Error("iv should be a 16 bytes string");this.iv = o,this.mode = "cbc",["cbc", "ecb"].indexOf(t.mode) >= 0 && (this.mode = t.mode),this.cipherType = "base64",["base64", "text"].indexOf(t.outType) >= 0 && (this.cipherType = t.outType),this.encryptRoundKeys = new Uint32Array(32),this.spawnEncryptRoundKeys(),this.decryptRoundKeys = Uint32Array.from(this.encryptRoundKeys),this.decryptRoundKeys.reverse()}doBlockCrypt(t, n) {let o = new Uint32Array(36);o.set(t, 0);for (let s = 0; s < 32; s++)o[s + 4] = o[s] ^ this.tTransform1(o[s + 1] ^ o[s + 2] ^ o[s + 3] ^ n[s]);let r = new Uint32Array(4);return r[0] = o[35],r[1] = o[34],r[2] = o[33],r[3] = o[32],r}spawnEncryptRoundKeys() {let t = new Uint32Array(4);t[0] = this.key[0] << 24 | this.key[1] << 16 | this.key[2] << 8 | this.key[3],t[1] = this.key[4] << 24 | this.key[5] << 16 | this.key[6] << 8 | this.key[7],t[2] = this.key[8] << 24 | this.key[9] << 16 | this.key[10] << 8 | this.key[11],t[3] = this.key[12] << 24 | this.key[13] << 16 | this.key[14] << 8 | this.key[15];let n = new Uint32Array(36);n[0] = t[0] ^ Oi[0],n[1] = t[1] ^ Oi[1],n[2] = t[2] ^ Oi[2],n[3] = t[3] ^ Oi[3];for (let o = 0; o < 32; o++)n[o + 4] = n[o] ^ this.tTransform2(n[o + 1] ^ n[o + 2] ^ n[o + 3] ^ L_e[o]),this.encryptRoundKeys[o] = n[o + 4]}rotateLeft(t, n) {return t << n | t >>> 32 - n}linearTransform1(t) {return t ^ this.rotateLeft(t, 2) ^ this.rotateLeft(t, 10) ^ this.rotateLeft(t, 18) ^ this.rotateLeft(t, 24)}linearTransform2(t) {return t ^ this.rotateLeft(t, 13) ^ this.rotateLeft(t, 23)}tauTransform(t) {return Di[t >>> 24 & 255] << 24 | Di[t >>> 16 & 255] << 16 | Di[t >>> 8 & 255] << 8 | Di[t & 255]}tTransform1(t) {let n = this.tauTransform(t);return this.linearTransform1(n)}tTransform2(t) {let n = this.tauTransform(t);return this.linearTransform2(n)}padding(t) {if (t === null)return null;let n = to - t.length % to, o = new Uint8Array(t.length + n);return o.set(t, 0),o.fill(n, t.length),o}dePadding(t) {if (t === null)return null;let n = t[t.length - 1];return t.slice(0, t.length - n)}uint8ToUint32Block(t, n=0) {let o = new Uint32Array(4);return o[0] = t[n] << 24 | t[n + 1] << 16 | t[n + 2] << 8 | t[n + 3],o[1] = t[n + 4] << 24 | t[n + 5] << 16 | t[n + 6] << 8 | t[n + 7],o[2] = t[n + 8] << 24 | t[n + 9] << 16 | t[n + 10] << 8 | t[n + 11],o[3] = t[n + 12] << 24 | t[n + 13] << 16 | t[n + 14] << 8 | t[n + 15],o}encrypt(t) {let n = Sr.stringToArrayBufferInUtf8(t), o = this.padding(n), r = o.length / to, s = new Uint8Array(o.length);if (this.mode === "cbc") {if (this.iv === null || this.iv.length !== 16)throw new Error("iv error");let a = this.uint8ToUint32Block(this.iv);for (let l = 0; l < r; l++) {let i = l * to, c = this.uint8ToUint32Block(o, i);a[0] = a[0] ^ c[0],a[1] = a[1] ^ c[1],a[2] = a[2] ^ c[2],a[3] = a[3] ^ c[3];let u = this.doBlockCrypt(a, this.encryptRoundKeys);a = u;for (let f = 0; f < to; f++)s[i + f] = u[parseInt(f / 4)] >> (3 - f) % 4 * 8 & 255}} elsefor (let a = 0; a < r; a++) {let l = a * to, i = this.uint8ToUint32Block(o, l), c = this.doBlockCrypt(i, this.encryptRoundKeys);for (let u = 0; u < to; u++)s[l + u] = c[parseInt(u / 4)] >> (3 - u) % 4 * 8 & 255}return this.cipherType === "base64" ? Sr.arrayBufferToBase64(s) : Sr.utf8ArrayBufferToString(s)}decrypt(t) {let n = new Uint8Array;this.cipherType === "base64" ? n = Sr.base64ToArrayBuffer(t) : n = Sr.stringToArrayBufferInUtf8(t);let o = n.length / to, r = new Uint8Array(n.length);if (this.mode === "cbc") {if (this.iv === null || this.iv.length !== 16)throw new Error("iv error");let a = this.uint8ToUint32Block(this.iv);for (let l = 0; l < o; l++) {let i = l * to, c = this.uint8ToUint32Block(n, i), u = this.doBlockCrypt(c, this.decryptRoundKeys), f = new Uint32Array(4);f[0] = a[0] ^ u[0],f[1] = a[1] ^ u[1],f[2] = a[2] ^ u[2],f[3] = a[3] ^ u[3],a = c;for (let d = 0; d < to; d++)r[i + d] = f[parseInt(d / 4)] >> (3 - d) % 4 * 8 & 255}} elsefor (let a = 0; a < o; a++) {let l = a * to, i = this.uint8ToUint32Block(n, l), c = this.doBlockCrypt(i, this.decryptRoundKeys);for (let u = 0; u < to; u++)r[l + u] = c[parseInt(u / 4)] >> (3 - u) % 4 * 8 & 255}let s = this.dePadding(r);return Sr.utf8ArrayBufferToString(s)}
}
var j_e = {sm4: R_e
}
function W_e() {const t = {};t.key = "B6*40.2_C9#e4$E3",t['mode'] = 'ecb',t.cipherType = "base64";const n = t, o = j_e['sm4'];return new o(n)
}function get_params(data) {e = W_e().encrypt(JSON.stringify(data))var encrypt = new JSEncrypt();encrypt.setPublicKey(G_e);const o = 117, r = Math['ceil'](e['length'] / o);let s = [];for (let a = 0; a < r; a++) {const l = e.slice(a * o, (a + 1) * o), i = encrypt.encrypt(l);s.push(i)}return s
}
相关文章:

爬虫逆向实战(36)-某建设监管平台(RSA,魔改)
一、数据接口分析 主页地址:某建设监管平台 1、抓包 通过抓包可以发现网站首先是请求了一个/prod-api/mohurd-pub/vcode/genVcode的接口,用于获取滑块验证码的图片 滑块验证之后,请求了/prod-api/mohurd-pub/dataServ/findBaseEntDpPage这…...

DeepLearning in Pytorch|共享单车预测NN详解(思路+代码剖析)
目录 概要 一、代码概览 二、详解 基本逻辑 1.数据准备 2.设计神经网络 初版 改进版 测试 总结 概要 原文链接:DeepLearning in Pytorch|我的第一个NN-共享单车预测 我的第一个深度学习神经网络模型---利用Pytorch设计人工神经网络对某地区租赁单车的使用…...

如何配置Apache的反向代理
目录 前言 一、反向代理的工作原理 二、Apache反向代理的配置 1. 安装Apache和相关模块 2. 配置反向代理规则 3. 重启Apache服务器 三、常见的使用案例 1. 负载均衡 2. 缓存 3. SSL加密 总结 前言 随着Web应用程序的不断发展和扩展,需要处理大量的请求和…...

Vue.js 应用实现监控可观测性最佳实践
前言 Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。 TinyPro 是一套使用 Vue …...
Rust 语言中符号 :: 的使用场景
在 Rust 语言中,:: 符号主要用于以下几个场合: 指定关联函数或关联类型: 关联函数(也称为静态方法)是与类型关联而非实例关联的函数。它们使用 :: 符号来调用。例如: let value String::from("Hello,…...
Java 获取笔记本WiFi网络基站信息的方法
在Android开发中,获取基站信息(如基站ID、运营商信息、信号强度等)通常涉及使用TelephonyManager类。请注意,由于隐私和安全的考虑,从Android 10(API级别29)开始,对访问此类信息的权…...
Python如何处理拥塞控制
拥塞控制是计算机网络中用于防止网络拥塞(即过多的数据导致网络性能下降)的一系列技术和算法。在Python中,处理拥塞控制通常不直接涉及到代码层面的实现,因为拥塞控制主要是在网络协议栈(如TCP/IP)和操作系…...

【ArcGIS】栅格数据进行标准化(归一化)处理
栅格数据进行标准化(归一化)处理 方法1:栅格计算器方法2:模糊分析参考 栅格数据进行标准化(归一化)处理 方法1:栅格计算器 栅格计算器(Raster Calculator) 计算完毕后,得到归一化…...
【CMake】顶层 CMakeList.txt 常用命令总结
文章目录 cmake_minimum_required简介使用案例普通设置执行构建的cmake版本低于<min> project简介使用案例普通设置 set简介使用案例普通设置 cmake_minimum_required 简介 功能:为项目设置cmake的最低要求版本常用程度:⭐⭐⭐⭐⭐命令格式 cma…...

mac启动elasticsearch
1.首先下载软件,然后双击解压,我用的是7.17.3的版本 2.然后执行如下命令 Last login: Thu Mar 14 23:14:44 on ttys001 diannao1xiejiandeMacBook-Air ~ % cd /Users/xiejian/local/software/elasticsearch/elasticsearch-7.17.3 diannao1xiejiandeMac…...

【FFmpeg】ffmpeg 命令行参数 ⑤ ( 使用 ffmpeg 命令提取 音视频 数据 | 保留封装格式 | 保留编码格式 | 重新编码 )
文章目录 一、使用 ffmpeg 命令提取 音视频 数据1、提取音频数据 - 保留封装格式2、提取视频数据 - 保留封装格式3、提取视频数据 - 保留编码格式4、提取视频数据 - 重新编码5、提取音频数据 - 保留编码格式6、提取音频数据 - 重新编码 一、使用 ffmpeg 命令提取 音视频 数据 1…...

JMeter 二次开发之环境准备
通过JMeter二次开发,可以充分发挥JMeter的潜力,定制化和扩展工具的能力以满足具体需求。无论是开发自定义插件、函数二次开发还是定制UI,深入学习和掌握JMeter的二次开发技术,将为接口功能测试/接口性能测试工作带来更多的便利和效…...

Laravel Class ‘Facade\Ignition\IgnitionServiceProvider‘ not found 解决
Laravel Class Facade\Ignition\IgnitionServiceProvider not found 问题解决 问题 在使用laravel 更新本地依赖环境时,出现报错,如下: 解决 这时候需要更新本地的composer,然后在更新本地依赖环境。 命令如下: co…...
DNS 技巧与窍门
简介 在本文中,您将学习三种可以使用 DNS 完成的技巧。如果您曾经进行过任何与 DNS 配置相关的工作,这些小技巧可能会帮助您更快地完成工作流程。您将学习一些在终端中使用的命令和处理 DNS 数据的方法,比如如何检查当前的域名服务器。完成后…...

第2章 信息技术基础
本章学习要点 全面了解医院信息系统建设所涉及的主要信息技术以及这些技术的应用情况。 计算机与网络、信息技术与信息系统、数字媒体与数据存储技术、条形码(二维码)、RFID技术、云计算、APP技术 1.XML 可扩展标记语言与Access,Oracle和SQL Server等数据库不同…...
uniapp 微信小程序和h5处理文件(pdf)下载+保存到本地+预览功能
uniapp实现微信小程序下载资源功能和h5有很大的不同,后台需返回blob文件流 1.微信小程序实现下载资源功能 步骤1:下载文件 uni.downloadFile({url:url,//调接口返回urlsuccess:(res)>{uni.hideLoading();if(res.statusCode200){var tempFilePath …...

Linux从0到1——Linux第一个小程序:进度条
Linux从0到1——Linux第一个小程序:进度条 1. 输出缓冲区2. 回车和换行的本质3. 实现进度条3.1 简单原理版本3.2 实际工程版本 1. 输出缓冲区 1. 小实验: 编写一个test.c文件,: #include <stdio.h> #include <unistd.h…...
软件工程师,是时候了解下Rust编程语言了
背景 2024年年初,美国政府发布了一份网络安全报告,呼吁软件开发人员停止使用容易出现内存安全漏洞的编程语言,比如:C和C,转而使用内存安全的编程语言。这份报告由美国网络空间总监办公室 (ONCD) 发布,旨在落…...

SSL---VPN
文章目录 目录 一.SSL-VPN概述 优点 二.SSL协议的工作原理 三.虚拟网关技术 用户认证方式 本地认证 服务器认证: 证书匿名认证 Web代理 Web-link和Web改写 端口转发 网络扩展(允许UDP协议) 总结 一.SSL-VPN概述 SLL VPN是一种基于HTTPS&am…...
Chrome 跨域问题CORS 分析
先叠个甲,有错误,望沟通指正! 文章目录 1.什么是跨域报错2.为什么postman可以,浏览器访问就不行?根本原因是什么?2.1浏览器是依据什么来报错跨域的? 3.常规解决方案的分析方案1.通过代理解决方案2.被请求的B域的服务端开启Access-Control-Allow-Origin返回头的支持方案3.通…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...