算法--入门

什么是算法?

算法是解决问题方案准确而完整的描述,是一系列解决问题的清晰指令,算法代表着的是用系统的方法描述解决问题的策略机制。也就是,对一定范围内的规范输入,在有限的时间内获得所要求的输出。如果一个算法有缺陷,或者不适合这个问题。那么这个算法将不能解决这个问题。不同的算法可以在不同的时间空间或者效率来完成未完成的任务。一个算法的优劣可以用 时间复杂度和空间复杂度衡量。

算法的指令指令描述的是一个计算,当运行时能从一个初始状态和初始输入开始,经过一系列的有限清晰定义状态,最终产生输出并停止一个状态。一个状态到另一个状态的转移不一定是确定的。随机算法在内的一些算法,包含了一些随即输入。

一个算法应该有五个特征

有穷性:必须在执行有限的几个步骤后结束。

确切性:算法的每一个步骤必须明确的定义。

输入项:一个算法有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] + "块的");
            }
        }
    }

 

分治法

分治法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

分治法所能解决的问题一般具有以下几个特征:
(1) 该问题的规模缩小到一定的程度就可以容易地解决;
(2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
(3) 利用该问题分解出的子问题的解可以合并为该问题的解;
(4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
大数据里面用到这一算法较多,比如mapreduce的就是基于化大为小,分而治之的思想。hdfs也是把一个文件分为128m每块来进行运算

 

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;
}

 

 
算法可以宏泛的分为三类:
一,有限的,确定性算法 这类算法在有限的一段时间内终止。他们可能要花很长时间来执行指定的任务,但仍将在一定的时间内终止。这类算法得出的结果常取决于输入值。
二,有限的,非确定算法 这类算法在有限的时间内终止。然而,对于一个(或一些)给定的数值,算法的结果并不是唯一的或确定的。
三,无限的算法 是那些由于没有定义终止定义条件,或定义的条件无法由输入的数据满足而不终止运行的算法。通常,无限算法的产生是由于未能确定的定义终止条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值