二分查找 跳表 LRU缓存 贪心算法 霍夫曼编码 分治算法 回溯算法 动态规划

二分查找
只能是有序的数组,而且应该用在插入删除不频繁的场景中。

    public static int commonBinarySearch(int[] arr,int key){
        int low = 0;
        int high = arr.length - 1;
        if(key < arr[low] || key > arr[high] || low > high){
            return -1;
        }
        while(low <= high){
           int  middle =  low+((high-low)>>1);//这种写法性能最优  // low+(high-low)/2;   //(low + high) / 2 这种写法可能会造成溢出
            if(arr[middle] > key){
                //比关键字大则关键字在左区域
                high = middle - 1;
            }else if(arr[middle] < key){
                //比关键字小则关键字在右区域
                low = middle + 1;
            }else{
                return middle;
            }
        }
        return -1;		//最后仍然没有找到,则返回-1
    }

递归的二分查找

	public static int bsearch(int[] arr,int key){
		return 	recursionBinarySearch(arr,key,0,arr.length-1);
	}
    public static int recursionBinarySearch(int[] arr,int key,int low,int high){
        if(key < arr[low] || key > arr[high] || low > high){
            return -1;
        }
        int middle = (low + high) / 2;			//初始中间位置
        if(arr[middle] > key){
            //比关键字大则关键字在左区域
            return recursionBinarySearch(arr, key, low, middle - 1);
        }else if(arr[middle] < key){
            //比关键字小则关键字在右区域
            return recursionBinarySearch(arr, key, middle + 1, high);
        }else {
            return middle;
        }
    }

二分查找(重复数据)
查找第一个值等于给定的元素

public static int bserach1(int[] a,int n,int value){
        int low= 0;
        int high = n-1;
        while(low<=high){
            int mid = low + ((high-low)>>1);
            if(a[mid]>value){
                high=mid-1;
            }else if(a[mid]<value){
                low=mid+1;
            }else {
                if((mid==0)||(a[mid-1] != value)) return mid;
                else high = mid-1;
            }
        }
        return  -1;
    }

二分查找 (重复)
查找第一个值大于给定的元素

    public static int bserach2(int[] a,int n,int value){
        int low= 0;
        int high = n-1;
        while(low<=high){
            int mid = low + ((high-low)>>1);
            if(a[mid]>=value){
                if((mid==0)||(a[mid-1]<value)){return mid;}
                else high = mid -1;
            }else {
                low= mid +1;
            }
        }
        return  -1;
    }

跳表
在这里插入图片描述我们通过索引层结点的 down 指针,下降到原始链表这一层,继续遍历。
第 k级索引结点的个数就是 n/(2k次方)。
整个链表高度是log2n。
如果每一层都要遍历 m 个结点,那在跳表中查询一个数据的时间复杂度就是 O(m*logn)。

在这里插入图片描述可知m=3。
所以时间复杂度是O(logn)(时间换空间)
空间复杂度是O(n)(n/2+n/4+n/8…+8+4+2=n-2)
但是在实际的软件开发中,原始链表中存储的有可能是很大的对象,而索引结点只需要存储关键值和几个指针,并不需要存储对象,所以当对象比索引结点大很多时,那索引占用的额外空间就可以忽略了。

跳表的插入、删除(时间复杂度也是 O(logn)

插入
如果插入的数据过多,很有可能会退化成单链表,所以我们需要动态的更新索引。
可通过一个随机函数,生成一个K值,K值是第几层就在第几层添加该元素的索引。
当新增一个 key 值为 8 的节点时,首先新增一个节点到最底层的链表中,根据概率算出 level 值,再根据 level 值新建索引层,最后链接索引层的新节点。新增节点和链接索引都是基于 CAS 操作实现。

在这里插入图片描述
删除跳表结点
如果这个结点在索引中也有出现,我们除了要删除原始链表中的结点,还要删除索引中的。
当删除一个 key 值为 7 的结点时,首先找到待删除结点,将其 value 值设置为 null;之后再向待删除结点的next 位置新增一个标记结点,以便减少并发冲突;然后让待删结点的前驱节点直接越过本身指向的待删结点,直接指向后继结点,中间要被删除的结点最终将会被 JVM垃圾回收处理掉;最后判断此次删除后是否导致某一索引层没有其它节点了,并视情况删除该层索引 。

Redis 中的有序集合是通过跳表来实现的(其实是复合数据结构)(应该是由一个双hashmap构成的字典和跳跃表实现的)
插入、删除、查找以及迭代输出有序序列这几个操作,红黑树也可以完成,时间复杂度跟跳表是一样的。
但是,按照区间来查找数据这个操作,红黑树的效率没有跳表高。
对于按照区间查找数据这个操作,跳表可以做到 O(logn)的时间复杂度定位区间的起点,然后在原始链表中顺序往后遍历就可以了。这样做非常高效。
跳表更加灵活,它可以通过改变索引构建策略,有效平衡执行效率和内存消耗。

斐波那契数列优化:

 /**
     * 递归优化
     * HashMap 缓存
     * @param n
     * @return
     */
    public static Map<Integer,Integer> map = new HashMap<>();
    public int Fibonacci3(int n){
        if(n<=0){
            return 0;
        }
        if(n==1||n==2){
            return 1;
        }
        if(!map.containsKey(n)){
            map.put(n,Fibonacci3(n-1)+Fibonacci3(n-2));
        }
        return map.get(n);
    }

    /*
    非递归方法
     */
    public int Fibonacci2(int n){
        int a = 0;
        int b = 1;
        if(n == 0){
            return 0;
        }
        if (n == 1||n==2) {
            return 1;
        }
        int i=2;
        int sum=0;
        while(i<=n){
            sum=a+b;
            a=b;
            b=sum;
            i++;
        }
        return sum;
        }

LRU缓存算法
(自己实现的,时间复杂度有点高,运行大量数据会超出时间限制)

class LRUCache {
    private int capacity;
    private int count = 0;
    private List<Map<Integer,Integer>> list_HashMap ;
    public LRUCache(int capacity) {
        this.capacity = capacity;
       list_HashMap = new ArrayList<Map<Integer,Integer>>(capacity);
    }

    public int get(int key) {
        int value = 0;
        boolean flag = false;

        for(int i =0;i<list_HashMap.size();i++){
            if(list_HashMap.get(i).containsKey(key)){
                flag = true;
                Map<Integer, Integer> map = list_HashMap.get(i);
                value = map.get(key);
                list_HashMap.remove(i);
                list_HashMap.add(0,map);
            }
        }
        if(!flag){
            return -1;
        }
        return value;
    }

    public void put(int key, int value) {
        HashMap<Integer,Integer> map = new HashMap<>();
        map.put(key,value);
        if(count<capacity){
            for(int i =0;i<list_HashMap.size();i++){
                if(list_HashMap.get(i).containsKey(key)){
                    list_HashMap.remove(i);
                    count--;
                    break;
                }
            }
            list_HashMap.add(0,map);
            count++;
        }else{
            boolean flag = false;
            for(int i =0;i<list_HashMap.size();i++){
                if(list_HashMap.get(i).containsKey(key)){
                    flag = true;
                    list_HashMap.remove(i);
                    list_HashMap.add(0,map);
                    break;
                }
            }
            if(!flag){//false  没重复
                list_HashMap.add(0,map);
                list_HashMap.remove(capacity);
            }else{

            }
        }
    }
}

贪心算法
1 针对一组数据,我们定义了限制值和期望值,希望从中选出几个数据,在满足限制值的情况下,期望值最大。
2 每次选择当前情况下,在对限制值同等贡献量的情况下,对期望值贡献最大的数据。
3 我们举几个例子看下贪心算法产生的结果是否是最优的。

霍夫曼编码:
我们把每个字符看作一个节点,并且辅带着把频率放到优先级队列中。我们从队列中取出频率最小的两个节点 A、B,然后新建一个节点 C,把频率设置为两个节点的频率之和,并把这个新节点 C 作为节点 A、B 的父节点。最后再把 C 节点放入到优先级队列中。重复这个过程,直到队列中没有数据。
在这里插入图片描述

分治算法
分而治之:将原问题划分成 n 个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原问题的解。
需满足的条件:
1 原问题与分解成的小问题具有相同的模式;
2 原问题分解成的子问题可以独立求解,子问题之间没有相关性
3 具有分解终止条件,也就是说,当问题足够小时,可以直接求解;
4 可以将子问题合并成原问题,而这个合并操作的复杂度不能太高,否则就起不到减小算法总体复杂度的效果了。

例:求数组的逆序对
套用分治的思想来求数组 A 的逆序对个数。我们可以将数组分成前后两半 A1 和 A2,分别计算 A1 和 A2 的逆序对个数 K1 和 K2,然后再计算 A1 与 A2 之间的逆序对个数 K3。那数组A的逆序对个数就等于 K1+K2+K3。分治中可以使用归并排序,每次合并操作,我们都计算逆序对个数,把这些计算出来的逆序对个数求和,就是这个数组的逆序对个数了。

在这里插入图片描述

private int num = 0; //全局变量或者成员变量
    public  int count (int[] arr,int n){
        num = 0;
        mergeSortCounting(arr,0,n-1);
        return num;
    }
    private void mergeSortCounting(int[] arr, int p, int r) {
        if(p >=r){
            return ;
        }
        int q = (p+r)/2;
        mergeSortCounting(arr,p,q);
        mergeSortCounting(arr,q+1,r);
        merge(arr,p,q,r);
    }
    private void merge(int[] arr, int p, int q, int r) {
        int i = p,j = q+1,k=0;
        int[] tmp = new int[r-p+1];
        while(i<=q && j<=r){
            if(arr[i] <=arr[j]){
                tmp[k++] = arr[i++];
            }else{
                num +=(q-i+1);//统计p-q之间,比a[j]大的元素
                tmp[k++] = arr[j++];
            }
        }
        while(i<=q){  //处理剩下的
            tmp[k++] = arr[i++];
        }
        while(j <= r){//处理剩下的
            tmp[k++] = arr[j++];
        }
        for(i = 0;i<r-p;i++){//从tmp拷回给arr
            arr[p+i] = tmp[i];
        }
    }

如:亦可以使用分治,利用MapReduce提供高可靠,高性能,高容错的并行计算框架。

回溯算法:

深度优先搜索、八皇后、0-1 背包问题、图的着色、旅行商问题、数独、全排列、正则表达式匹配等等。

/**
 * 八皇后
 */
public class Question2_EightQueens {
    int[] result = new int[8];//成员变量,下标表示行,值表示queen存储在哪一列
    public void cal8Queens(int row){//调用方法:cal8Queens(0);
        if(row==8){//8个棋子都放置好了,打印结果
            printQueens(result);
            return; //8 行棋子都放好了,已经没法再往下递归了,
        }
        for(int column = 0;column<8;column++){//每一行都有8种放法
            if(isOk(row,column)){//有些放法不满足要求
                result[row] = column;//第row行的棋子放到了column列
                cal8Queens(row+1);//考察下一行
            }
        }
    }
    private boolean isOk(int row,int column){//判断row行column列放置是否合适
        int leftup = column-1;
        int rightup = column+1;
        for(int i =row-1;i>=0;--i){//逐行往上考察每一行
            if(result[i]==column){
                return  false;//第i行的column列有棋子吗?
            }
            if(leftup>=0){  //考察左上对角线,dii行leftup列有棋子吗
                if(result[i]==leftup){
                    return  false;
                }
            }
                if(rightup<8){ //考察右上对角线,第i行rightup列有棋子吗
                    if(result[i]==rightup){
                        return false;
                    }
                }
                --leftup;
                ++rightup;
        }
        return  false;
    }
    private void printQueens(int[] result){//打印一个二维矩阵
        for(int row = 0;row<8;row++){
            for(int column = 0;column<8;column++){
                if(result[row] == column){
                    System.out.print("Q ");
                }else{
                    System.out.println("* ");
                }
            }
            System.out.println();
            System.out.println();
        }

    }

}
/**
 * 01背包问题
 * 使用递归 回溯算法
 * 时间复杂度O(2^n)
 * 可以优化:递归中存在很多重复计算,可以用一个二维数组来记录每层可以达到的不同状态。
 */
public class Question3_01Bag {
    public int maxW = Integer.MIN_VALUE;//存储背包中总重量的最大值
    /**
     * @param i   考察到哪个物品
     * @param cw   表示当前已经装进去的物品重量
     * @param items  装到第几个了
     * @param n     物品个数
     * @param w     背包重量
     */
    public void f(int i ,int cw,int[] items,int n,int w){
        if (cw == w | i == n) {
            if(cw>maxW){
                maxW = cw;
            }
            return;
        }
        f(i+1,cw,items,n,w);//当前物品不装进背包
        if(cw+items[i]<=w){ //已经超过背包重量
            f(i+1,cw+items[i],items,n,w);//当前物品装进背包
        }
    }
}


    /**
     *01背包问题变形
     * 存储的最大价值是多少
     * @param i   考察到哪个物品
     * @param cw   表示当前已经装进去的物品重量
     * @param items  装到第几个了
     * @param n     物品个数
     * @param w     背包重量
     */
    public int maxV= Integer.MIN_VALUE;//存储背包中总价值
    private int[] items = {2,2,4,6,3};//物品重量
    private int[] value = {3,4,8,9,6}; //物品的价值
    private int n = 5; //物品个数
    private int w = 9; //背包承受的最大重量
    public void f(int i ,int cw, int cv){
        if (cw == w | i == n) {
            if(cv>maxV){
                maxV = cv;
            }
            return;
        }
        f(i+1,cw,cv);
        if(cw+items[i]<=w){ //已经超过背包重量
            f(i+1,cw+items[i],cv+value[i]);//选择装第i个物品
        }
    }
/**
 * 正则表达式
 */
public class Question4_Pattern {
    private boolean matched = false;
    private  char[] pattern ; //正则表达式
    private int plen; //正则表达式长度

    public Question4_Pattern(char[] pattern,int plen){
        this.pattern = pattern;
        this.plen = plen;
    }
    public boolean match(char[] text,int tlen){//文本串及长度
        matched  = false;
        rmatch(0,0,text,tlen);
        return matched;
    }

    private void rmatch(int ti, int pj, char[] text, int tlen) {
        if(matched){
            return;   //已经匹配了,就不要继续再递归
        }
        if(pj==plen){//正则表达式到结尾了
            if(ti == tlen){//文本串也到结尾了
                matched = true;
            }
        }
        if(pattern[pj] == '*'){  //匹配任意字符
            for(int k = 0;k<=tlen-ti;k++){
                rmatch(ti+k,pj+1,text,tlen);
            }
        }else if(pattern[pj] == '?'){//匹配0-1个
            rmatch(ti,pj+1,text,tlen);//0
            rmatch(ti+1,pj+1,text,tlen);//1
        }else if(ti<tlen && pattern[pj]==text[ti]){//纯字符匹配
            rmatch(ti+1,pj+1,text,tlen);
        }
    }

}

动态规划:(最优)
大部分动态规划能解决的问题,都可以通过回溯算法来解决,只不过回溯算法解决起来效率比较低。
把问题分解为多个阶段,每个阶段对应一个决策。记录每一个阶段可达的状态集合(去掉重复的),然后通过当前阶段的状态集合,来推导下一个阶段的状态集合,动态地往前推进。
1.最优子结构
最优子结构指的是,问题的最优解包含子问题的最优解。那我们也可以理解为,后面阶段的状态可以通过前面阶段的状态推导出来。
2.无后效性
第一层含义是,在推导后面阶段的状态的时候,我们只关心前面阶段的状态值,不关心这个状态是怎么一步一步推导出来的。第二层含义是,某阶段状态一旦确定,就不受之后阶段的决策影响。
3.重复子问题
不同的决策序列,到达某个相同的阶段时,可能会产生重复的状态。

最长公共子序列

/**
 * 最长公共子序列
 */
public class Question9_LongestIncrementalSubsequence {
    public int LIS1(int[] arr ,int length){
        int[] longest = new int[length];
        int i,j;
        for(i = 0;i<length;i++){
            longest[i] = 1;
        }
        int nLis = 1;
        for(i = 1;i<length;i++){
            for(j = 0;j<i;j++){  //当前值前面的值
                if(arr[j] <= arr[i]){
                    longest[i] = Math.max(longest[i],longest[j]+1);//看看原来的和前面的+1比较
                }
            }
            nLis = Math.max(nLis,longest[i]);//遍历一遍之后找到最大值
        }
        return nLis;
    }
}

01背包问题
时间复杂度:O(n*w)
我们把整个求解过程分为 n 个阶段,每个阶段会决策一个物品是否放到背包中。每个物品决策(放入或者不放入背包)完之后,背包中的物品的重量会有多种情况,也就是说,会达到多种不同的状态,对应到递归树中,就是有很多不同的节点。我们把每一层重复的状态(节点)合并,只记录不同的状态,然后基于上一层的状态集合,来推导下一层的状态集合。我们可以通过合并每一层重复的状态,这样就保证每一层不同状态的个数都不会超过 w 个(w 表示背包的承载重量)

在这里插入图片描述

 /**
     *
     * @param weight   物品重量
     * @param n   物品个数
     * @param w   背包可承受的重量
     * @return
     */
    public int knapsack(int[] weight,int n,int w){
        boolean[][] states  = new boolean[n][w+1];  //默认为false
        states[0][0] = true ;  //第一行的数据要特殊处理,可以利用哨兵优化
        states[0][weight[0]] = true;
        for(int i =1;i<n;i++){  //动态规划 状态转移
            for(int j = 0;j<w;j++){ //不把第i个物品放入背包
                if(states[i-1][j]==true){
                    states[i][j] = states[i-1][j];//不放进去的情况同步上一层的数据
                }
            }
            for(int j = 0;j<=w-weight[i];j++){//放入第i个物品
                if(states[i-1][j]==true){
                    states[i][j+weight[i]] = true;
                }
            }
        }
        for(int i = w;i>0;i--){//对最下层最后一个为true的结果输出
            if(states[n-1][i]==true){
                return i;
            }
        }
        return 0;
    }

   /**
     *减少空间消耗
     * @param weight   物品重量
     * @param n   物品个数
     * @param w   背包可承受的重量
     * @return
     */
    public int knapsack2(int[] weight,int n,int w){
        boolean[] states  = new boolean[w+1];  //默认为false
        states[0] = true ;  //第一行的数据要特殊处理,可以利用哨兵优化
        for(int i =1;i<n;i++){  //动态规划 状态转移
            for(int j = w-weight[i];j>=0;j--){ //第i个物品放入背包
                if(states[j]==true){
                    states[j+weight[i]] =true;
                }
            }
        }
        for(int i = w;i>0;i--){//输出结果
            if(states[i]==true){
                return i;
            }
        }
        return 0;
    }


   /**
     * 01背包 优化回溯算法中不必要的计算
     * 时间复杂度和空间复杂度都是O(n*w)
     * 加入物品价值的考虑,使得背包中拥有的物品价值最大
     * @param weight
     * @param value
     * @param n
     * @param w
     * @return
     */
    public static int knapsack3(int[] weight,int[] value,int n,int w){
        int[][] states = new int[n][w+1];
        for(int i = 0;i<n;i++){//初始化states
            for(int j = 0;j<w+1;j++){
                states[i][j] = -1;
            }
        }
        states[0][0] = 0;
        states[0][weight[0]] = value[0];
        for(int i =1;i<n;i++){//动态规划,状态转移
            for(int j = 0;j<=w;j++){//不选择第i个物品
                if(states[i-1][j]>=0){
                    states[i][j] = states[i-1][j];//同步上一层的状态
                }
            }
            for(int j = 0;j<=w-weight[i];j++){//选择第i个物品
                if(states[i-1][j] >=0){
                    int v = states[i-1][j]+value[i];//拿上一层的总价值加上当前i的价值
                    if(v>states[i][j+weight[i]]){
                        states[i][j+weight[i]] = v;
                    }
                }
            }
        }
        //找出最大值
        int maxValue = -1;
        for(int j = 0;j<=w;j++){
            if(states[n-1][j] >maxValue){
                maxValue = states[n-1][j];
            }
        }
        return maxValue;
    }

例子:求出从最高层移动到最底层的最短路径长度。(还没弄明白)
在这里插入图片描述

/**
     * 求出杨辉三角中从最高层移动到最底层的最短路径长度。
     *
     * @param matrix  杨辉三角
     * @return
     */
    int[][] matrix = {{5},{7,8},{2,3,4},{4,9,6,1},{2,7,9,4,5}};
    public int yangHuiTriangle(int[][] matrix){
        int[][] state = new int[matrix.length][matrix.length];
        state[0][0] = matrix[0][0];//初始状态
        for(int i = 1;i<matrix.length;i++){
            for(int j = 0;j<matrix.length;j++){
                if(j==0){
                    state[i][j] = state[i-1][j]+matrix[i][j];//上一层的state加上这层的权值
                }else if(j==matrix[i].length-1){
                    state[i][j] = state[i-1][j-1]+matrix[i][j];
                }else{
                    int top1 = state[i-1][j];
                    int top2 = state[i-1][j];
                    state[i][j] = Math.min(top1,top2)+matrix[i][j];
                }
            }
        }
        int minDis = Integer.MAX_VALUE;
        for(int i =0;i<matrix[matrix.length-1].length;i++){
            int distance = state[matrix.length-1][i];
            if(distance<minDis){
                minDis = distance;
            }
        }
        return minDis;
    }

二维数组最短路径问题

 public int minDist = Integer.MAX_VALUE;//全局变量保存最短路径值
    /**
     * 回溯算法求最短路径
     * @param i
     * @param j
     * @param dist
     * @param w
     * @param n
     */
    public void minDistBT(int i,int j,int dist,int[][] w,int n){
        //到达了n-1,n-1这个位置了
        if(i==n && j==n ){
            if(dist<minDist){
                minDist = dist;
            }
            return;
        }
        if(i<n){//往下走
            minDistBT(i+1,j,dist+w[i][j],w,n);
        }
        if(j<n){//往下走
            minDistBT(i,j+1,dist+w[i][j],w,n);
        }
    }

    /**
     * 动态规划
     * @param matrix
     * @param n
     * @return
     */
    public int minDistDP(int[][] matrix,int n){
        int[][] states = new int[n][n];
        int sum = 0;
        for(int j = 0;j<n;j++){//初始化第一行数据
            sum += matrix[0][j];
            states[0][j] = sum;
        }
        sum = 0;
        for(int i = 0;i<n;i++){//初始化第一列shuju
            sum += matrix[i][0];
            states[i][0] = sum;
        }
        for(int i = 1;i<n;i++){
            for(int j= 1;j<n;j++){
                states[i][j] = matrix[i][j] + Math.min(states[i][j-1],states[i-1][j]);
            }
        }
        return states[n-1][n-1];
    }

    /**
     * 备忘录+递归方式
     * @param i
     * @param j
     * @return
     */
    private int[][] matrix = {{1,3,5,9},{2,1,3,4},{5,2,7,6},{6,8,4,3}};
    private int n = 4;
    private int[][] mem = new int[4][4];
    public int minDist(int i,int j){//调用minDIst(n-1,n-1);
        if(i == 0 && j ==0 ){
            return matrix[0][0];
        }
        if(mem[i][j] > 0){
            return matrix[i][j];
        }
        int minLeft = Integer.MAX_VALUE;
        if(j-1>=0){
            minLeft = minDist(i,j-1);
        }
        int minUp = Integer.MAX_VALUE;
        if(i-1 >= 0){//不是(0,0)
            minUp = minDist(i-1,j);
        }
        int currMinDist = matrix[i][j] + Math.min(minLeft,minUp);
        mem[i][j] = currMinDist;
        return currMinDist;
    }

莱文斯坦距离

在这里插入图片描述

    /**
     *回溯算法
     * @param i
     * @param j
     * @param edist
     */
    private char[] a = "mitcmu".toCharArray();
    private char[] b = "mtacnu".toCharArray();
    private int n = 6;
    private int m = 6;
    private int minDist = Integer.MAX_VALUE;//存储结果
    public void lwstBT(int i,int j,int edist){
        if( i==n || j== m){
            if(i<n){
                edist += (n-i);
            }
            if(j<m){
                edist += (m-j);
            }
            if(edist<minDist){
                minDist = edist;
            }
            return ;
        }
        if(a[i] == b[j]){  //两字符匹配
            lwstBT(i+1,j+1,edist);
        }else {
            lwstBT(i+1,j,edist+1);//删除a[i] 或者b[j]前添加一个字符
            lwstBT(i,j+1,edist+1);//删除b[j] 或者a[i]前添加一个字符
            lwstBT(i+1,j+1,edist+1);//将a[i]和b[j]替换为相同的字符
        }
    }

    /**
     * 动态规划
     * 维护一个二维状态表
     * @param a
     * @param n
     * @param b
     * @param m
     * @return
     */
    public int lwstDP(char[] a,int n,char[] b,int m){
        int[][] minDist = new int[n][m];
        for(int j = 0;j<m;j++){//初始化第0行
            if(a[0] == b[j]){
                minDist[0][j] = j;//0 1 2 3 4 5
            }else if(j!=0){
                minDist[0][j] = minDist[0][j-1]+1;
            }else {
                minDist[0][j] = 1;
            }
        }
        for(int i = 0;i<m;i++){//初始化第0列
            if(a[i] == b[0]){
                minDist[i][0] = i;//0 1 2 3 4 5
            }else if(i!=0){
                minDist[i][0] = minDist[i-1][0]+1;
            }else {
                minDist[i][0] = 1;
            }
        }
        for(int i = 1;i<n;i++){//按行填表
            for(int j = 1;j<m;j++){
                if(a[i] == b[j]){
                    minDist[i][j] = min(minDist[i-1][j]+1,minDist[i][j-1]+1,minDist[i-1][j-1]);
                }else{
                    minDist[i][j] = min(minDist[i-1][j]+1,minDist[i][j-1]+1,minDist[i-1][j-1]+1);
                }
            }
        }
        return  minDist[n-1][m-1];

    }

    private int min(int x, int y, int z) {
        int minv = Integer.MAX_VALUE;
        if(x<minv){
            minv = x;
        }
        if(y<minv){
            minv = y;
        }
        if(z<minv){
            minv = z;
        }
        return minv;
    }

计算最长公共字串长度

/**
     *
     * 维护一个二维状态表
     * @param a
     * @param n
     * @param b
     * @param m
     * @return
     */
    public int lcs(char[] a,int n,char[] b,int m){
        int[][] maxlcs = new int[n][m];
        for(int j = 0;j<m;j++){//初始化第0行
            if(a[0] == b[j]){
                maxlcs[0][j] = 1;
            }else if(j!=0){
                maxlcs[0][j] = maxlcs[0][j-1];
            }else {
                maxlcs[0][j] = 0;
            }
        }
        for(int i = 0;i<m;i++){//初始化第0列
            if(a[i] == b[0]){
                maxlcs[i][0] =1;
            }else if(i!=0){
                maxlcs[i][0] = maxlcs[i-1][0];
            }else {
                maxlcs[i][0] = 0;
            }
        }
        for(int i = 1;i<n;i++){//按行填表
            for(int j = 1;j<m;j++){
                if(a[i] == b[j]){
                    maxlcs[i][j] = max(maxlcs[i-1][j]+1,maxlcs[i][j-1]+1,maxlcs[i-1][j-1]+1);//看看哪种方式得到的长度最长
                }else{
                    maxlcs[i][j] = max(maxlcs[i-1][j],maxlcs[i][j-1],maxlcs[i-1][j-1]);
                }
            }
        }
        return  maxlcs[n-1][m-1];

    }

    private int max(int x, int y, int z) {
        int maxv = Integer.MIN_VALUE;
        if(x>maxv){
            maxv = x;
        }
        if(y>maxv){
            maxv = y;
        }
        if(z>maxv){
            maxv = z;
        }
        return maxv;

    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值