From 63cca039c11997ec48e5c7b0c0c2a42e3b97809d Mon Sep 17 00:00:00 2001 From: SnailClimb Date: Tue, 26 Mar 2019 20:05:50 +0800 Subject: [PATCH] =?UTF-8?q?Update=20=E5=AF=B9=E7=AE=97=E6=B3=95=E9=83=A8?= =?UTF-8?q?=E5=88=86=E8=BF=9B=E8=A1=8C=E5=A4=A7=E5=B9=85=E5=BA=A6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source code/securityAlgorithm/.classpath | 26 - .../source code/securityAlgorithm/.gitignore | 1 - .../source code/securityAlgorithm/.project | 23 - .../org.eclipse.core.resources.prefs | 4 - .../.settings/org.eclipse.jdt.core.prefs | 5 - .../.settings/org.eclipse.m2e.core.prefs | 4 - .../source code/securityAlgorithm/pom.xml | 37 - .../ks/securityAlgorithm/Base64Demo.java | 49 - .../ks/securityAlgorithm/DesDemo.java | 100 --- .../ks/securityAlgorithm/IDEADemo.java | 46 - .../snailclimb/ks/securityAlgorithm/MD5.java | 160 ---- .../ks/securityAlgorithm/MD5Demo.java | 50 -- .../ks/securityAlgorithm/RSADemo.java | 249 ----- .../ks/securityAlgorithm/SHA1Demo.java | 45 - .../snailclimb/ks/securityAlgorithm/readme | 3 - .../ks/securityAlgorithm/AppTest.java | 38 - ...54\345\217\270\347\234\237\351\242\230.md" | 42 +- ...62\347\256\227\346\263\225\351\242\230.md" | 0 ...50\347\256\227\346\263\225\351\242\230.md" | 0 ...06\347\274\226\347\250\213\351\242\230.md" | 686 ++++++++++++++ ...11\357\274\211\346\200\273\347\273\223.md" | 849 ------------------ .../\347\256\227\346\263\225.md" | 90 -- ...04\346\272\220\346\216\250\350\215\220.md" | 52 ++ ...60\351\230\266\351\227\256\351\242\230.md" | 127 --- ...72\346\240\274\351\227\256\351\242\230.md" | 64 -- ...03\347\264\240\351\241\272\345\272\217.md" | 113 --- ...63\347\274\226\347\250\213\351\242\230.md" | 189 ---- ...71\345\207\272\345\272\217\345\210\227.md" | 111 --- 28 files changed, 758 insertions(+), 2405 deletions(-) delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/.classpath delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/.gitignore delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/.project delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.core.resources.prefs delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.jdt.core.prefs delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.m2e.core.prefs delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/pom.xml delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/Base64Demo.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/DesDemo.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/IDEADemo.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5Demo.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/RSADemo.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/SHA1Demo.java delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/readme delete mode 100644 docs/dataStructures-algorithms/source code/securityAlgorithm/src/test/java/com/snailclimb/ks/securityAlgorithm/AppTest.java rename "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md" => "docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md" (93%) rename "docs/dataStructures-algorithms/\346\220\236\345\256\232BAT\351\235\242\350\257\225\342\200\224\342\200\224\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" => "docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" (100%) rename docs/dataStructures-algorithms/Leetcode-LinkList1.md => "docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\351\223\276\350\241\250\347\256\227\346\263\225\351\242\230.md" (100%) create mode 100644 "docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md" delete mode 100644 "docs/dataStructures-algorithms/\345\270\270\350\247\201\345\256\211\345\205\250\347\256\227\346\263\225\357\274\210MD5\343\200\201SHA1\343\200\201Base64\347\255\211\347\255\211\357\274\211\346\200\273\347\273\223.md" delete mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225.md" create mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md" delete mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2101\357\274\211\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\351\227\256\351\242\230\345\222\214\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.md" delete mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2102\357\274\211\344\272\214\347\273\264\346\225\260\347\273\204\346\237\245\346\211\276\345\222\214\346\233\277\346\215\242\347\251\272\346\240\274\351\227\256\351\242\230.md" delete mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2103\357\274\211\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271\345\222\214\350\260\203\346\225\264\346\225\260\347\273\204\345\205\203\347\264\240\351\241\272\345\272\217.md" delete mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2104\357\274\211\351\223\276\350\241\250\347\233\270\345\205\263\347\274\226\347\250\213\351\242\230.md" delete mode 100644 "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2105\357\274\211\346\240\210\345\217\230\351\230\237\345\210\227\345\222\214\346\240\210\347\232\204\345\216\213\345\205\245\343\200\201\345\274\271\345\207\272\345\272\217\345\210\227.md" diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/.classpath b/docs/dataStructures-algorithms/source code/securityAlgorithm/.classpath deleted file mode 100644 index 0a1daddd..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/.classpath +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/.gitignore b/docs/dataStructures-algorithms/source code/securityAlgorithm/.gitignore deleted file mode 100644 index b83d2226..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/ diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/.project b/docs/dataStructures-algorithms/source code/securityAlgorithm/.project deleted file mode 100644 index 7b9c539d..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - securityAlgorithm - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.core.resources.prefs b/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index f9fe3459..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding//src/test/java=UTF-8 -encoding/=UTF-8 diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.jdt.core.prefs b/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index abec6ca3..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.m2e.core.prefs b/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f1..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/pom.xml b/docs/dataStructures-algorithms/source code/securityAlgorithm/pom.xml deleted file mode 100644 index 39d693b8..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - 4.0.0 - - com.snailclimb.ks - securityAlgorithm - 0.0.1-SNAPSHOT - jar - - securityAlgorithm - http://maven.apache.org - - - UTF-8 - - - - - junit - junit - 4.12 - test - - - - commons-codec - commons-codec - 1.8 - - - org.bouncycastle - bcprov-jdk15on - 1.56 - - - - diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/Base64Demo.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/Base64Demo.java deleted file mode 100644 index 1c6fd6df..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/Base64Demo.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import java.io.UnsupportedEncodingException; -import java.util.Base64; - -public class Base64Demo { - - public static void main(String[] args) throws UnsupportedEncodingException { - // TODO Auto-generated method stub - CommonsCodecDemo(); - bouncyCastleDemo(); - jdkDemo(); - } - - static String str = "你若安好,便是晴天"; - - /** - * commons codec实现Base64加密解密 - */ - public static void CommonsCodecDemo() { - // 加密: - byte[] encodeBytes = org.apache.commons.codec.binary.Base64.encodeBase64(str.getBytes()); - System.out.println("commons codec实现base64加密: " + new String(encodeBytes)); - // 解密: - byte[] decodeBytes = org.apache.commons.codec.binary.Base64.decodeBase64(encodeBytes); - System.out.println("commons codec实现base64解密: " + new String(decodeBytes)); - } - - /** - * bouncy castle实现Base64加密解密 - */ - public static void bouncyCastleDemo() { - // 加密 - byte[] encodeBytes = org.bouncycastle.util.encoders.Base64.encode(str.getBytes()); - System.out.println("bouncy castle实现base64加密: " + new String(encodeBytes)); - // 解密 - byte[] decodeBytes = org.bouncycastle.util.encoders.Base64.decode(encodeBytes); - System.out.println("bouncy castle实现base64解密:" + new String(decodeBytes)); - } - - public static void jdkDemo() throws UnsupportedEncodingException { - // 加密 - String encodeBytes = Base64.getEncoder().encodeToString(str.getBytes("UTF-8")); - System.out.println("JDK实现的base64加密: " + encodeBytes); - //解密 - byte[] decodeBytes = Base64.getDecoder().decode(encodeBytes.getBytes("UTF-8")); - System.out.println("JDK实现的base64解密: "+new String(decodeBytes)); - } -} diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/DesDemo.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/DesDemo.java deleted file mode 100644 index ce8b09ee..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/DesDemo.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import java.io.UnsupportedEncodingException; -import java.security.SecureRandom; -import javax.crypto.spec.DESKeySpec; -import javax.crypto.SecretKeyFactory; -import javax.crypto.SecretKey; -import javax.crypto.Cipher; - -/** - * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究, - * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力, - * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。 - * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数 - */ -public class DesDemo { - public DesDemo() { - } - - // 测试 - public static void main(String args[]) { - // 待加密内容 - String str = "cryptology"; - // 密码,长度要是8的倍数 - String password = "95880288"; - - byte[] result; - try { - result = DesDemo.encrypt(str.getBytes(), password); - System.out.println("加密后:" + result); - byte[] decryResult = DesDemo.decrypt(result, password); - System.out.println("解密后:" + decryResult); - } catch (UnsupportedEncodingException e2) { - // TODO Auto-generated catch block - e2.printStackTrace(); - } catch (Exception e1) { - e1.printStackTrace(); - } - } - - // 直接将如上内容解密 - - /** - * 加密 - * - * @param datasource - * byte[] - * @param password - * String - * @return byte[] - */ - public static byte[] encrypt(byte[] datasource, String password) { - try { - SecureRandom random = new SecureRandom(); - DESKeySpec desKey = new DESKeySpec(password.getBytes()); - // 创建一个密匙工厂,然后用它把DESKeySpec转换成 - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); - SecretKey securekey = keyFactory.generateSecret(desKey); - // Cipher对象实际完成加密操作 - Cipher cipher = Cipher.getInstance("DES"); - // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量 - cipher.init(Cipher.ENCRYPT_MODE, securekey, random); - // 现在,获取数据并加密 - // 正式执行加密操作 - return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作 - } catch (Throwable e) { - e.printStackTrace(); - } - return null; - } - - /** - * 解密 - * - * @param src - * byte[] - * @param password - * String - * @return byte[] - * @throws Exception - */ - public static byte[] decrypt(byte[] src, String password) throws Exception { - // DES算法要求有一个可信任的随机数源 - SecureRandom random = new SecureRandom(); - // 创建一个DESKeySpec对象 - DESKeySpec desKey = new DESKeySpec(password.getBytes()); - // 创建一个密匙工厂 - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的 - // Cipher - // 对象 - // 将DESKeySpec对象转换成SecretKey对象 - SecretKey securekey = keyFactory.generateSecret(desKey); - // Cipher对象实际完成解密操作 - Cipher cipher = Cipher.getInstance("DES"); - // 用密匙初始化Cipher对象 - cipher.init(Cipher.DECRYPT_MODE, securekey, random); - // 真正开始解密操作 - return cipher.doFinal(src); - } -} \ No newline at end of file diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/IDEADemo.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/IDEADemo.java deleted file mode 100644 index 5ce251df..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/IDEADemo.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import java.security.Key; -import java.security.Security; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Base64; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -public class IDEADemo { - public static void main(String args[]) { - bcIDEA(); - } - public static void bcIDEA() { - String src = "www.xttblog.com security idea"; - try { - Security.addProvider(new BouncyCastleProvider()); - - //生成key - KeyGenerator keyGenerator = KeyGenerator.getInstance("IDEA"); - keyGenerator.init(128); - SecretKey secretKey = keyGenerator.generateKey(); - byte[] keyBytes = secretKey.getEncoded(); - - //转换密钥 - Key key = new SecretKeySpec(keyBytes, "IDEA"); - - //加密 - Cipher cipher = Cipher.getInstance("IDEA/ECB/ISO10126Padding"); - cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] result = cipher.doFinal(src.getBytes()); - System.out.println("bc idea encrypt : " + Base64.encodeBase64String(result)); - - //解密 - cipher.init(Cipher.DECRYPT_MODE, key); - result = cipher.doFinal(result); - System.out.println("bc idea decrypt : " + new String(result)); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5.java deleted file mode 100644 index 2b8e31f8..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -public class MD5{ - /* - *四个链接变量 - */ - private final int A=0x67452301; - private final int B=0xefcdab89; - private final int C=0x98badcfe; - private final int D=0x10325476; - /* - *ABCD的临时变量 - */ - private int Atemp,Btemp,Ctemp,Dtemp; - - /* - *常量ti - *公式:floor(abs(sin(i+1))×(2pow32) - */ - private final int K[]={ - 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, - 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8, - 0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193, - 0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51, - 0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, - 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905, - 0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681, - 0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60, - 0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, - 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244, - 0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92, - 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314, - 0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391}; - /* - *向左位移数,计算方法未知 - */ - private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7, - 12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, - 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10, - 15,21,6,10,15,21,6,10,15,21,6,10,15,21}; - - - /* - *初始化函数 - */ - private void init(){ - Atemp=A; - Btemp=B; - Ctemp=C; - Dtemp=D; - } - /* - *移动一定位数 - */ - private int shift(int a,int s){ - return(a<>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位 - } - /* - *主循环 - */ - private void MainLoop(int M[]){ - int F,g; - int a=Atemp; - int b=Btemp; - int c=Ctemp; - int d=Dtemp; - for(int i = 0; i < 64; i ++){ - if(i<16){ - F=(b&c)|((~b)&d); - g=i; - }else if(i<32){ - F=(d&b)|((~d)&c); - g=(5*i+1)%16; - }else if(i<48){ - F=b^c^d; - g=(3*i+5)%16; - }else{ - F=c^(b|(~d)); - g=(7*i)%16; - } - int tmp=d; - d=c; - c=b; - b=b+shift(a+F+K[i]+M[g],s[i]); - a=tmp; - } - Atemp=a+Atemp; - Btemp=b+Btemp; - Ctemp=c+Ctemp; - Dtemp=d+Dtemp; - - } - /* - *填充函数 - *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64) - *填充方式为先加一个0,其它位补零 - *最后加上64位的原来长度 - */ - private int[] add(String str){ - int num=((str.length()+8)/64)+1;//以512位,64个字节为一组 - int strByte[]=new int[num*16];//64/4=16,所以有16个整数 - for(int i=0;i>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序 - } - strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1 - /* - *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位 - */ - strByte[num*16-2]=str.length()*8; - return strByte; - } - /* - *调用函数 - */ - public String getMD5(String source){ - init(); - int strByte[]=add(source); - for(int i=0;i>i*8)%(1<<8))&0xff)).replace(' ', '0'); - - } - return str; - } - /* - *单例 - */ - private static MD5 instance; - public static MD5 getInstance(){ - if(instance==null){ - instance=new MD5(); - } - return instance; - } - - private MD5(){}; - - public static void main(String[] args){ - String str=MD5.getInstance().getMD5("你若安好,便是晴天"); - System.out.println(str); - } -} \ No newline at end of file diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5Demo.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5Demo.java deleted file mode 100644 index 3a8635d1..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5Demo.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import java.security.MessageDigest; - -public class MD5Demo { - - // test - public static void main(String[] args) { - System.out.println(getMD5Code("你若安好,便是晴天")); - } - - private MD5Demo() { - } - - // md5加密 - public static String getMD5Code(String message) { - String md5Str = ""; - try { - //创建MD5算法消息摘要 - MessageDigest md = MessageDigest.getInstance("MD5"); - //生成的哈希值的字节数组 - byte[] md5Bytes = md.digest(message.getBytes()); - md5Str = bytes2Hex(md5Bytes); - }catch(Exception e) { - e.printStackTrace(); - } - return md5Str; - } - - // 2进制转16进制 - public static String bytes2Hex(byte[] bytes) { - StringBuffer result = new StringBuffer(); - int temp; - try { - for (int i = 0; i < bytes.length; i++) { - temp = bytes[i]; - if(temp < 0) { - temp += 256; - } - if (temp < 16) { - result.append("0"); - } - result.append(Integer.toHexString(temp)); - } - } catch (Exception e) { - e.printStackTrace(); - } - return result.toString(); - } -} diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/RSADemo.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/RSADemo.java deleted file mode 100644 index 5234028e..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/RSADemo.java +++ /dev/null @@ -1,249 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import org.apache.commons.codec.binary.Base64; - -import java.security.*; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.Cipher; - -/** - * Created by humf.需要依赖 commons-codec 包 - */ -public class RSADemo { - - public static void main(String[] args) throws Exception { - Map keyMap = initKey(); - String publicKey = getPublicKey(keyMap); - String privateKey = getPrivateKey(keyMap); - - System.out.println(keyMap); - System.out.println("-----------------------------------"); - System.out.println(publicKey); - System.out.println("-----------------------------------"); - System.out.println(privateKey); - System.out.println("-----------------------------------"); - byte[] encryptByPrivateKey = encryptByPrivateKey("123456".getBytes(), privateKey); - byte[] encryptByPublicKey = encryptByPublicKey("123456", publicKey); - System.out.println(encryptByPrivateKey); - System.out.println("-----------------------------------"); - System.out.println(encryptByPublicKey); - System.out.println("-----------------------------------"); - String sign = sign(encryptByPrivateKey, privateKey); - System.out.println(sign); - System.out.println("-----------------------------------"); - boolean verify = verify(encryptByPrivateKey, publicKey, sign); - System.out.println(verify); - System.out.println("-----------------------------------"); - byte[] decryptByPublicKey = decryptByPublicKey(encryptByPrivateKey, publicKey); - byte[] decryptByPrivateKey = decryptByPrivateKey(encryptByPublicKey, privateKey); - System.out.println(decryptByPublicKey); - System.out.println("-----------------------------------"); - System.out.println(decryptByPrivateKey); - - } - - public static final String KEY_ALGORITHM = "RSA"; - public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; - - private static final String PUBLIC_KEY = "RSAPublicKey"; - private static final String PRIVATE_KEY = "RSAPrivateKey"; - - public static byte[] decryptBASE64(String key) { - return Base64.decodeBase64(key); - } - - public static String encryptBASE64(byte[] bytes) { - return Base64.encodeBase64String(bytes); - } - - /** - * 用私钥对信息生成数字签名 - * - * @param data - * 加密数据 - * @param privateKey - * 私钥 - * @return - * @throws Exception - */ - public static String sign(byte[] data, String privateKey) throws Exception { - // 解密由base64编码的私钥 - byte[] keyBytes = decryptBASE64(privateKey); - // 构造PKCS8EncodedKeySpec对象 - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); - // KEY_ALGORITHM 指定的加密算法 - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - // 取私钥匙对象 - PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); - // 用私钥对信息生成数字签名 - Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); - signature.initSign(priKey); - signature.update(data); - return encryptBASE64(signature.sign()); - } - - /** - * 校验数字签名 - * - * @param data - * 加密数据 - * @param publicKey - * 公钥 - * @param sign - * 数字签名 - * @return 校验成功返回true 失败返回false - * @throws Exception - */ - public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { - // 解密由base64编码的公钥 - byte[] keyBytes = decryptBASE64(publicKey); - // 构造X509EncodedKeySpec对象 - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); - // KEY_ALGORITHM 指定的加密算法 - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - // 取公钥匙对象 - PublicKey pubKey = keyFactory.generatePublic(keySpec); - Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); - signature.initVerify(pubKey); - signature.update(data); - // 验证签名是否正常 - return signature.verify(decryptBASE64(sign)); - } - - public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { - // 对密钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得私钥 - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); - // 对数据解密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - return cipher.doFinal(data); - } - - /** - * 解密
- * 用私钥解密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] decryptByPrivateKey(String data, String key) throws Exception { - return decryptByPrivateKey(decryptBASE64(data), key); - } - - /** - * 解密
- * 用公钥解密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception { - // 对密钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得公钥 - X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key publicKey = keyFactory.generatePublic(x509KeySpec); - // 对数据解密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.DECRYPT_MODE, publicKey); - return cipher.doFinal(data); - } - - /** - * 加密
- * 用公钥加密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] encryptByPublicKey(String data, String key) throws Exception { - // 对公钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得公钥 - X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key publicKey = keyFactory.generatePublic(x509KeySpec); - // 对数据加密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - return cipher.doFinal(data.getBytes()); - } - - /** - * 加密
- * 用私钥加密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception { - // 对密钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得私钥 - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); - // 对数据加密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - return cipher.doFinal(data); - } - - /** - * 取得私钥 - * - * @param keyMap - * @return - * @throws Exception - */ - public static String getPrivateKey(Map keyMap) throws Exception { - Key key = (Key) keyMap.get(PRIVATE_KEY); - return encryptBASE64(key.getEncoded()); - } - - /** - * 取得公钥 - * - * @param keyMap - * @return - * @throws Exception - */ - public static String getPublicKey(Map keyMap) throws Exception { - Key key = keyMap.get(PUBLIC_KEY); - return encryptBASE64(key.getEncoded()); - } - - /** - * 初始化密钥 - * - * @return - * @throws Exception - */ - public static Map initKey() throws Exception { - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); - keyPairGen.initialize(1024); - KeyPair keyPair = keyPairGen.generateKeyPair(); - Map keyMap = new HashMap(2); - keyMap.put(PUBLIC_KEY, keyPair.getPublic());// 公钥 - keyMap.put(PRIVATE_KEY, keyPair.getPrivate());// 私钥 - return keyMap; - } - -} \ No newline at end of file diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/SHA1Demo.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/SHA1Demo.java deleted file mode 100644 index ab19e3d0..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/SHA1Demo.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class SHA1Demo { - - public static void main(String[] args) { - // TODO Auto-generated method stub - System.out.println(getSha1("你若安好,便是晴天")); - - } - - public static String getSha1(String str) { - if (null == str || 0 == str.length()) { - return null; - } - char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - try { - //创建SHA1算法消息摘要对象 - MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); - //使用指定的字节数组更新摘要。 - mdTemp.update(str.getBytes("UTF-8")); - //生成的哈希值的字节数组 - byte[] md = mdTemp.digest(); - //SHA1算法生成信息摘要关键过程 - int j = md.length; - char[] buf = new char[j * 2]; - int k = 0; - for (int i = 0; i < j; i++) { - byte byte0 = md[i]; - buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; - buf[k++] = hexDigits[byte0 & 0xf]; - } - return new String(buf); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - return "0"; - - } -} diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/readme b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/readme deleted file mode 100644 index 5c2d452d..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/readme +++ /dev/null @@ -1,3 +0,0 @@ -Des算法参考:http://blog.csdn.net/super_cui/article/details/70820983 -IDEA算法参考:https://www.xttblog.com/?p=1121 -RSA算法实现参考:https://www.cnblogs.com/xlhan/p/7120488.html \ No newline at end of file diff --git a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/test/java/com/snailclimb/ks/securityAlgorithm/AppTest.java b/docs/dataStructures-algorithms/source code/securityAlgorithm/src/test/java/com/snailclimb/ks/securityAlgorithm/AppTest.java deleted file mode 100644 index 93225451..00000000 --- a/docs/dataStructures-algorithms/source code/securityAlgorithm/src/test/java/com/snailclimb/ks/securityAlgorithm/AppTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.snailclimb.ks.securityAlgorithm; - -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Unit test for simple App. - */ -public class AppTest - extends TestCase -{ - /** - * Create the test case - * - * @param testName name of the test case - */ - public AppTest( String testName ) - { - super( testName ); - } - - /** - * @return the suite of tests being tested - */ - public static Test suite() - { - return new TestSuite( AppTest.class ); - } - - /** - * Rigourous Test :-) - */ - public void testApp() - { - assertTrue( true ); - } -} diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md" "b/docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md" similarity index 93% rename from "docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md" rename to "docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md" index d929d200..c78ed8f3 100644 --- "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md" +++ "b/docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md" @@ -1,9 +1,10 @@ +# 网易 2018 + 下面三道编程题来自网易2018校招编程题,这三道应该来说是非常简单的编程题了,这些题目大家稍微有点编程和数学基础的话应该没什么问题。看答案之前一定要自己先想一下如果是自己做的话会怎么去做,然后再对照这我的答案看看,和你自己想的有什么区别?那一种方法更好? -![问题](https://user-gold-cdn.xitu.io/2018/7/7/1647557d5a1474d7?w=1024&h=1024&f=jpeg&s=638271) -> # 问题 +## 问题 -## 一 获得特定数量硬币问题 +### 一 获得特定数量硬币问题 小易准备去魔法王国采购魔法神器,购买魔法神器需要使用魔法币,但是小易现在一枚魔法币都没有,但是小易有两台魔法机器可以通过投入x(x可以为0)个魔法币产生更多的魔法币。 @@ -15,33 +16,30 @@ **输入描述:** 输入包括一行,包括一个正整数n(1 ≤ n ≤ 10^9),表示小易需要的魔法币数量。 - **输出描述:** 输出一个字符串,每个字符表示该次小易选取投入的魔法机器。其中只包含字符'1'和'2'。 **输入例子1:** 10 **输出例子1:** 122 -## 二 求“相反数”问题 +### 二 求“相反数”问题 为了得到一个数的"相反数",我们将这个数的数字顺序颠倒,然后再加上原先的数得到"相反数"。例如,为了得到1325的"相反数",首先我们将该数的数字顺序颠倒,我们得到5231,之后再加上原先的数,我们得到5231+1325=6556.如果颠倒之后的数字有前缀零,前缀零将会被忽略。例如n = 100, 颠倒之后是1. **输入描述:** 输入包括一个整数n,(1 ≤ n ≤ 10^5) - **输出描述:** 输出一个整数,表示n的相反数 **输入例子1:** 1325 **输出例子1:** 6556 -## 三 字符串碎片的平均长度 +### 三 字符串碎片的平均长度 一个由小写字母组成的字符串可以看成一些同一字母的最大碎片组成的。例如,"aaabbaaac"是由下面碎片组成的:'aaa','bb','c'。牛牛现在给定一个字符串,请你帮助计算这个字符串的所有碎片的平均长度是多少。 **输入描述:** 输入包括一个字符串s,字符串s的长度length(1 ≤ length ≤ 50),s只含小写字母('a'-'z') - **输出描述:** 输出一个整数,表示所有碎片的平均长度,四舍五入保留两位小数。 **如样例所示:** s = "aaabbaaac" @@ -51,19 +49,18 @@ **输出例子1:** 2.25 -![答案](https://user-gold-cdn.xitu.io/2018/7/7/16475582faddc9b2?w=1024&h=1024&f=jpeg&s=531663) - -> # 答案 +## 答案 -## 一 获得特定数量硬币问题 +### 一 获得特定数量硬币问题 -### 分析: +#### 分析: 作为该试卷的第一题,这道题应该只要思路正确就很简单了。 解题关键:明确魔法机器1只能产生奇数,魔法机器2只能产生偶数即可。我们从后往前一步一步推回去即可。 -### 示例代码 +#### 示例代码 + 注意:由于用户的输入不确定性,一般是为了程序高可用性使需要将捕获用户输入异常然后友好提示用户输入类型错误并重新输入的。所以下面我给了两个版本,这两个版本都是正确的。这里只是给大家演示如何捕获输入类型异常,后面的题目中我给的代码没有异常处理的部分,参照下面两个示例代码,应该很容易添加。(PS:企业面试中没有明确就不用添加异常处理,当然你有的话也更好) **不带输入异常处理判断的版本:** @@ -141,32 +138,33 @@ public class Main { ``` +### 二 求“相反数”问题 -## 二 求“相反数”问题 - -### 分析: +#### 分析: 解决本道题有几种不同的方法,但是最快速的方法就是利用reverse()方法反转字符串然后再将字符串转换成int类型的整数,这个方法是快速解决本题关键。我们先来回顾一下下面两个知识点: **1)String转int;** 在 Java 中要将 String 类型转化为 int 类型时,需要使用 Integer 类中的 parseInt() 方法或者 valueOf() 方法进行转换. + ```java String str = "123"; int a = Integer.parseInt(str); ``` + 或 + ```java String str = "123"; int a = Integer.valueOf(str).intValue(); ``` - **2)next()和nextLine()的区别** 在Java中输入字符串有两种方法,就是next()和nextLine().两者的区别就是:nextLine()的输入是碰到回车就终止输入,而next()方法是碰到空格,回车,Tab键都会被视为终止符。所以next()不会得到带空格的字符串,而nextLine()可以得到带空格的字符串。 -### 示例代码: +#### 示例代码: ```java import java.util.Scanner; @@ -192,15 +190,15 @@ public class Main { } ``` -## 三 字符串碎片的平均长度 +### 三 字符串碎片的平均长度 -### 分析: +#### 分析: 这道题的意思也就是要求:(字符串的总长度)/(相同字母团构成的字符串的个数)。 这样就很简单了,就变成了字符串的字符之间的比较。如果需要比较字符串的字符的话,我们可以利用charAt(i)方法:取出特定位置的字符与后一个字符比较,或者利用toCharArray()方法将字符串转换成字符数组采用同样的方法做比较。 -### 示例代码 +#### 示例代码 **利用charAt(i)方法:** diff --git "a/docs/dataStructures-algorithms/\346\220\236\345\256\232BAT\351\235\242\350\257\225\342\200\224\342\200\224\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" "b/docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" similarity index 100% rename from "docs/dataStructures-algorithms/\346\220\236\345\256\232BAT\351\235\242\350\257\225\342\200\224\342\200\224\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" rename to "docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" diff --git a/docs/dataStructures-algorithms/Leetcode-LinkList1.md "b/docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\351\223\276\350\241\250\347\256\227\346\263\225\351\242\230.md" similarity index 100% rename from docs/dataStructures-algorithms/Leetcode-LinkList1.md rename to "docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\351\223\276\350\241\250\347\256\227\346\263\225\351\242\230.md" diff --git "a/docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md" "b/docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md" new file mode 100644 index 00000000..51de35ea --- /dev/null +++ "b/docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md" @@ -0,0 +1,686 @@ +### 一 斐波那契数列 + +#### **题目描述:** + +大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。 +n<=39 + +#### **问题分析:** + +可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有一个很大的问题,那就是递归大量的重复计算会导致内存溢出。另外可以使用迭代法,用fn1和fn2保存计算过程中的结果,并复用起来。下面我会把两个方法示例代码都给出来并给出两个方法的运行时间对比。 + +#### **示例代码:** + +**采用迭代法:** + +```java + int Fibonacci(int number) { + if (number <= 0) { + return 0; + } + if (number == 1 || number == 2) { + return 1; + } + int first = 1, second = 1, third = 0; + for (int i = 3; i <= number; i++) { + third = first + second; + first = second; + second = third; + } + return third; + } +``` + +**采用递归:** + +```java + public int Fibonacci(int n) { + + if (n <= 0) { + return 0; + } + if (n == 1||n==2) { + return 1; + } + + return Fibonacci(n - 2) + Fibonacci(n - 1); + + } +``` + +#### **运行时间对比:** + +假设n为40我们分别使用迭代法和递归法计算,计算结果如下: + +1. 迭代法 + ![迭代法](https://ws1.sinaimg.cn/large/006rNwoDgy1fpydt5as85j308a025dfl.jpg) +2. 递归法 + ![递归法](https://ws1.sinaimg.cn/large/006rNwoDgy1fpydt2d1k3j30ed02kt8i.jpg) + +### 二 跳台阶问题 + +#### **题目描述:** + +一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 + +#### **问题分析:** + +**正常分析法:** +a.如果两种跳法,1阶或者2阶,那么假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1); +b.假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2) +c.由a,b假设可以得出总跳法为: f(n) = f(n-1) + f(n-2) +d.然后通过实际的情况可以得出:只有一阶的时候 f(1) = 1 ,只有两阶的时候可以有 f(2) = 2 +**找规律分析法:** +f(1) = 1, f(2) = 2, f(3) = 3, f(4) = 5, 可以总结出f(n) = f(n-1) + f(n-2)的规律。 +但是为什么会出现这样的规律呢?假设现在6个台阶,我们可以从第5跳一步到6,这样的话有多少种方案跳到5就有多少种方案跳到6,另外我们也可以从4跳两步跳到6,跳到4有多少种方案的话,就有多少种方案跳到6,其他的不能从3跳到6什么的啦,所以最后就是f(6) = f(5) + f(4);这样子也很好理解变态跳台阶的问题了。 + +**所以这道题其实就是斐波那契数列的问题。** +代码只需要在上一题的代码稍做修改即可。和上一题唯一不同的就是这一题的初始元素变为 1 2 3 5 8.....而上一题为1 1 2 3 5 .......。另外这一题也可以用递归做,但是递归效率太低,所以我这里只给出了迭代方式的代码。 + +#### **示例代码:** + +```java + int jumpFloor(int number) { + if (number <= 0) { + return 0; + } + if (number == 1) { + return 1; + } + if (number == 2) { + return 2; + } + int first = 1, second = 2, third = 0; + for (int i = 3; i <= number; i++) { + third = first + second; + first = second; + second = third; + } + return third; + } +``` + +### 三 变态跳台阶问题 + +#### **题目描述:** + +一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 + +#### **问题分析:** + +假设n>=2,第一步有n种跳法:跳1级、跳2级、到跳n级 +跳1级,剩下n-1级,则剩下跳法是f(n-1) +跳2级,剩下n-2级,则剩下跳法是f(n-2) +...... +跳n-1级,剩下1级,则剩下跳法是f(1) +跳n级,剩下0级,则剩下跳法是f(0) +所以在n>=2的情况下: +f(n)=f(n-1)+f(n-2)+...+f(1) +因为f(n-1)=f(n-2)+f(n-3)+...+f(1) +所以f(n)=2*f(n-1) 又f(1)=1,所以可得**f(n)=2^(number-1)** + +#### **示例代码:** + +```java + int JumpFloorII(int number) { + return 1 << --number;//2^(number-1)用位移操作进行,更快 + } +``` + +#### **补充:** + +**java中有三种移位运算符:** + +1. “<<” : **左移运算符**,等同于乘2的n次方 +2. “>>”: **右移运算符**,等同于除2的n次方 +3. “>>>” **无符号右移运算符**,不管移动前最高位是0还是1,右移后左侧产生的空位部分都以0来填充。与>>类似。 + 例: + int a = 16; + int b = a << 2;//左移2,等同于16 * 2的2次方,也就是16 * 4 + int c = a >> 2;//右移2,等同于16 / 2的2次方,也就是16 / 4 + +### 四 二维数组查找 + +#### **题目描述:** + +在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 + +#### **问题解析:** + +这一道题还是比较简单的,我们需要考虑的是如何做,效率最快。这里有一种很好理解的思路: + +> 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增, +> 因此从左下角开始查找,当要查找数字比左下角数字大时。右移 +> 要查找数字比左下角数字小时,上移。这样找的速度最快。 + +#### **示例代码:** + +```java + public boolean Find(int target, int [][] array) { + //基本思路从左下角开始找,这样速度最快 + int row = array.length-1;//行 + int column = 0;//列 + //当行数大于0,当前列数小于总列数时循环条件成立 + while((row >= 0)&& (column< array[0].length)){ + if(array[row][column] > target){ + row--; + }else if(array[row][column] < target){ + column++; + }else{ + return true; + } + } + return false; + } +``` + +### 五 替换空格 + +#### **题目描述:** + +请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 + +#### **问题分析:** + +这道题不难,我们可以通过循环判断字符串的字符是否为空格,是的话就利用append()方法添加追加“%20”,否则还是追加原字符。 + +或者最简单的方法就是利用: replaceAll(String regex,String replacement)方法了,一行代码就可以解决。 + +#### **示例代码:** + +**常规做法:** + +```java + public String replaceSpace(StringBuffer str) { + StringBuffer out=new StringBuffer(); + for (int i = 0; i < str.toString().length(); i++) { + char b=str.charAt(i); + if(String.valueOf(b).equals(" ")){ + out.append("%20"); + }else{ + out.append(b); + } + } + return out.toString(); + } +``` + +**一行代码解决:** + +```java + public String replaceSpace(StringBuffer str) { + //return str.toString().replaceAll(" ", "%20"); + //public String replaceAll(String regex,String replacement) + //用给定的替换替换与给定的regular expression匹配的此字符串的每个子字符串。 + //\ 转义字符. 如果你要使用 "\" 本身, 则应该使用 "\\". String类型中的空格用“\s”表示,所以我这里猜测"\\s"就是代表空格的意思 + return str.toString().replaceAll("\\s", "%20"); + } + +``` + +### 六 数值的整数次方 + +#### **题目描述:** + +给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 + +#### **问题解析:** + +这道题算是比较麻烦和难一点的一个了。我这里采用的是**二分幂**思想,当然也可以采用**快速幂**。 +更具剑指offer书中细节,该题的解题思路如下: +1.当底数为0且指数<0时,会出现对0求倒数的情况,需进行错误处理,设置一个全局变量; +2.判断底数是否等于0,由于base为double型,所以不能直接用==判断 +3.优化求幂函数(二分幂)。 +当n为偶数,a^n =(a^n/2)*(a^n/2); +当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a。时间复杂度O(logn) + +**时间复杂度**:O(logn) + +#### **示例代码:** + +```java +public class Solution { + boolean invalidInput=false; + public double Power(double base, int exponent) { + //如果底数等于0并且指数小于0 + //由于base为double型,不能直接用==判断 + if(equal(base,0.0)&&exponent<0){ + invalidInput=true; + return 0.0; + } + int absexponent=exponent; + //如果指数小于0,将指数转正 + if(exponent<0) + absexponent=-exponent; + //getPower方法求出base的exponent次方。 + double res=getPower(base,absexponent); + //如果指数小于0,所得结果为上面求的结果的倒数 + if(exponent<0) + res=1.0/res; + return res; + } + //比较两个double型变量是否相等的方法 + boolean equal(double num1,double num2){ + if(num1-num2>-0.000001&&num1-num2<0.000001) + return true; + else + return false; + } + //求出b的e次方的方法 + double getPower(double b,int e){ + //如果指数为0,返回1 + if(e==0) + return 1.0; + //如果指数为1,返回b + if(e==1) + return b; + //e>>1相等于e/2,这里就是求a^n =(a^n/2)*(a^n/2) + double result=getPower(b,e>>1); + result*=result; + //如果指数n为奇数,则要再乘一次底数base + if((e&1)==1) + result*=b; + return result; + } +} +``` + +当然这一题也可以采用笨方法:累乘。不过这种方法的时间复杂度为O(n),这样没有前一种方法效率高。 + +```java + // 使用累乘 + public double powerAnother(double base, int exponent) { + double result = 1.0; + for (int i = 0; i < Math.abs(exponent); i++) { + result *= base; + } + if (exponent >= 0) + return result; + else + return 1 / result; + } +``` + +### 七 调整数组顺序使奇数位于偶数前面 + +#### **题目描述:** + +输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 + +#### **问题解析:** + +这道题有挺多种解法的,给大家介绍一种我觉得挺好理解的方法: +我们首先统计奇数的个数假设为n,然后新建一个等长数组,然后通过循环判断原数组中的元素为偶数还是奇数。如果是则从数组下标0的元素开始,把该奇数添加到新数组;如果是偶数则从数组下标为n的元素开始把该偶数添加到新数组中。 + +#### **示例代码:** + +时间复杂度为O(n),空间复杂度为O(n)的算法 + +```java +public class Solution { + public void reOrderArray(int [] array) { + //如果数组长度等于0或者等于1,什么都不做直接返回 + if(array.length==0||array.length==1) + return; + //oddCount:保存奇数个数 + //oddBegin:奇数从数组头部开始添加 + int oddCount=0,oddBegin=0; + //新建一个数组 + int[] newArray=new int[array.length]; + //计算出(数组中的奇数个数)开始添加元素 + for(int i=0;i stack1 = new Stack(); + Stack stack2 = new Stack(); + + //当执行push操作时,将元素添加到stack1 + public void push(int node) { + stack1.push(node); + } + + public int pop() { + //如果两个队列都为空则抛出异常,说明用户没有push进任何元素 + if(stack1.empty()&&stack2.empty()){ + throw new RuntimeException("Queue is empty!"); + } + //如果stack2不为空直接对stack2执行pop操作, + if(stack2.empty()){ + while(!stack1.empty()){ + //将stack1的元素按后进先出push进stack2里面 + stack2.push(stack1.pop()); + } + } + return stack2.pop(); + } +} +``` + +### 十二 栈的压入,弹出序列 + +#### **题目描述:** + +输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) + +#### **题目分析:** + +这道题想了半天没有思路,参考了Alias的答案,他的思路写的也很详细应该很容易看懂。 +作者:Alias +https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106 +来源:牛客网 + +【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。 + +举例: + +入栈1,2,3,4,5 + +出栈4,5,3,2,1 + +首先1入辅助栈,此时栈顶1≠4,继续入栈2 + +此时栈顶2≠4,继续入栈3 + +此时栈顶3≠4,继续入栈4 + +此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3 + +此时栈顶3≠5,继续入栈5 + +此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3 + +…. +依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。 + + + +#### **考察内容:** + +栈 + +#### **示例代码:** + +```java +import java.util.ArrayList; +import java.util.Stack; +//这道题没想出来,参考了Alias同学的答案:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106 +public class Solution { + public boolean IsPopOrder(int [] pushA,int [] popA) { + if(pushA.length == 0 || popA.length == 0) + return false; + Stack s = new Stack(); + //用于标识弹出序列的位置 + int popIndex = 0; + for(int i = 0; i< pushA.length;i++){ + s.push(pushA[i]); + //如果栈不为空,且栈顶元素等于弹出序列 + while(!s.empty() &&s.peek() == popA[popIndex]){ + //出栈 + s.pop(); + //弹出序列向后一位 + popIndex++; + } + } + return s.empty(); + } +} +``` \ No newline at end of file diff --git "a/docs/dataStructures-algorithms/\345\270\270\350\247\201\345\256\211\345\205\250\347\256\227\346\263\225\357\274\210MD5\343\200\201SHA1\343\200\201Base64\347\255\211\347\255\211\357\274\211\346\200\273\347\273\223.md" "b/docs/dataStructures-algorithms/\345\270\270\350\247\201\345\256\211\345\205\250\347\256\227\346\263\225\357\274\210MD5\343\200\201SHA1\343\200\201Base64\347\255\211\347\255\211\357\274\211\346\200\273\347\273\223.md" deleted file mode 100644 index 8dddb1b9..00000000 --- "a/docs/dataStructures-algorithms/\345\270\270\350\247\201\345\256\211\345\205\250\347\256\227\346\263\225\357\274\210MD5\343\200\201SHA1\343\200\201Base64\347\255\211\347\255\211\357\274\211\346\200\273\347\273\223.md" +++ /dev/null @@ -1,849 +0,0 @@ -本文主要对消息摘要算法和加密算法做了整理,包括MD5、SHA、DES、AES、RSA等,并且提供了相应算法的Java实现和测试。 - -# 一 消息摘要算法 - -## **1. 简介:** - -- **消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密** -- **只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。** -- **消息摘要算法主要应用在“数字签名”领域,作为对明文的摘要算法。** -- **著名的摘要算法有RSA公司的MD5算法和SHA-1算法及其大量的变体**。 - -## **2. 特点:** - -1. **无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。** -2. **消息摘要看起来是“伪随机的”。也就是说对相同的信息求摘要结果相同。** -3. **消息轻微改变生成的摘要变化会很大** -4. **只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息** - -## **3. 应用:** - -消息摘要算法最常用的场景就是数字签名以及数据(密码)加密了。(一般平时做项目用的比较多的就是使用MD5对用户密码进行加密) - -## **4. 何谓数字签名:** - -数字签名主要用到了非对称密钥加密技术与数字摘要技术。数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。 -如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过. - -因此数字签名能够验证信息的完整性。 -数字签名是个加密的过程,数字签名验证是个解密的过程。 - -## **5. 常见消息/数字摘要算法:** - -### [**MD5:**](https://baike.baidu.com/item/MD5/212708?fr=aladdin) - -#### 简介: - -MD5的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式 - (也就是把一个任意长度的字节串变换成一定长的十六进制数字串)。 - -#### 特点: - -1. **压缩性:** 任意长度的数据,算出的MD5值长度都是固定的。 -2. **容易计算:** 从原数据计算出MD5值很容易。 -3. **抗修改性:** 对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。 -4. **强抗碰撞:** 已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。 - -#### 代码实现: - -**利用JDK提供java.security.MessageDigest类实现MD5算法:** - -```java -package com.snailclimb.ks.securityAlgorithm; - -import java.security.MessageDigest; - -public class MD5Demo { - - // test - public static void main(String[] args) { - System.out.println(getMD5Code("你若安好,便是晴天")); - } - - private MD5Demo() { - } - - // md5加密 - public static String getMD5Code(String message) { - String md5Str = ""; - try { - //创建MD5算法消息摘要 - MessageDigest md = MessageDigest.getInstance("MD5"); - //生成的哈希值的字节数组 - byte[] md5Bytes = md.digest(message.getBytes()); - md5Str = bytes2Hex(md5Bytes); - }catch(Exception e) { - e.printStackTrace(); - } - return md5Str; - } - - // 2进制转16进制 - public static String bytes2Hex(byte[] bytes) { - StringBuffer result = new StringBuffer(); - int temp; - try { - for (int i = 0; i < bytes.length; i++) { - temp = bytes[i]; - if(temp < 0) { - temp += 256; - } - if (temp < 16) { - result.append("0"); - } - result.append(Integer.toHexString(temp)); - } - } catch (Exception e) { - e.printStackTrace(); - } - return result.toString(); - } -} - -``` - -**结果:** -``` -6bab82679914f7cb480a120b532ffa80 - -``` - -**注意MessageDigest类的几个方法:** - -```java -static MessageDigest getInstance(String algorithm)//返回实现指定摘要算法的MessageDigest对象 -``` -```java -byte[] digest(byte[] input)//使用指定的字节数组对摘要执行最终更新,然后完成摘要计算。 -``` - -#### 不利用Java提供的java.security.MessageDigest类实现MD5算法: - -```java -package com.snailclimb.ks.securityAlgorithm; - -public class MD5{ - /* - *四个链接变量 - */ - private final int A=0x67452301; - private final int B=0xefcdab89; - private final int C=0x98badcfe; - private final int D=0x10325476; - /* - *ABCD的临时变量 - */ - private int Atemp,Btemp,Ctemp,Dtemp; - - /* - *常量ti - *公式:floor(abs(sin(i+1))×(2pow32) - */ - private final int K[]={ - 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, - 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8, - 0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193, - 0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51, - 0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, - 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905, - 0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681, - 0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60, - 0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, - 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244, - 0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92, - 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314, - 0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391}; - /* - *向左位移数,计算方法未知 - */ - private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7, - 12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, - 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10, - 15,21,6,10,15,21,6,10,15,21,6,10,15,21}; - - - /* - *初始化函数 - */ - private void init(){ - Atemp=A; - Btemp=B; - Ctemp=C; - Dtemp=D; - } - /* - *移动一定位数 - */ - private int shift(int a,int s){ - return(a<>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位 - } - /* - *主循环 - */ - private void MainLoop(int M[]){ - int F,g; - int a=Atemp; - int b=Btemp; - int c=Ctemp; - int d=Dtemp; - for(int i = 0; i < 64; i ++){ - if(i<16){ - F=(b&c)|((~b)&d); - g=i; - }else if(i<32){ - F=(d&b)|((~d)&c); - g=(5*i+1)%16; - }else if(i<48){ - F=b^c^d; - g=(3*i+5)%16; - }else{ - F=c^(b|(~d)); - g=(7*i)%16; - } - int tmp=d; - d=c; - c=b; - b=b+shift(a+F+K[i]+M[g],s[i]); - a=tmp; - } - Atemp=a+Atemp; - Btemp=b+Btemp; - Ctemp=c+Ctemp; - Dtemp=d+Dtemp; - - } - /* - *填充函数 - *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64) - *填充方式为先加一个0,其它位补零 - *最后加上64位的原来长度 - */ - private int[] add(String str){ - int num=((str.length()+8)/64)+1;//以512位,64个字节为一组 - int strByte[]=new int[num*16];//64/4=16,所以有16个整数 - for(int i=0;i>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序 - } - strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1 - /* - *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位 - */ - strByte[num*16-2]=str.length()*8; - return strByte; - } - /* - *调用函数 - */ - public String getMD5(String source){ - init(); - int strByte[]=add(source); - for(int i=0;i>i*8)%(1<<8))&0xff)).replace(' ', '0'); - - } - return str; - } - /* - *单例 - */ - private static MD5 instance; - public static MD5 getInstance(){ - if(instance==null){ - instance=new MD5(); - } - return instance; - } - - private MD5(){}; - - public static void main(String[] args){ - String str=MD5.getInstance().getMD5("你若安好,便是晴天"); - System.out.println(str); - } -} -``` - -### [**SHA1:**](https://baike.baidu.com/item/MD5/212708?fr=aladdin) -对于长度小于2^64位的消息,SHA1会产生一个160位(40个字符)的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。 - -SHA1有如下特性: - -- 不可以从消息摘要中复原信息; -- 两个不同的消息不会产生同样的消息摘要,(但会有1x10 ^ 48分之一的机率出现相同的消息摘要,一般使用时忽略)。 - -#### 代码实现: - -**利用JDK提供java.security.MessageDigest类实现SHA1算法:* - -```java -package com.snailclimb.ks.securityAlgorithm; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class SHA1Demo { - - public static void main(String[] args) { - // TODO Auto-generated method stub - System.out.println(getSha1("你若安好,便是晴天")); - - } - - public static String getSha1(String str) { - if (null == str || 0 == str.length()) { - return null; - } - char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - try { - //创建SHA1算法消息摘要对象 - MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); - //使用指定的字节数组更新摘要。 - mdTemp.update(str.getBytes("UTF-8")); - //生成的哈希值的字节数组 - byte[] md = mdTemp.digest(); - //SHA1算法生成信息摘要关键过程 - int j = md.length; - char[] buf = new char[j * 2]; - int k = 0; - for (int i = 0; i < j; i++) { - byte byte0 = md[i]; - buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; - buf[k++] = hexDigits[byte0 & 0xf]; - } - return new String(buf); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - return "0"; - - } -} - -``` - -**结果:** - -``` -8ce764110a42da9b08504b20e26b19c9e3382414 -``` - - - -# 二 加密算法 - -## **1. 简介:** - -- **加密技术包括两个元素:加密算法和密钥。** -- **加密算法是将普通的文本(或者可以理解的信息)与一串数字(密钥)的结合,产生不可理解的密文的步骤。** -- **密钥是用来对数据进行编码和解码的一种算法。** -- **在安全保密中,可通过适当的密钥加密技术和管理机制来保证网络的信息通讯安全。** - -## **2. 分类:** - -**密钥加密技术的密码体制分为对称密钥体制和非对称密钥体制两种。相应地,对数据加密的技术分为两类,即对称加密(私人密钥加密)和非对称加密(公开密钥加密)。** - -**对称加密以数据加密标准(DES,Data Encryption Standard)算法为典型代表,非对称加密通常以RSA(Rivest Shamir Adleman)算法为代表。** - -**对称加密的加密密钥和解密密钥相同。非对称加密的加密密钥和解密密钥不同,加密密钥可以公开而解密密钥需要保密** -## **3. 应用:** - -常被用在电子商务或者其他需要保证网络传输安全的范围。 - -## **4. 对称加密:** - -加密密钥和解密密钥相同的加密算法。 - -对称加密算法使用起来简单快捷,密钥较短,且破译困难,除了数据加密标准(DES), -另一个对称密钥加密系统是国际数据加密算法(IDEA),它比DES的加密性好,而且对计算机功能要求也没有那么高。IDEA加密标准由PGP(Pretty Good Privacy)系统使用。 -### [**DES:**](https://baike.baidu.com/item/DES) - -DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,现在已经过时。 - -#### 代码实现: - -DES算法实现 : - -```java -package com.snailclimb.ks.securityAlgorithm; - -import java.io.UnsupportedEncodingException; -import java.security.SecureRandom; -import javax.crypto.spec.DESKeySpec; -import javax.crypto.SecretKeyFactory; -import javax.crypto.SecretKey; -import javax.crypto.Cipher; - -/** - * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究, - * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力, - * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。 - * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数 - */ -public class DesDemo { - public DesDemo() { - } - - // 测试 - public static void main(String args[]) { - // 待加密内容 - String str = "cryptology"; - // 密码,长度要是8的倍数 - String password = "95880288"; - - byte[] result; - try { - result = DesDemo.encrypt(str.getBytes(), password); - System.out.println("加密后:" + result); - byte[] decryResult = DesDemo.decrypt(result, password); - System.out.println("解密后:" + new String(decryResult)); - } catch (UnsupportedEncodingException e2) { - // TODO Auto-generated catch block - e2.printStackTrace(); - } catch (Exception e1) { - e1.printStackTrace(); - } - } - - // 直接将如上内容解密 - - /** - * 加密 - * - * @param datasource - * byte[] - * @param password - * String - * @return byte[] - */ - public static byte[] encrypt(byte[] datasource, String password) { - try { - SecureRandom random = new SecureRandom(); - DESKeySpec desKey = new DESKeySpec(password.getBytes()); - // 创建一个密匙工厂,然后用它把DESKeySpec转换成 - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); - SecretKey securekey = keyFactory.generateSecret(desKey); - // Cipher对象实际完成加密操作 - Cipher cipher = Cipher.getInstance("DES"); - // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量 - cipher.init(Cipher.ENCRYPT_MODE, securekey, random); - // 现在,获取数据并加密 - // 正式执行加密操作 - return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作 - } catch (Throwable e) { - e.printStackTrace(); - } - return null; - } - - /** - * 解密 - * - * @param src - * byte[] - * @param password - * String - * @return byte[] - * @throws Exception - */ - public static byte[] decrypt(byte[] src, String password) throws Exception { - // DES算法要求有一个可信任的随机数源 - SecureRandom random = new SecureRandom(); - // 创建一个DESKeySpec对象 - DESKeySpec desKey = new DESKeySpec(password.getBytes()); - // 创建一个密匙工厂 - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的 - // Cipher - // 对象 - // 将DESKeySpec对象转换成SecretKey对象 - SecretKey securekey = keyFactory.generateSecret(desKey); - // Cipher对象实际完成解密操作 - Cipher cipher = Cipher.getInstance("DES"); - // 用密匙初始化Cipher对象 - cipher.init(Cipher.DECRYPT_MODE, securekey, random); - // 真正开始解密操作 - return cipher.doFinal(src); - } -} -``` - -结果: - -``` -加密后:[B@50cbc42f -解密后:cryptology -``` - -### [**IDEA:**](https://baike.baidu.com/item/%E5%9B%BD%E9%99%85%E6%95%B0%E6%8D%AE%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/11048972?fr=aladdin) - -- **这种算法是在DES算法的基础上发展出来的,类似于三重DES。** -- **发展IDEA也是因为感到DES具有密钥太短等缺点。** -- **IDEA的密钥为128位,这么长的密钥在今后若干年内应该是安全的。** -- **在实际项目中用到的很少了解即可。** - -#### 代码实现: - -IDEA算法实现 - -```java -package com.snailclimb.ks.securityAlgorithm; - -import java.security.Key; -import java.security.Security; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.codec.binary.Base64; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -public class IDEADemo { - public static void main(String args[]) { - bcIDEA(); - } - public static void bcIDEA() { - String src = "www.xttblog.com security idea"; - try { - Security.addProvider(new BouncyCastleProvider()); - - //生成key - KeyGenerator keyGenerator = KeyGenerator.getInstance("IDEA"); - keyGenerator.init(128); - SecretKey secretKey = keyGenerator.generateKey(); - byte[] keyBytes = secretKey.getEncoded(); - - //转换密钥 - Key key = new SecretKeySpec(keyBytes, "IDEA"); - - //加密 - Cipher cipher = Cipher.getInstance("IDEA/ECB/ISO10126Padding"); - cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] result = cipher.doFinal(src.getBytes()); - System.out.println("bc idea encrypt : " + Base64.encodeBase64String(result)); - - //解密 - cipher.init(Cipher.DECRYPT_MODE, key); - result = cipher.doFinal(result); - System.out.println("bc idea decrypt : " + new String(result)); - } catch (Exception e) { - e.printStackTrace(); - } - } -} - -``` - -## **5. 非对称加密:** - -- 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥 (privatekey)。 -- 公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密; -- 如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。 -- 因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 -### [**RAS:**](https://baike.baidu.com/item/DES) - -RSA是目前最有影响力和最常用的公钥加密算法。它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。 - -#### 代码实现: - -RAS算法实现: - -```java -package com.snailclimb.ks.securityAlgorithm; - -import org.apache.commons.codec.binary.Base64; - -import java.security.*; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.Cipher; - -/** - * Created by humf.需要依赖 commons-codec 包 - */ -public class RSADemo { - - public static void main(String[] args) throws Exception { - Map keyMap = initKey(); - String publicKey = getPublicKey(keyMap); - String privateKey = getPrivateKey(keyMap); - - System.out.println(keyMap); - System.out.println("-----------------------------------"); - System.out.println(publicKey); - System.out.println("-----------------------------------"); - System.out.println(privateKey); - System.out.println("-----------------------------------"); - byte[] encryptByPrivateKey = encryptByPrivateKey("123456".getBytes(), privateKey); - byte[] encryptByPublicKey = encryptByPublicKey("123456", publicKey); - System.out.println(encryptByPrivateKey); - System.out.println("-----------------------------------"); - System.out.println(encryptByPublicKey); - System.out.println("-----------------------------------"); - String sign = sign(encryptByPrivateKey, privateKey); - System.out.println(sign); - System.out.println("-----------------------------------"); - boolean verify = verify(encryptByPrivateKey, publicKey, sign); - System.out.println(verify); - System.out.println("-----------------------------------"); - byte[] decryptByPublicKey = decryptByPublicKey(encryptByPrivateKey, publicKey); - byte[] decryptByPrivateKey = decryptByPrivateKey(encryptByPublicKey, privateKey); - System.out.println(decryptByPublicKey); - System.out.println("-----------------------------------"); - System.out.println(decryptByPrivateKey); - - } - - public static final String KEY_ALGORITHM = "RSA"; - public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; - - private static final String PUBLIC_KEY = "RSAPublicKey"; - private static final String PRIVATE_KEY = "RSAPrivateKey"; - - public static byte[] decryptBASE64(String key) { - return Base64.decodeBase64(key); - } - - public static String encryptBASE64(byte[] bytes) { - return Base64.encodeBase64String(bytes); - } - - /** - * 用私钥对信息生成数字签名 - * - * @param data - * 加密数据 - * @param privateKey - * 私钥 - * @return - * @throws Exception - */ - public static String sign(byte[] data, String privateKey) throws Exception { - // 解密由base64编码的私钥 - byte[] keyBytes = decryptBASE64(privateKey); - // 构造PKCS8EncodedKeySpec对象 - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); - // KEY_ALGORITHM 指定的加密算法 - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - // 取私钥匙对象 - PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); - // 用私钥对信息生成数字签名 - Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); - signature.initSign(priKey); - signature.update(data); - return encryptBASE64(signature.sign()); - } - - /** - * 校验数字签名 - * - * @param data - * 加密数据 - * @param publicKey - * 公钥 - * @param sign - * 数字签名 - * @return 校验成功返回true 失败返回false - * @throws Exception - */ - public static boolean verify(byte[] data, String publicKey, String sign) throws Exception { - // 解密由base64编码的公钥 - byte[] keyBytes = decryptBASE64(publicKey); - // 构造X509EncodedKeySpec对象 - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); - // KEY_ALGORITHM 指定的加密算法 - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - // 取公钥匙对象 - PublicKey pubKey = keyFactory.generatePublic(keySpec); - Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); - signature.initVerify(pubKey); - signature.update(data); - // 验证签名是否正常 - return signature.verify(decryptBASE64(sign)); - } - - public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception { - // 对密钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得私钥 - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); - // 对数据解密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - return cipher.doFinal(data); - } - - /** - * 解密
- * 用私钥解密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] decryptByPrivateKey(String data, String key) throws Exception { - return decryptByPrivateKey(decryptBASE64(data), key); - } - - /** - * 解密
- * 用公钥解密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception { - // 对密钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得公钥 - X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key publicKey = keyFactory.generatePublic(x509KeySpec); - // 对数据解密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.DECRYPT_MODE, publicKey); - return cipher.doFinal(data); - } - - /** - * 加密
- * 用公钥加密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] encryptByPublicKey(String data, String key) throws Exception { - // 对公钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得公钥 - X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key publicKey = keyFactory.generatePublic(x509KeySpec); - // 对数据加密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - return cipher.doFinal(data.getBytes()); - } - - /** - * 加密
- * 用私钥加密 - * - * @param data - * @param key - * @return - * @throws Exception - */ - public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception { - // 对密钥解密 - byte[] keyBytes = decryptBASE64(key); - // 取得私钥 - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); - // 对数据加密 - Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - return cipher.doFinal(data); - } - - /** - * 取得私钥 - * - * @param keyMap - * @return - * @throws Exception - */ - public static String getPrivateKey(Map keyMap) throws Exception { - Key key = (Key) keyMap.get(PRIVATE_KEY); - return encryptBASE64(key.getEncoded()); - } - - /** - * 取得公钥 - * - * @param keyMap - * @return - * @throws Exception - */ - public static String getPublicKey(Map keyMap) throws Exception { - Key key = keyMap.get(PUBLIC_KEY); - return encryptBASE64(key.getEncoded()); - } - - /** - * 初始化密钥 - * - * @return - * @throws Exception - */ - public static Map initKey() throws Exception { - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); - keyPairGen.initialize(1024); - KeyPair keyPair = keyPairGen.generateKeyPair(); - Map keyMap = new HashMap(2); - keyMap.put(PUBLIC_KEY, keyPair.getPublic());// 公钥 - keyMap.put(PRIVATE_KEY, keyPair.getPrivate());// 私钥 - return keyMap; - } - -} -``` - -结果: - -``` -{RSAPublicKey=Sun RSA public key, 1024 bits - modulus: 115328826086047873902606456571034976538836553998745367981848911677968062571831626674499650854318207280419960767020601253071739555161388135589487284843845439403614883967713749605268831336418001722701924537624573180276356615050309809260289965219855862692230362893996010057188170525719351126759886050891484226169 - public exponent: 65537, RSAPrivateKey=sun.security.rsa.RSAPrivateCrtKeyImpl@93479} ------------------------------------ -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkO9PBTOFJQTkzznALN62PU7ixd9YFjXrt2dPOGj3wwhymbOU8HLoCztjwpLXHgbpBUJlGmbURV955M1BkZ1kr5dkZYR5x1gO4xOnu8rEipy4AAMcpFttfiarIZrtzL9pKEvEOxABltVN4yzFDr3IjBqY46aHna7YjwhXI0xHieQIDAQAB ------------------------------------ -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKQ708FM4UlBOTPOcAs3rY9TuLF31gWNeu3Z084aPfDCHKZs5TwcugLO2PCktceBukFQmUaZtRFX3nkzUGRnWSvl2RlhHnHWA7jE6e7ysSKnLgAAxykW21+Jqshmu3Mv2koS8Q7EAGW1U3jLMUOvciMGpjjpoedrtiPCFcjTEeJ5AgMBAAECgYAK4sxOa8IjEOexv2U92Rrv/SSo3sCY7Z/QVDft2V9xrewoO9+V9HF/7iYDDWffKYInAiimvVl7JM/iSLxza0ZFv29VMpyDcr4TigYmWwBlk7ZbxSTkqLdNwxxldMmEoTn1py53MUm+1V1K3rzNvJjuZaZFAevU7vUnwQwD+JGQYQJBAM9HBaC+dF3PJ2mkXekHpDS1ZPaSFdrdzd/GvHFi/cJAMM+Uz6PmpkosNXRtOpSYWwlOMRamLZtrHhfQoqSk3S8CQQDK1qL1jGvVdqw5OjqxktR7MmOsWUVZdWiBN+6ojxBgA0yVn0n7vkdAAgEZBj89WG0VHPEu3hd4AgXFZHDfXeDXAkBvSn7nE9t/Et7ihfI2UHgGJO8UxNMfNMB5Skebyb7eMYEDs67ZHdpjMOFypcMyTatzj5wjwQ3zyMvblZX+ONbZAkAX4ysRy9WvL+icXLUo0Gfhkk+WrnSyUldaUGH0y9Rb2kecn0OxN/lgGlxSvB+ac910zRHCOTl+Uo6nbmq0g3PFAkAyqA4eT7G9GXfncakgW1Kdkn72w/ODpozgfhTLNX0SGw1ITML3c4THTtH5h3zLi3AF9zJO2O+K6ajRbV0szHHI ------------------------------------ -[B@387c703b ------------------------------------ -[B@224aed64 ------------------------------------ -la4Hc4n/UbeBu0z9iLRuwKVv014SiOJMXkO5qdJvKBsw0MlnsrM+89a3p73yMrb1dAnCU/2kgO0PtFpvmG8pzxTe1u/5nX/25iIyUXALlwVRptJyjzFE83g2IX0XEv/Dxqr1RCRcrMHOLQM0oBoxZCaChmyw1Ub4wsSs6Ndxb9M= ------------------------------------ -true ------------------------------------ -[B@c39f790 ------------------------------------ -[B@71e7a66b - -``` - diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225.md" "b/docs/dataStructures-algorithms/\347\256\227\346\263\225.md" deleted file mode 100644 index ec53e700..00000000 --- "a/docs/dataStructures-algorithms/\347\256\227\346\263\225.md" +++ /dev/null @@ -1,90 +0,0 @@ - -## LeetCode -[LeetCode(中国)官网](https://leetcode-cn.com/) - -[如何高效地使用 LeetCode](https://leetcode-cn.com/articles/%E5%A6%82%E4%BD%95%E9%AB%98%E6%95%88%E5%9C%B0%E4%BD%BF%E7%94%A8-leetcode/) - - -## 牛客网: - -[牛客网首页](https://www.nowcoder.com) - - -> ### **[剑指offer编程题](https://www.nowcoder.com/ta/coding-interviews)** - -**分类解析:** -- [(1)斐波那契数列问题和跳台阶问题](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(1)斐波那契数列问题和跳台阶问题.md) -- [(2)二维数组查找和替换空格问题](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(2)二维数组查找和替换空格问题.md) -- [(3)数值的整数次方和调整数组元素顺序](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(3)数值的整数次方和调整数组元素顺序.md) -- [(4)链表相关编程题](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(4)链表相关编程题.md) -- [(5)栈变队列和栈的压入、弹出序列](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(5)栈变队列和栈的压入、弹出序列.md) - -> ### [2017校招真题](https://www.nowcoder.com/ta/2017test) - -> ### [华为机试题](https://www.nowcoder.com/ta/huawei) - - -## 公司真题 - -> [ 网易2018校园招聘编程题真题集合](https://www.nowcoder.com/test/6910869/summary) - -**解析:** -- [ 网易2018校招编程题1-3](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/公司真题/网易2018校招编程题1-3.md) - -> [ 网易2018校招内推编程题集合](https://www.nowcoder.com/test/6291726/summary) - -> [2017年校招全国统一模拟笔试(第五场)编程题集合](https://www.nowcoder.com/test/5986669/summary) - - > [2017年校招全国统一模拟笔试(第四场)编程题集合](https://www.nowcoder.com/test/5507925/summary) - -> [2017年校招全国统一模拟笔试(第三场)编程题集合](https://www.nowcoder.com/test/5217106/summary) - -> [2017年校招全国统一模拟笔试(第二场)编程题集合](https://www.nowcoder.com/test/4546329/summary) - -> [ 2017年校招全国统一模拟笔试(第一场)编程题集合](https://www.nowcoder.com/test/4236887/summary) - - -> [百度2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4998655/summary) - -> [网易2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4575457/summary) - - > [网易2017秋招编程题集合](https://www.nowcoder.com/test/2811407/summary) - - > [网易有道2017内推编程题](https://www.nowcoder.com/test/2385858/summary) - - > [ 滴滴出行2017秋招笔试真题-编程题汇总](https://www.nowcoder.com/test/3701760/summary) - -> [腾讯2017暑期实习生编程题](https://www.nowcoder.com/test/1725829/summary) - - > [今日头条2017客户端工程师实习生笔试题](https://www.nowcoder.com/test/1649301/summary) - - > [今日头条2017后端工程师实习生笔试题](https://www.nowcoder.com/test/1649268/summary) - - - -## 排序算法: -[图解排序算法(一)之3种简单排序(选择,冒泡,直接插入)](http://www.cnblogs.com/chengxiao/p/6103002.html) - -[图解排序算法(二)之希尔排序](https://www.cnblogs.com/chengxiao/p/6104371.html) - -[图解排序算法(三)之堆排序](http://www.cnblogs.com/chengxiao/p/6129630.html) - -[图解排序算法(四)之归并排序](http://www.cnblogs.com/chengxiao/p/6194356.html) - -[图解排序算法(五)之快速排序——三数取中法](http://www.cnblogs.com/chengxiao/p/6262208.html) - - - - - - - - - - - - - - - - diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md" "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md" new file mode 100644 index 00000000..12033ede --- /dev/null +++ "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md" @@ -0,0 +1,52 @@ +我比较推荐大家可以刷一下 Leetcode ,我自己平时没事也会刷一下,我觉得刷 Leetcode 不仅是为了能让你更从容地面对面试中的手撕算法问题,更可以提高你的编程思维能力、解决问题的能力以及你对某门编程语言 API 的熟练度。当然牛客网也有一些算法题,我下面也整理了一些。 + +## LeetCode + +- [LeetCode(中国)官网](https://leetcode-cn.com/) + +- [如何高效地使用 LeetCode](https://leetcode-cn.com/articles/%E5%A6%82%E4%BD%95%E9%AB%98%E6%95%88%E5%9C%B0%E4%BD%BF%E7%94%A8-leetcode/) + + +## 牛客网: + +- [牛客网官网](https://www.nowcoder.com) +- [剑指offer编程题](https://www.nowcoder.com/ta/coding-interviews) + +- [2017校招真题](https://www.nowcoder.com/ta/2017test) +- [华为机试题](https://www.nowcoder.com/ta/huawei) + + +## 公司真题 + +- [ 网易2018校园招聘编程题真题集合](https://www.nowcoder.com/test/6910869/summary) +- [ 网易2018校招内推编程题集合](https://www.nowcoder.com/test/6291726/summary) +- [2017年校招全国统一模拟笔试(第五场)编程题集合](https://www.nowcoder.com/test/5986669/summary) +- [2017年校招全国统一模拟笔试(第四场)编程题集合](https://www.nowcoder.com/test/5507925/summary) +- [2017年校招全国统一模拟笔试(第三场)编程题集合](https://www.nowcoder.com/test/5217106/summary) +- [2017年校招全国统一模拟笔试(第二场)编程题集合](https://www.nowcoder.com/test/4546329/summary) +- [ 2017年校招全国统一模拟笔试(第一场)编程题集合](https://www.nowcoder.com/test/4236887/summary) +- [百度2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4998655/summary) +- [网易2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4575457/summary) +- [网易2017秋招编程题集合](https://www.nowcoder.com/test/2811407/summary) +- [网易有道2017内推编程题](https://www.nowcoder.com/test/2385858/summary) +- [ 滴滴出行2017秋招笔试真题-编程题汇总](https://www.nowcoder.com/test/3701760/summary) +- [腾讯2017暑期实习生编程题](https://www.nowcoder.com/test/1725829/summary) +- [今日头条2017客户端工程师实习生笔试题](https://www.nowcoder.com/test/1649301/summary) +- [今日头条2017后端工程师实习生笔试题](https://www.nowcoder.com/test/1649268/summary) + + + + + + + + + + + + + + + + + diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2101\357\274\211\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\351\227\256\351\242\230\345\222\214\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.md" "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2101\357\274\211\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\351\227\256\351\242\230\345\222\214\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.md" deleted file mode 100644 index 87a51d90..00000000 --- "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2101\357\274\211\346\226\220\346\263\242\351\202\243\345\245\221\346\225\260\345\210\227\351\227\256\351\242\230\345\222\214\350\267\263\345\217\260\351\230\266\351\227\256\351\242\230.md" +++ /dev/null @@ -1,127 +0,0 @@ -### 一 斐波那契数列 -#### **题目描述:** -大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。 -n<=39 - -#### **问题分析:** -可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有一个很大的问题,那就是递归大量的重复计算会导致内存溢出。另外可以使用迭代法,用fn1和fn2保存计算过程中的结果,并复用起来。下面我会把两个方法示例代码都给出来并给出两个方法的运行时间对比。 - -#### **示例代码:** -**采用迭代法:** - -```java - - int Fibonacci(int number) { - if (number <= 0) { - return 0; - } - if (number == 1 || number == 2) { - return 1; - } - int first = 1, second = 1, third = 0; - for (int i = 3; i <= number; i++) { - third = first + second; - first = second; - second = third; - } - return third; - } -``` -**采用递归:** -```java - public int Fibonacci(int n) { - - if (n <= 0) { - return 0; - } - if (n == 1||n==2) { - return 1; - } - - return Fibonacci(n - 2) + Fibonacci(n - 1); - - } -``` - -#### **运行时间对比:** -假设n为40我们分别使用迭代法和递归法计算,计算结果如下: -1. 迭代法 -![迭代法](https://ws1.sinaimg.cn/large/006rNwoDgy1fpydt5as85j308a025dfl.jpg) -2. 递归法 - ![递归法](https://ws1.sinaimg.cn/large/006rNwoDgy1fpydt2d1k3j30ed02kt8i.jpg) - - -### 二 跳台阶问题 -#### **题目描述:** -一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 -#### **问题分析:** -**正常分析法:** -a.如果两种跳法,1阶或者2阶,那么假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1); -b.假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2) -c.由a,b假设可以得出总跳法为: f(n) = f(n-1) + f(n-2) -d.然后通过实际的情况可以得出:只有一阶的时候 f(1) = 1 ,只有两阶的时候可以有 f(2) = 2 -**找规律分析法:** -f(1) = 1, f(2) = 2, f(3) = 3, f(4) = 5, 可以总结出f(n) = f(n-1) + f(n-2)的规律。 -但是为什么会出现这样的规律呢?假设现在6个台阶,我们可以从第5跳一步到6,这样的话有多少种方案跳到5就有多少种方案跳到6,另外我们也可以从4跳两步跳到6,跳到4有多少种方案的话,就有多少种方案跳到6,其他的不能从3跳到6什么的啦,所以最后就是f(6) = f(5) + f(4);这样子也很好理解变态跳台阶的问题了。 - -**所以这道题其实就是斐波那契数列的问题。** -代码只需要在上一题的代码稍做修改即可。和上一题唯一不同的就是这一题的初始元素变为 1 2 3 5 8.....而上一题为1 1 2 3 5 .......。另外这一题也可以用递归做,但是递归效率太低,所以我这里只给出了迭代方式的代码。 -#### **示例代码:** -```java - - int jumpFloor(int number) { - if (number <= 0) { - return 0; - } - if (number == 1) { - return 1; - } - if (number == 2) { - return 2; - } - int first = 1, second = 2, third = 0; - for (int i = 3; i <= number; i++) { - third = first + second; - first = second; - second = third; - } - return third; - } -``` - - -### 三 变态跳台阶问题 -#### **题目描述:** -一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 - -#### **问题分析:** -假设n>=2,第一步有n种跳法:跳1级、跳2级、到跳n级 -跳1级,剩下n-1级,则剩下跳法是f(n-1) -跳2级,剩下n-2级,则剩下跳法是f(n-2) -...... -跳n-1级,剩下1级,则剩下跳法是f(1) -跳n级,剩下0级,则剩下跳法是f(0) -所以在n>=2的情况下: -f(n)=f(n-1)+f(n-2)+...+f(1) -因为f(n-1)=f(n-2)+f(n-3)+...+f(1) -所以f(n)=2*f(n-1) 又f(1)=1,所以可得**f(n)=2^(number-1)** - -#### **示例代码:** - -```java - int JumpFloorII(int number) { - return 1 << --number;//2^(number-1)用位移操作进行,更快 - } -``` -#### **补充:** -**java中有三种移位运算符:** - -1. “<<” : **左移运算符**,等同于乘2的n次方 -2. “>>”: **右移运算符**,等同于除2的n次方 -3. “>>>” **无符号右移运算符**,不管移动前最高位是0还是1,右移后左侧产生的空位部分都以0来填充。与>>类似。 -例: - int a = 16; - int b = a << 2;//左移2,等同于16 * 2的2次方,也就是16 * 4 - int c = a >> 2;//右移2,等同于16 / 2的2次方,也就是16 / 4 - - diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2102\357\274\211\344\272\214\347\273\264\346\225\260\347\273\204\346\237\245\346\211\276\345\222\214\346\233\277\346\215\242\347\251\272\346\240\274\351\227\256\351\242\230.md" "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2102\357\274\211\344\272\214\347\273\264\346\225\260\347\273\204\346\237\245\346\211\276\345\222\214\346\233\277\346\215\242\347\251\272\346\240\274\351\227\256\351\242\230.md" deleted file mode 100644 index 964ed6c9..00000000 --- "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2102\357\274\211\344\272\214\347\273\264\346\225\260\347\273\204\346\237\245\346\211\276\345\222\214\346\233\277\346\215\242\347\251\272\346\240\274\351\227\256\351\242\230.md" +++ /dev/null @@ -1,64 +0,0 @@ -### 一 二维数组查找 -#### **题目描述:** -在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 -#### **问题解析:** -这一道题还是比较简单的,我们需要考虑的是如何做,效率最快。这里有一种很好理解的思路: - -> 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增, - 因此从左下角开始查找,当要查找数字比左下角数字大时。右移 - 要查找数字比左下角数字小时,上移。这样找的速度最快。 - -#### **示例代码:** -```java - public boolean Find(int target, int [][] array) { - //基本思路从左下角开始找,这样速度最快 - int row = array.length-1;//行 - int column = 0;//列 - //当行数大于0,当前列数小于总列数时循环条件成立 - while((row >= 0)&& (column< array[0].length)){ - if(array[row][column] > target){ - row--; - }else if(array[row][column] < target){ - column++; - }else{ - return true; - } - } - return false; - } -``` -### 二 替换空格 -#### **题目描述:** -请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 -#### **问题分析:** -这道题不难,我们可以通过循环判断字符串的字符是否为空格,是的话就利用append()方法添加追加“%20”,否则还是追加原字符。 - -或者最简单的方法就是利用: replaceAll(String regex,String replacement)方法了,一行代码就可以解决。 - -#### **示例代码:** -**常规做法:** -```java - public String replaceSpace(StringBuffer str) { - StringBuffer out=new StringBuffer(); - for (int i = 0; i < str.toString().length(); i++) { - char b=str.charAt(i); - if(String.valueOf(b).equals(" ")){ - out.append("%20"); - }else{ - out.append(b); - } - } - return out.toString(); - } -``` -**一行代码解决:** -```java - public String replaceSpace(StringBuffer str) { - //return str.toString().replaceAll(" ", "%20"); - //public String replaceAll(String regex,String replacement) - //用给定的替换替换与给定的regular expression匹配的此字符串的每个子字符串。 - //\ 转义字符. 如果你要使用 "\" 本身, 则应该使用 "\\". String类型中的空格用“\s”表示,所以我这里猜测"\\s"就是代表空格的意思 - return str.toString().replaceAll("\\s", "%20"); - } - -``` diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2103\357\274\211\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271\345\222\214\350\260\203\346\225\264\346\225\260\347\273\204\345\205\203\347\264\240\351\241\272\345\272\217.md" "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2103\357\274\211\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271\345\222\214\350\260\203\346\225\264\346\225\260\347\273\204\345\205\203\347\264\240\351\241\272\345\272\217.md" deleted file mode 100644 index 291569c0..00000000 --- "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\211\221\346\214\207offer/\357\274\2103\357\274\211\346\225\260\345\200\274\347\232\204\346\225\264\346\225\260\346\254\241\346\226\271\345\222\214\350\260\203\346\225\264\346\225\260\347\273\204\345\205\203\347\264\240\351\241\272\345\272\217.md" +++ /dev/null @@ -1,113 +0,0 @@ -### 一 数值的整数次方 -#### **题目描述:** -给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。 -#### **问题解析:** -这道题算是比较麻烦和难一点的一个了。我这里采用的是**二分幂**思想,当然也可以采用**快速幂**。 -更具剑指offer书中细节,该题的解题思路如下: -1.当底数为0且指数<0时,会出现对0求倒数的情况,需进行错误处理,设置一个全局变量; -2.判断底数是否等于0,由于base为double型,所以不能直接用==判断 -3.优化求幂函数(二分幂)。 -当n为偶数,a^n =(a^n/2)*(a^n/2); -当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a。时间复杂度O(logn) - -**时间复杂度**:O(logn) -#### **示例代码:** -```java -public class Solution { - boolean invalidInput=false; - public double Power(double base, int exponent) { - //如果底数等于0并且指数小于0 - //由于base为double型,不能直接用==判断 - if(equal(base,0.0)&&exponent<0){ - invalidInput=true; - return 0.0; - } - int absexponent=exponent; - //如果指数小于0,将指数转正 - if(exponent<0) - absexponent=-exponent; - //getPower方法求出base的exponent次方。 - double res=getPower(base,absexponent); - //如果指数小于0,所得结果为上面求的结果的倒数 - if(exponent<0) - res=1.0/res; - return res; - } - //比较两个double型变量是否相等的方法 - boolean equal(double num1,double num2){ - if(num1-num2>-0.000001&&num1-num2<0.000001) - return true; - else - return false; - } - //求出b的e次方的方法 - double getPower(double b,int e){ - //如果指数为0,返回1 - if(e==0) - return 1.0; - //如果指数为1,返回b - if(e==1) - return b; - //e>>1相等于e/2,这里就是求a^n =(a^n/2)*(a^n/2) - double result=getPower(b,e>>1); - result*=result; - //如果指数n为奇数,则要再乘一次底数base - if((e&1)==1) - result*=b; - return result; - } -} -``` - -当然这一题也可以采用笨方法:累乘。不过这种方法的时间复杂度为O(n),这样没有前一种方法效率高。 -```java - // 使用累乘 - public double powerAnother(double base, int exponent) { - double result = 1.0; - for (int i = 0; i < Math.abs(exponent); i++) { - result *= base; - } - if (exponent >= 0) - return result; - else - return 1 / result; - } -``` -### 二 调整数组顺序使奇数位于偶数前面 -#### **题目描述:** -输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。 - -#### **问题解析:** -这道题有挺多种解法的,给大家介绍一种我觉得挺好理解的方法: -我们首先统计奇数的个数假设为n,然后新建一个等长数组,然后通过循环判断原数组中的元素为偶数还是奇数。如果是则从数组下标0的元素开始,把该奇数添加到新数组;如果是偶数则从数组下标为n的元素开始把该偶数添加到新数组中。 - -#### **示例代码:** -时间复杂度为O(n),空间复杂度为O(n)的算法 -```java -public class Solution { - public void reOrderArray(int [] array) { - //如果数组长度等于0或者等于1,什么都不做直接返回 - if(array.length==0||array.length==1) - return; - //oddCount:保存奇数个数 - //oddBegin:奇数从数组头部开始添加 - int oddCount=0,oddBegin=0; - //新建一个数组 - int[] newArray=new int[array.length]; - //计算出(数组中的奇数个数)开始添加元素 - for(int i=0;i stack1 = new Stack(); - Stack stack2 = new Stack(); - - //当执行push操作时,将元素添加到stack1 - public void push(int node) { - stack1.push(node); - } - - public int pop() { - //如果两个队列都为空则抛出异常,说明用户没有push进任何元素 - if(stack1.empty()&&stack2.empty()){ - throw new RuntimeException("Queue is empty!"); - } - //如果stack2不为空直接对stack2执行pop操作, - if(stack2.empty()){ - while(!stack1.empty()){ - //将stack1的元素按后进先出push进stack2里面 - stack2.push(stack1.pop()); - } - } - return stack2.pop(); - } -} -``` - -### 二 栈的压入、弹出序列 -#### **题目描述:** -输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的) -#### **题目分析:** -这道题想了半天没有思路,参考了Alias的答案,他的思路写的也很详细应该很容易看懂。 -作者:Alias -https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106 -来源:牛客网 - -【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。 - -举例: - -入栈1,2,3,4,5 - -出栈4,5,3,2,1 - -首先1入辅助栈,此时栈顶1≠4,继续入栈2 - -此时栈顶2≠4,继续入栈3 - -此时栈顶3≠4,继续入栈4 - -此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3 - -此时栈顶3≠5,继续入栈5 - -此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3 - -…. -依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。 - - - -#### **考察内容:** -栈 - -#### **示例代码:** -```java -import java.util.ArrayList; -import java.util.Stack; -//这道题没想出来,参考了Alias同学的答案:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106 -public class Solution { - public boolean IsPopOrder(int [] pushA,int [] popA) { - if(pushA.length == 0 || popA.length == 0) - return false; - Stack s = new Stack(); - //用于标识弹出序列的位置 - int popIndex = 0; - for(int i = 0; i< pushA.length;i++){ - s.push(pushA[i]); - //如果栈不为空,且栈顶元素等于弹出序列 - while(!s.empty() &&s.peek() == popA[popIndex]){ - //出栈 - s.pop(); - //弹出序列向后一位 - popIndex++; - } - } - return s.empty(); - } -} -``` \ No newline at end of file -- GitLab