穷举法破解密码-方法详解

  1. 生成一个长度是3的随机字符串,把这个字符串作为当做密码

  2. 使用穷举法生成长度是3个字符串,匹配上述生成的密码

要求: 分别使用多层for循环 和 递归解决上述问题

1.穷举法:
穷举算法,依赖计算机强大的计算能力,来穷举每一种可能的情况,以达到解决问题的目的,也叫枚举法、暴力破解法。

基本思想———逐一列举问题所涉及的所有情形,并根据问题提出的条件进行检验从而找到可能的解 。

方法步骤———确定枚举对象、枚举范围、判断条件;循环验证每一个解

2.递归:
递归的思想:
以此类推是递归的基本思想。

具体来讲就是把规模大的问题转化为规模小的相似的子问题来解决。在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况。另外这个解决问题的函数必须有明显的结束条件,这样就不会产生无限递归的情况了。

递归的两个条件:
可以通过递归调用来缩小问题规模,且新问题与原问题有着相同的形式。(自身调用)
存在一种简单情境,可以使递归在简单情境下退出。(递归出口)

递归三要素:
一定有一种可以退出程序的情况;
总是在尝试将一个问题化简到更小的规模
父问题与子问题不能有重叠的部分
递归:自已(方法)调用自已
例子:用递归把目录下所有的目录及文件全部显示出来

方法一:多层循环方式

package day6;
/*
 * 练习-穷举法破解密码 
 * 	1. 生成一个长度是3的随机字符串,把这个字符串作为当做密码

	2. 使用穷举法生成长度是3个字符串,匹配上述生成的密码

	要求: 分别使用多层for循环 和 递归解决上述问题
 */
public class TestNumber10 {

	public static void main(String[] args) {
		//多层循环方式
		String password=randomString(3);//首先通过调用randomString()方法随机生成一个字符串作为密码,并将它赋值给password
		System.out.println("密码是:"+password);//输出这个密码
		
		char[]guesspassword=new char[3];//新建一个长度为3的空数组
		outloop://设置一个标签,在break的时候使用该标签,即能达到结束多重嵌套循环的效果
			//开始多层循环,也就是穷举
			for(short i ='0';i<='z';i++){
				for(short j ='0';j<='z';j++){
					for(short k ='0';k<='z';k++){
						if(!isLetterOrDigit(i,j,k)){//调用isLetterOrDigt()方法,如果i,j,k有一个不符合条件,就跳出当前循环,并开始下一次循环
							continue;
						}
						//如果i,j,k都符合条件,那就分别把i,j,k赋值给guesspassword数组的三个位置
						guesspassword[0]=(char)i;
						guesspassword[1]=(char)j;
						guesspassword[2]=(char)k;
						//这样就得到了穷举出来的密码
						String guess = new String(guesspassword);
						//System.out.println("穷举出来的密码是:"+guess);
						
						if(guess.equals(password))//将穷举出来的密码与原密码进行比较,如果二者一致,执行if
							{
							System.out.println("找到了,密码是:"+guess);
							break outloop;
							}
						}
						
					}
				}
			}
	
	private static boolean isLetterOrDigit(short i,short j ,short k){//判断i,j,k是不是符合条件
		return (Character.isLetterOrDigit(i))&&(Character.isLetterOrDigit(j))&&Character.isLetter(k);
	}
	
	private static String randomString(int length){//随机生成一个长度为3的字符串,注意这里有参数Length,是字符串的长度
		String pool="";
		for(int i ='0';i<='9';i++){
			pool+=(char)i;
		}
		for(int i ='a';i<='z';i++){
			pool+=(char)i;
		}
		for(int i ='A';i<='Z';i++){
			pool+=(char)i;
		}
		
		char cs[]=new char[length];//参数传到了这里,也就是new char[3]
		for(int i =0;i<cs.length;i++){//这样就可以按照cs的长度(也就是password的长度)来随机分配数字或者字母了
		int index= (int)(Math.random()*(pool.length()));
		cs[i]=pool.charAt(index);//把字符串随机下标的一个字符放入每一个数组元素
		}
		String result = String.valueOf(cs);  //把字符数组转换成字符串,记住
		return result;
	}	
}

方法二:递归方式

package day6;
/*
 * 练习-穷举法破解密码 
 * 	1. 生成一个长度是3的随机字符串,把这个字符串作为当做密码

	2. 使用穷举法生成长度是3个字符串,匹配上述生成的密码

	要求: 分别使用多层for循环 和 递归解决上述问题
 */
public class TestNumber11 {
	public static boolean found = false;
	public static void main(String[] args) {
		
		String password= randomString(3);//定义了一个Password字符串,并调用randomString方法随机生成了一个长度为3的字符串,赋值给了password
		System.out.println("密码是:"+password);
		
		
		
		char[]guessPassword= new char[password.length()];//定义了一个数组guessPassword,她的长度和password的长度一样
		generatePassword(guessPassword,password);//调用generatePassword方法,注意里面有两个参数

	}
	
	private static void generatePassword(char[]guessPassword,String password){//定义了generatePassword方法,有两个参数
		generatePassword(guessPassword,0,password);//方法内又调用了generatePassword方法,注意这里是三个参数
	}
	
	private static void generatePassword(char[] guessPassword,int index,String password){//将generatePassword方法重载,改成了三个参数,方法体也有了改变
		if(found)
		//这里found如果是false,就不执行if语句,然后继续执行for循环,也就表示false的时候没有找到密码,继续循环;
		//如果found是true,就代表找到了密码,那么就执行if语句,返回一个空,这里已经有了返回值给generatePassword()方法,那么就不在继续向下执行for循环了,这里要注意。
			return;
		for(short i ='0';i<='z';i++){
			char c =(char)i;//定义一个字符变量c,将i的值赋值给c,并强制类型转换
			if(!Character.isLetterOrDigit(c))//如果c不符合是字母或者数字的要求,跳出本次循环
				continue;
			guessPassword[index]=c;//如果c符合要求,就把c赋值给参入的index参数对应的数组的位置
			
			if(index!=guessPassword.length-1){//如果index的值还没有到数组的最后一个位置的值,就继续调用generatePassword
				//这里index继续向后移动,所以变成里index+1,以此类推
				generatePassword(guessPassword,index+1,password);
			}
			
			else
			{//如果index已经到了数组的最后一个位置,就执行else后面这里的方法体
				String guess = new String(guessPassword);//把guessPassword赋值给定义的字符串guess
				//System.out.println("穷举出来的密码是:" + guess);
				if(guess.equals(password)){//比较guess和原密码
                    System.out.println("找到了,密码是" + guess);
                    found =true;//找到了密码。将found改成true,返回空
                    return;
				}
			}
	
		}
		
	}
	 private static String randomString(int length) {//randomString函数的内容:生成长度为3的随机字符串
	        String pool = "";
	        for (short i = '0'; i <= '9'; i++) {
	            pool += (char) i;
	        }
	        for (short i = 'a'; i <= 'z'; i++) {
	            pool += (char) i;
	        }
	        for (short i = 'A'; i <= 'Z'; i++) {
	            pool += (char) i;
	        }
	        char cs[] = new char[length];
	        for (int i = 0; i < cs.length; i++) {
	            int index = (int) (Math.random() * pool.length());
	            cs[i] = pool.charAt(index);
	        }
	        String result = new String(cs);
	        return result;
	    }
}

你可能感兴趣的:(字符串,java,算法,数据结构)