什么是算法?
算法是解决问题方案准确而完整的描述,是一系列解决问题的清晰指令,算法代表着的是用系统的方法描述解决问题的策略机制。也就是,对一定范围内的规范输入,在有限的时间内获得所要求的输出。如果一个算法有缺陷,或者不适合这个问题。那么这个算法将不能解决这个问题。不同的算法可以在不同的时间空间或者效率来完成未完成的任务。一个算法的优劣可以用 时间复杂度和空间复杂度衡量。
算法的指令指令描述的是一个计算,当运行时能从一个初始状态和初始输入开始,经过一系列的有限清晰定义状态,最终产生输出并停止一个状态。一个状态到另一个状态的转移不一定是确定的。随机算法在内的一些算法,包含了一些随即输入。
一个算法应该有五个特征:
有穷性:必须在执行有限的几个步骤后结束。
确切性:算法的每一个步骤必须明确的定义。
输入项:一个算法有0个或者多个输入,以刻画运算对象的初始情况,所谓的0个输入是指算法本身的初始条件;
输出项:一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出 算法毫无意义。
可行性:算法的任何执行计算步骤都可以分解为可执行的操作步骤,即每一个计算都可以在有限的时间完成(也称为有效性)
算法的评定:同一个问题可以用不同的算法解决,算法的质量优劣影响算法乃至程序的效率。算法分析的目的在于找到合适的算法。一个算法的评价主要有时间复杂度和空间复杂度来考虑。
stop!请问什么是时间复杂度什么是空间复杂度?以及算法的优略的评判标准?
时间复杂度:算法的时间复杂度是指执行算法需要的计算工作量。一般来说,计算机是问题规模n的函数发f(n),算法的时间复杂度也这样记作。
空间复杂度:算法计算所需要花费的内存空间,用复杂度的渐进性表示
正确性:算法的正确性是评判一个算法的优劣的重要标准
可读性:算法的可读性是指一个算法可供人们阅读的容易程度
健壮性:健壮性是指一些算法对输入不合理的数据的反应能力和处理能力,也称为容性。
算法实现的常用方法:
递推法:
递推法是计算机序列常用的一种算法,它按照一定的规律来计算序列中的每一项,通常是通过计算机前面的一些项来的出序列中指定的值。其思想是把一个庞大的负责的运算过程转化为简单的多次重复计算,该方法利用了计算机快和不知疲惫的机器特点。
举个例子:小明有5块钱,说小红比小明多2块,小李又说我比小红多2块,小王说我比小李多两块。那么其他人是多少?
这个问题就可以使用递推算法:设小明=a 小红=a1 小李=a2 小王= a3
a=5
a1=5+2
a2=(5+2)+2
a3=((5+2)+2)+2
使用java编程 来表示:
package com.hainniu.algorithm; import java.util.Scanner; public class Recurrence { public static void main(String[] args) { // 递推算法 Scanner sc = new Scanner(System.in); int n= sc.nextInt();for (int i = 1; i < 5; i++) { if(true){ n += 2; } System.out.println("a"+i+":"+n); } } }
//运行结果
5
a1:7
a2:9
a3:11
a4:13
递归法:
递归法就是自身调用自身,通过少量的程序进行多次的重复计算,递归可以进行无线的运算,当然一般情况下不会这样做。一般递归都需要一个出口,当不满足条件时运算,当满足时返回结果。
注意:1)递归就是在过程函数或者函数里调用自身;2)在使用递归策略时必须有一个明确的递归条件,称之为递归出口。
递归
package com.hainniu.algorithm; public class Recursion { //实现一个递归 int i =0; public void add(){ i++; if(i==9){ return; } System.out.println(i); add(); } public static void main(String[] args) { Recursion re = new Recursion(); re.add(); } }
递归实现1-9的阶乘
首先了解什么是阶乘。阶乘的形式
package com.hainniu.algorithm; public class Factorial { // 使用递归实现阶乘 public int add(int n){ if(n==1){ return 1; }else{ return n*add(n-1); } } public static void main(String[] args) { Factorial fa = new Factorial(); System.out.println(fa.add(9)); } }
穷举法:
穷举法:又叫做暴力破解法。 基本思路是对于所有要解决的问题,列出它所有的可能,逐个判断。那个是符合问题所要求的条件,从而得到问题的解。他也常用于对密码的破译。即将密码进行逐个的推算直到找出正在的密码为止。列如已知一个四位数的密码 它最多有一万种组合,因此最多尝试10000次就能找到正确的密码。理论上这种方法可以破解任何一种密码,问题在于如何缩短时间。因此有人运用计算机来实现,有些人辅以字典来缩小密码组合的范围。
简单的来说就是依靠计算机强大的计算能力,计算出问题所有的可能性,达到解决问题的目的。
java编程 穷举法
练习1:输出所有三个数字 随机匹配的所有 可能
public static void main(String[] args) { //输出所有3位数的可能 int num= 0; for (int i = 1; i < 4; i++) { for (int j = 1; j < 4; j++) { for (int j2 = 1; j2 < 4; j2++) { num++; System.out.print(i+""+j+""+j2+""+" "); if(num%9==0){ System.out.println(); } } } } } }
贪心算法:
贪心算法是求某些最优解问题的更简单,更迅速的的设计技术。用贪心法设计算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,它省去了为找最优解要穷尽所有可能而必须耗费的大量时间,它采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题, 通过每一步贪心选择,可得到问题的一个最优解,虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪婪法不要回溯。
java编程:
假设1元、2元、5元、10元、20元、50元、100元的纸币,张数不限制,现在要用来支付K元,至少要多少张纸币?
很显然,我们很容易就想到使用贪心算法来解决,并且我们所根据的贪心策略是,每一步尽可能用面值大的纸币即可。当然这是正确的,代码如下:
/** * 钱币找零问题 */ public static void greedyGiveMoney(int money) { System.out.println("需要找零: " + money); int[] moneyLevel = {1, 5, 10, 20, 50, 100}; for (int i = moneyLevel.length - 1; i >= 0; i--) { int num = money/ moneyLevel[i]; int mod = money % moneyLevel[i]; money = mod; if (num > 0) { System.out.println("需要" + num + "张" + moneyLevel[i] + "块的"); } } }
分治法
分治法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
java--二分查找 前提数据有有序的
//二分搜索算法 public class test{ public static void main(String[] args){ int[] a = {1,2,3,4,5,6,7,8,9}; int position = bSearch(a,0,a.length-1,3); System.out.println(position); } public static int bSearch(int[] data,int left,int right,int key){ //获取中间位置 int middle = (left+right)/2; //三种情况 if(data[middle] == key){ return middle; }else if(data[middle] > key){ return bSearch(data,left,middle-1,key); }else{ return bSearch(data,middle+1,right,key); } } }
动态规划法:
一个高度为N的由正整数组成的三角形,从上走到下,求经过的数字和的最大值。
每次只能走到下一层相邻的数上,例如从第3层的6向下走,只能走到第4层的2或9上。
该三角形第n层有n个数字,例如:
第一层有一个数字:5
第二层有两个数字:8 4
第三层有三个数字:3 6 9
第四层有四个数字:7 2 9 5
最优方案是:5 + 8 + 6 + 9 = 28
注意:上面应该是排列成一个三角形的样子不是竖向对应的,排版问题没有显示成三角形。
状态定义: Fi,j是第i行j列项最大取数和,求第n行Fn,m(0 < m < n)中最大值。
状态转移方程:Fi,j = max{Fi-1,j-1,Fi-1,j}+Ai,jt
public class Dp01 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); long max = 0; int[][] dp = new int[n][n]; dp[0][0] = scan.nextInt(); for(int i=1;i<n;i++){ for(int j=0;j<=i;j++){ int num = scan.nextInt(); if(j==0){ dp[i][j] = dp[i-1][j] + num; }else { dp[i][j] = Math.max(dp[i-1][j-1],dp[i - 1][j])+num; } max = Math.max(dp[i][j],max); } } System.out.println(max); } }
int factorial (int n) { int product = 1; for(int i=2; i<n; i++) { product *= i; } return product; }