常见加密算法详解

☆* o(≧▽≦)o *☆嗨~我是小奥🍹
📄📄📄个人博客:小奥的博客
📄📄📄CSDN:个人CSDN
📙📙📙Github:传送门
📅📅📅面经分享(牛客主页):传送门
🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正!
📜 如果觉得内容还不错,欢迎点赞收藏关注哟! ❤️

文章目录

  • 加密算法详解
    • 1、分类
      • 对称加密
      • 非对称加密
      • Hash算法
    • 2、常见的加密算法
      • 2.1 对称加密算法 DES
        • 加密的原则
        • 加密的原理
        • 加密的特点
        • DES 实现
      • 2.2 非对称加密算法 RSA
        • 加密的原理
        • 加密的具体过程
          • 1、公钥和私钥的产生
          • 2、加密消息
          • 3、解密消息
        • RSA算法的应用
          • 1、加密少量数据
          • 2、实现数字签名
          • 3、实现
      • 2.3 Hash加密算法 MD5
        • MD5 算法的原理
        • MD5算法概述
        • MD5应用场景
        • MD5实现

加密算法详解

数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的密钥之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。

1、分类

对称加密

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。亦指加密和解密使用相同密钥的加密算法。

对称加密算法的优点在于加解密的高速度和使用长密钥时的难破解性

假设两个用户需要使用对称加密方法加密然后交换数据,则用户最少需要2个密钥并交换使用,如果企业内用户有n个,则整个企业共需要n×(n-1) 个密钥,密钥的生成和分发将成为企业信息部门的恶梦。对称加密算法的安全性取决于加密密钥的保存情况,但要求企业中每一个持有密钥的人都保守秘密是不可能的,他们通常会有意无意的把密钥泄漏出去——如果一个用户使用的密钥被入侵者所获得,入侵者便可以读取该用户密钥加密的所有文档,如果整个企业共用一个加密密钥,那整个企业文档的保密性便无从谈起。

常见的对称加密算法:DES、3DES、DESX、Blowfish、IDEA、RC4、RC5、RC6和AES

非对称加密

指加密和解密使用不同密钥的加密算法,也称为公私钥加密

假设两个用户要加密交换数据,双方交换公钥,使用时一方用对方的公钥加密,另一方即可用自己的私钥解密。如果企业中有n个用户,企业需要生成n对密钥,并分发n个公钥。由于公钥是可以公开的,用户只要保管好自己的私钥即可,因此加密密钥的分发将变得十分简单。同时,由于每个用户的私钥是唯一的,其他用户除了可以可以通过信息发送者的公钥来验证信息的来源是否真实,还可以确保发送者无法否认曾发送过该信息。非对称加密的缺点是加解密速度要远远慢于对称加密,在某些极端情况下,甚至能比非对称加密慢上1000倍。

常见的非对称加密算法:RSA、ECC(移动设备用)、Diffie-Hellman、El Gamal、DSA(数字签名用)

Hash算法

Hash算法特别的地方在于它是一种单向算法,用户可以通过Hash算法对目标信息生成一段特定长度的唯一的Hash值,却不能通过这个Hash值重新获得目标信息。因此Hash算法常用在不可还原的密码存储、信息完整性校验等。

常见的Hash算法:MD2、MD4、MD5、HAVAL、SHA、SHA-1、HMAC、HMAC-MD5、HMAC-SHA1

2、常见的加密算法

2.1 对称加密算法 DES

Java 利用 DES / 3DES / AES 三种算法分别实现 对称加密 - 掘金 (juejin.cn)

加密的原则

(1)混淆(confusion):使密文与密钥的关系尽可能复杂化,使得对手即使获取了许多明文和对应的密文,以及关于密文的一些统计特性,也无法推测密钥。
(2)扩散(diffusion):让明文中的每一位影响密文中的许多位,或者说让密文中的每一位受明文中的许多位的影响。这样可以隐蔽明文的统计特性。当然,理想的情况是让明文中的每一位影响密文中的所有位,或者说让密文中的每一位受明文中所有位的影响。
(3)分组(block cipher):可以看成经典的电报密码本加密技术的现代传承,其中由密钥来决定电报密码本的选择。一次加密一组数据,密钥长度为一组数据的长度。

加密的原理

DES(Data Encryption Standard)采用分组加密。使用64位的分组长度和56位的密钥长度,将64位的输入经过一系列变换得到64位的输出。DES算法利用多次组合替代算法和换位算法,通过混淆和扩散的相互作用,把明文编制成密码强度很高的密文。解密则使用了相同的步骤和相同的密钥。

DES的压缩、扩展和置换操作使其具有很强的雪崩效应。即输入明文或密钥中一个比特的变化会导致输出中至少一半比特的密文发生变化,这使得穷举试凑寻找其中规律变得不可能。

加密的特点

DES算法产生密钥的方式简单,密钥一般也比较短。
DES算法加密解密速度快,效率很高,适合对大数据量的数据进行加密。
DES算法的安全性依赖于密钥的高度保密,通信双方必须有方法能保证安全的分享密钥,并定期更换DES密钥。

DES 实现
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;public class DES {private static final String KEY = "Hello Ketty";/*** DES 加密** @param content* @return*/public static byte[] desEncrypt(String content) {try {KeyGenerator kGen = KeyGenerator.getInstance("DES");kGen.init(56, new SecureRandom(KEY.getBytes()));SecretKey secretKey = kGen.generateKey();byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec key = new SecretKeySpec(enCodeFormat, "DES");Cipher cipher = Cipher.getInstance("DES");// 创建密码器byte[] byteContent = content.getBytes("utf-8");cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化byte[] result = cipher.doFinal(byteContent);return result; // 加密} catch (Throwable e) {e.printStackTrace();}return null;}/*** DES 解密** @param content* @return*/public static byte[] desDecrypt(byte[] content) throws Exception {KeyGenerator kGen = KeyGenerator.getInstance("DES");kGen.init(56, new SecureRandom(KEY.getBytes()));SecretKey secretKey = kGen.generateKey();byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec key = new SecretKeySpec(enCodeFormat, "DES");Cipher cipher = Cipher.getInstance("DES"); // 创建密码器cipher.init(Cipher.DECRYPT_MODE, key); // 初始化byte[] result = cipher.doFinal(content); // 解密return result;}/*** 将二进制转换成16进制** @param buf* @return*/public static String parseByte2HexStr(byte buf[]) {StringBuffer sb = new StringBuffer();for (int i = 0; i < buf.length; i++) {String hex = Integer.toHexString(buf[i] & 0xFF);if (hex.length() == 1) {hex = '0' + hex;}sb.append(hex.toUpperCase());}return sb.toString();}/*** 将16进制转换为二进制** @param hexStr* @return*/public static byte[] parseHexStr2Byte(String hexStr) {if (hexStr.length() < 1)return null;byte[] result = new byte[hexStr.length() / 2];for (int i = 0; i < hexStr.length() / 2; i++) {int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);result[i] = (byte) (high * 16 + low);}return result;}/*** 主函数*/public static void main(String[] args) throws Exception {String content = "Hello World!";//加密System.out.println("加密前:" + content);byte[] encryptResult = desEncrypt(content);String result = parseByte2HexStr(encryptResult);System.out.println("加密后:" + result);//解密byte[] bytes = parseHexStr2Byte(result);byte[] decryptResult = desDecrypt(bytes);System.out.println("解密后:" + new String(decryptResult));}
}

2.2 非对称加密算法 RSA

加密的原理

RSA算法基于数论构造,其算法具体实现基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

加密的具体过程
1、公钥和私钥的产生

(1)任意选择两个大的质数(素数)p和q,p不等于q,计算N=pq
(2)根据欧拉函数,不大于N且与N互质的整数个数为(p-1)(q-1)
(3)选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1)
(4)用以下这个公式计算d:d×e ≡ 1 (mod (p-1)(q-1))
(5)将p和q销毁后,(N,e)是公钥,(N,d)是私钥

2、加密消息

假设Bob想给Alice送一个消息,他知道Alice产生的公钥N和e
将原始信息分为多段,每一段(假定为n)分别用以下公式计算出c:

n ^ e ≡ c (mod N)
3、解密消息

Alice得到Bob的消息c后就可以利用她的密钥(N,d)来解码。她可以用以下这个公式来将c转换为n:

e ^ d ≡ n (mod N)

得到n后,她可以将原来的信息m重新复原。

RSA算法的应用
1、加密少量数据

比起DES和其它对称算法来说,RSA的运算速度要慢得多。
实际使用时,RSA算法不用来加密消息,而是用来加密传输密钥,加密消息用对称算法,如DES。

2、实现数字签名

将RSA算法反向使用(私钥加密公钥解密),对消息摘要加密,可以实现数字签名的功能。
数字签名可以防止数据篡改、数据抵赖和数据伪造发生。

3、实现
package com.vip.file;import java.math.BigInteger;
import java.util.Random;public class RSA {private final static int numLength = 1024;//素数长度private final static int accuracy = 100;//素数的准确率为1-(2^(-accuracy))//获取最大公约数private BigInteger getGCD(BigInteger a, BigInteger b) {if (b.byteValue() == 0) return a;return getGCD(b, a.mod(b));}//扩展欧几里得方法,计算 ax + by = 1中的x与y的整数解(a与b互质)private static BigInteger[] extGCD(BigInteger a, BigInteger b) {if (b.signum() == 0) {return new BigInteger[]{a, new BigInteger("1"), new BigInteger("0")};} else {BigInteger[] bigIntegers = extGCD(b, a.mod(b));BigInteger y = bigIntegers[1].subtract(a.divide(b).multiply(bigIntegers[2]));return new BigInteger[]{bigIntegers[0], bigIntegers[2], y};}}//超大整数超大次幂然后对超大的整数取模,利用蒙哥马利乘模算法,//(base ^ exp) mod n//依据(a * b) mod n=(a % n)*(b % n) mod nprivate static BigInteger expMode(BigInteger base, BigInteger exp, BigInteger mod) {BigInteger res = BigInteger.ONE;//拷贝一份防止修改原引用BigInteger tempBase = new BigInteger(base.toString());//从左到右实现简答/*D=1WHILE E>=0IF E%2=0C=C*C % NE=E/2ELSED=D*C % NE=E-1RETURN D*/for (int i = 0; i < exp.bitLength(); i++) {if (exp.testBit(i)) {//判断对应二进制位是否为1res = (res.multiply(tempBase)).mod(mod);}tempBase = tempBase.multiply(tempBase).mod(mod);}return res;}//产生公钥与私钥public static SecretKey generateKey(BigInteger p, BigInteger q) {//令n = p * q。取 φ(n) = (p-1) * (q-1)。BigInteger n = p.multiply(q);//计算与n互质的整数个数 欧拉函数BigInteger fy = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));//取 e ∈ [1 < e < φ(n) ] ,( n , e )作为公钥对,这里取65537BigInteger e = new BigInteger("65537");//计算ed与fy的模反元素d。令 ed mod φ(n)  = 1,计算d,然后将( n , d ) 作为私钥对BigInteger[] bigIntegers = extGCD(e, fy);//计算出的x不能是负数,如果是负数,则进行x=x+fy。使x为正数,但是x<fy。BigInteger x = bigIntegers[1];if (x.signum() == -1) {x = x.add(fy);}//返回计算出的密钥return new SecretKey(n, e, x);}public static SecretKey generateKey() {BigInteger[] pq = getRandomPQ();return generateKey(pq[0], pq[1]);}//加密public static BigInteger encrypt(BigInteger text, SecretKey.PublicKey publicKey) {return expMode(text, publicKey.e, publicKey.n);}//解密public static BigInteger decrypt(BigInteger cipher, SecretKey.PrivateKey privateKey) {return expMode(cipher, privateKey.d, privateKey.n);}//加密public static String encrypt(String text, SecretKey.PublicKey publicKey) {return encrypt(new BigInteger(text.getBytes()), publicKey).toString();}//解密public static String decrypt(String chipper, SecretKey.PrivateKey privateKey) {BigInteger bigInteger = expMode(new BigInteger(chipper), privateKey.d, privateKey.n);byte[] bytes = new byte[bigInteger.bitLength() / 8 + 1];for (int i = 0; i < bytes.length; i++) {for (int j = 0; j < 8; j++) {if (bigInteger.testBit(j + i * 8)) {bytes[bytes.length - 1 - i] |= 1 << j;}}}return new String(bytes);}//产生两个随机1024位大质数public static BigInteger[] getRandomPQ() {BigInteger p = BigInteger.probablePrime(numLength, new Random());while (!p.isProbablePrime(accuracy)) {p = BigInteger.probablePrime(numLength, new Random());}BigInteger q = BigInteger.probablePrime(numLength, new Random());while (!q.isProbablePrime(accuracy)) {q = BigInteger.probablePrime(numLength, new Random());}return new BigInteger[]{p, q};}//密匙对static class SecretKey {BigInteger n, e, d;public SecretKey(BigInteger n, BigInteger e, BigInteger d) {this.n = n;this.e = e;this.d = d;}public PublicKey getPublicKey() {return new PublicKey(n, e);}public PrivateKey getPrivateKey() {return new PrivateKey(n, d);}//密钥static class PrivateKey {public BigInteger n, d;public PrivateKey(BigInteger n, BigInteger d) {this.n = n;this.d = d;}}//公钥static class PublicKey {public BigInteger n, e;public PublicKey(BigInteger n, BigInteger e) {this.n = n;this.e = e;}}}public static void main(String[] args) {SecretKey secretKey = RSA.generateKey();//明文内容不要超过1024位,超过后需要分段加密String text = "Hello world";String chipper = RSA.encrypt(text, secretKey.getPublicKey());System.out.println("加密后:\n" +//密文长度可能会随着随机密钥的改变而改变,最长不超过2048位"密文二进制长度:" + new BigInteger(chipper).bitLength()+ "\n"+ chipper);String origin = RSA.decrypt(chipper, secretKey.getPrivateKey());System.out.println("解密后:\n" + origin);}
}

2.3 Hash加密算法 MD5

(13条消息) MD5算法的Java实现_JankingWon的博客-CSDN博客

MD5 算法的原理

MD5码以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

MD5算法概述

MD5,是一种信息摘要算法。简单来说,就是把一段信息(明文),通过一种有损的方式压缩成定长的字符(32位密文)。因为这种压缩方式是会损失信息的,所以是无法还原出“明文”的。虽然无法从数学上破解MD5算法,但由于现在计算机具备强大的计算能力,还是可以通过“穷举法”破解该算法。如果想用该算法加密,还可以通过“加盐”的方式提高解密难度。该算法允许多传一个参数"salt",指定通过MD5加密的次数,这样是能够提高解密难度的。

MD5应用场景

数字签名是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串类似于写在纸上的物理签名,用于鉴别数字信息的真伪,同时也是对信息的发送者身份真实性的一个有效证明。
数字签名是公钥加密技术与消息摘要技术的结合应用。

MD5实现

Java 实现 MD5 加密算法 - 掘金 (juejin.cn)

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

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

相关文章

A Balanced Problemset? Codeforces Round 921 (Div. 2) 1925B

Problem - B - Codeforces 题目大意&#xff1a;给出一个整数x&#xff0c;要求将x分成n份&#xff0c;使得所有份的最大公因数最大&#xff0c;求这个最大的最大公因数 1<x<1e8;1<n<x 思路&#xff1a;我们设n个数的公因数是y,那么这n个数都应该是y的倍数&…

【Spark系列3】RDD源码解析实战

本文主要讲 1、什么是RDD 2、RDD是如何从数据中构建 一、什么是RDD&#xff1f; RDD&#xff1a;弹性分布式数据集&#xff0c;Resillient Distributed Dataset的缩写。 个人理解&#xff1a;RDD是一个容错的、并行的数据结构&#xff0c;可以让用户显式的将数据存储到磁盘…

前端——CSS

目录 文章目录 前言 一.CSS简介 1.CSS选择器 2.CSS选择器语法 3.CSS样式引入 4.CSS 高级选择器 二.CSS样式 1.字体 ​编辑 2.文本 3. 背景 4.边框 5.边距 6.浮动 7.清除浮动 8.定位 9. 列表样式 10.伪类样式 三.盒子模型 四.CSS3新特性 1.边框 2.盒子阴影 …

12.从项目经理的生存哲学到适配器模式(Adapter Pattern)

如果这个世界没有了项目经理&#xff0c;事情的发展可能并不会如同想象中一样美好&#xff0c;相反&#xff0c;对于开发人员来说可能是噩梦的开始。 比如&#xff1a; 客户因为几个需求的具体实现大发雷霆&#xff0c;甚至开始恶语相向&#xff0c;一通含ma量极高的“斯伯坦语…

自然语言处理:transfomer架构

介绍 transfomer是自然语言处理中的一个重要神经网络结构&#xff0c;算是在传统RNN和LSTM上的一个升级&#xff0c;接下来让我们来看看它有处理语言序列上有哪些特殊之处 模型整体架构 原论文中模型的整体架构如下&#xff0c;接下来我们将层层解析各层的作用和代码实现 该…

3d模型怎么分辨材质?--模大狮模型网

在3D模型中&#xff0c;通常可以通过以下几种方式来分辨材质&#xff1a; 视觉检查&#xff1a;在3D渲染视图或预览窗口中&#xff0c;您可以直接观察模型的外观来区分不同的材质。不同的材质可能具有不同的颜色、纹理、反射率等特征&#xff0c;因此通过直观的视觉检查&#x…

LV老板重夺全球首富 再次超过马斯克;新东方安徽总部大厦启用;中国与泰国签署互免签证协定

今日精选 • LV老板重夺全球首富 再次超过马斯克• 新东方安徽总部大厦启用• 中国与泰国签署互免签证协定 投融资与企业动态 • ​​传Temu将于3月在美国上线半托管业务• 国内数字支付解决方案提供商 “连连数字” 估值150亿&#xff0c;即将IPO• 滴滴与宁德时代宣布成立…

深度强化学习(王树森)笔记05

深度强化学习&#xff08;DRL&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。本文在ChatGPT辅助下完成。 参考链接 Deep Reinforcement Learning官方链接&#xff1a;https://github.com/wangshusen/DRL 源代码链接&#xff1a;https://github.c…

CF1925F/CF1924C Fractal Origami 题解

以下所有结论通过找规律获得&#xff0c;不会证明。 诈骗题。 发现每次 M M M 和 V V V 增加量是相同的&#xff0c;且是上一次增加量的 2 \sqrt2 2 ​ 倍。 以下式子中 q q q 定义为 n − 1 n-1 n−1。 通过等比数列求和公式可以得到 M V ( 2 ) q 1 ( 2 ) q − 2…

安全防御{第三次作业(在第二次作业上添加点需求)}

目录 需求&#xff1a; 拓扑图&#xff1a; 注意&#xff1a;先打开防火墙web界面&#xff0c;在此不做演示 1.要求一&#xff1a;&#xff0c;生产区在工作时间内可以访问服务器区&#xff0c;仅可以访问http服务器 2.要求二&#xff1a;办公区全天可以访问服务器区&#…

首页热卖推荐商品显示axios异步请求数据动态渲染实现

flex-wrap属性&#xff1a; 默认情况下&#xff0c;项目都排在一条线&#xff08;又称“轴线”&#xff09;上。flex- wrap属性定义&#xff0c;如果一条轴线 排不下&#xff0c;如何换行&#xff1f; flex-wrap:wrap 该样式用于设置 换行。 .product_name{white-space: nowrap…

BGP:03 BGP路由

这是实验拓扑&#xff0c;IBGP 利用环回口建立邻居&#xff0c;IGP 协议为 OSPF&#xff0c; EBGP 通过物理接口建立邻居 基本配置&#xff1a; R1: sys sysname R1 int loop 0 ip add 1.1.1.1 24 int g0/0/0 ip add 192.168.12.1 24 qR2: sys sysname R2 int loop 0 ip ad…

微信小程序 图片自适应高度 宽度 完美适配原生或者uniapp

-- - - - 查了一下百度看到网上图片高度自适应的解决方案 基本是靠JS获取图片的宽度进行按比例计算得出图片高度。 不是很符合我的需求/ 于是我脑瓜子一转 想到一种新的解决方案 不用JS计算也能完美解决。 我写了一个组件&#xff0c;直接导入可以使用。 - - - 1.新…

JCEF学习

JCEF重要概念 CEF CEF&#xff0c;全称Chromium Embedded Framework &#xff0c;它是基于Google Chromium的开源项目&#xff0c;它的目标是能够向第三方程序添加WEB浏览器功能&#xff0c;以及可以使用HTML、CSS和JS渲染界面。 CEF框架是由Marshall Greenblatt 在 2008 年创…

第17节-高质量简历写作求职通关-投递反馈

&#xff08;点击即可收听&#xff09; 投递跟进和感谢信 如果对一家公司特别心仪&#xff0c;但是投递简历后一直得不到回复怎么办&#xff1f; 面试之后觉得自己没有表现好怎么办&#xff1f; 面试完几天了&#xff0c;依然没有得到回应怎么办&#xff1f; 这个时候你需要写一…

【git】git远程仓库迁移后 本地批量修改远程地址

当公司迁移远程git仓库时&#xff0c;我们需要修改git仓库的远程仓库的地址&#xff0c;可以一个一个的修改&#xff0c;但是如果项目比较多并且改的东西都一样的话&#xff0c;使用脚本修改就比较方便了。 预备知识&#xff1a; 查看远程仓库地址&#xff1a; git remote -…

八种Flink任务告警方式

目录 一、Flink应用分析 1.1 Flink任务生命周期 1.2 Flink应用告警视角分析 二、监控告警方案说明 2.1 监控消息队中间件消费者偏移量 2.2 通过调度系统监控Flink任务运行状态 2.3 引入开源服务的SDK工具实现 2.4 调用FlinkRestApi实现任务监控告警 2.5 定时去查询目标…

无人机在三维空间中的转动问题

前提 这篇博客是对最近一个有关无人机拍摄图像项目中所学到的新知识的一个总结&#xff0c;比较杂乱&#xff0c;没有固定的写作顺序。 无人机坐标系旋转问题 上图是无人机坐标系&#xff0c;绕x轴是翻滚(Roll)&#xff0c;绕y轴是俯仰(Pitch)&#xff0c;绕z轴是偏航(Yaw)。…

力扣日记1.27-【回溯算法篇】131. 分割回文串

力扣日记&#xff1a;【回溯算法篇】131. 分割回文串 日期&#xff1a;2023.1.27 参考&#xff1a;代码随想录、力扣 131. 分割回文串 题目描述 难度&#xff1a;中等 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可…

D. Epic Transformation(堆+贪心)

思路&#xff1a;我们删的策略是从次数多的数开始删&#xff0c;每次取两种不同的数&#xff0c;每种删去一个&#xff0c;然后放回堆中。 代码&#xff1a; void solve(){int n;cin >> n;map<int,int>mp;for(int i 1;i < n;i ){int x;cin >> x;mp[x] …