数据结构与算法分析总结

二分查找:

非递归法:

package lession.arithme;

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 3, 8, 10, 11, 67, 10};
        System.out.println(binarySearch(arr, 67));
    }

    /**
     * @param arr    待查找的数组
     * @param target 返回对应下标
     * @return
     */
    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
}

递归法:

递归1:

package lession.search;

import java.util.ArrayList;
import java.util.List;

//二分查找必须是有序数组
public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 8, 10, 89, 1000, 1000, 1000, 1000, 1234};
        List<Integer> list = binarySearch2(arr, 0, arr.length - 1, 1000);
        System.out.println(list);
    }

    //二分查找算法

    /**
     * @param arr       带查找数组
     * @param left      左边索引
     * @param right     右边索引
     * @param findValue 带查找值
     * @return 找到返回下标, 没有找到返回-1
     */
    //查找一个
    public static int binarySearch(int[] arr, int left, int right, int findValue) {
        if (left > right) {
            return -1;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findValue > midVal) {
            return binarySearch(arr, mid + 1, right, findValue);
        } else if (findValue < midVal) {
            return binarySearch(arr, left, mid - 1, findValue);
        } else {
            return mid;
        }
    }

    //找到所有出现的数的下标
    public static List<Integer> binarySearch2(int[] arr, int left, int right, int findValue) {
        if (left > right) {
            return null;
        }
        int mid = (left + right) / 2;
        int midVal = arr[mid];
        if (findValue > midVal) {
            return binarySearch2(arr, mid + 1, right, findValue);
        } else if (findValue < midVal) {
            return binarySearch2(arr, left, mid - 1, findValue);
        } else {
            //向左扫描
            int tmp = mid - 1;
            List<Integer> list = new ArrayList<>();
            while (tmp >= 0 || arr[tmp] == findValue) {
                list.add(tmp);
                tmp -= 1;
            }
            list.add(mid);
            //向右扫描
            tmp = mid + 1;
            while (tmp <= arr.length - 1 || arr[tmp] == findValue) {
                list.add(tmp);
                tmp += 1;
            }
            return list;
        }
    }
}

递归2:

package exercise.luogu.binary;

import java.util.Scanner;

public class P2249 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] arr = new int[n];
        int[] crr = new int[m];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = sc.nextInt();
        }
        for (int i = 0; i < crr.length; i++) {
            crr[i] = sc.nextInt();
            int index = binarySearch(arr, crr[i]);
            if (index == -1) {
                System.out.print(-1 + " ");
            } else {
                System.out.print((index + 1) + " ");
            }
        }
    }

    public static int binarySearch(int[] arr, int findValue) {
        return binarySearchHelper(arr, 0, arr.length - 1, findValue, -1);
    }

    public static int binarySearchHelper(int[] arr, int left, int right, int findValue, int result) {
        if (left > right) {
            return result;
        }
        int mid = left + (right - left) / 2;
        if (arr[mid] < findValue) {
            return binarySearchHelper(arr, mid + 1, right, findValue, result);
        } else if (arr[mid] > findValue) {
            return binarySearchHelper(arr, left, mid - 1, findValue, result);
        } else {
            return binarySearchHelper(arr, left, mid - 1, findValue, mid);
        }
    }
}

分治算法

分治算法介绍

  1. 分治法是一种很重要的算法。字面上的解释是"分而治之",就是把一个复杂的问题分
    成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题。…直到最后子问题,可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换).

  2. 分治算法可以求解的一些经典问题
    2. 二分搜索
    3. 大整数乘法
    4. 棋盘覆盖
    5. 合并排序
    6. 快速排序
    7. 线性时间选择
    8. 最接近点对问题
    9. 循环赛日程表
    10. 汉诺塔

汉洛塔:
1.如果只有一个盘, A->C
2.如果有你>=2个盘,我们总是可以看成两个盘,1.最下边的盘2.上边的盘
3.先把上面的盘移到B,在把最下边的盘移到C,在B上的盘移到C

代码如下:

package lession.arithme;

//分治算法
public class HanLuoTa {
    public static void main(String[] args) {
        hanLuoTa(5, 'A', 'B', 'C');
    }

    /**
     * @param num 盘的数量
     * @param a   A位置
     * @param b   B位置
     * @param c   C位置
     */
    public static void hanLuoTa(int num, char a, char b, char c) {

        if (num == 1) {
            System.out.println("第1个盘从:" + a + "->" + c);

        } else {
            //总是看出两个盘,
            // 1先把上边的盘移动到B,中间媒介C
            hanLuoTa(num - 1, a, c, b);
            //2把最下边移到c
            System.out.println("第" + num + "个盘从:" + a + "->" + c);

            //3把b的所有盘移到c
            hanLuoTa(num - 1, b, a, c);
        }
    }
}

动态规划

动态规划算法介绍

  1. 动态规划(dynamicprogramming)算法的核心思想是:将大问题划分为小问题进 行解决,从而一步步获取最优解的处理算法
  2. 动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子 问题,先求解子问题,然后从这些子问题的解得到原问题的解。
  3. 与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不
    是互相独立的。(即下一个子阶段的求解是建立在上一个子阶段的解的基础上, 进行进一步的求解)
  4. 动态规划可以通过填表的方式来逐步推进,得到最优解,

动态规划算法最佳实践-背包问题
思路分析和图解
背包问题主要是指一个给定容量的背包,若干具有一定价值和重量的物品,如何选
择物品放入背包使物品的价值最大。其中又分01背包和完全背包含背包指的是:
每种物品都有无限件可用)
这里的问题属于01背包,即每个物品最多放一个。而无限背包可以转化为01背包

思路分析和图解
算法的主要思想,利用动态规划来解决。每次遍历到的第个物品,根据w们和v们来
确定是否需要将该物品放入背包中。即对于给定的几个物品,设v们,w们分别为第个
物品的价值和重量,c为背包的容量。再令v们们表示在前个物品中能够装入容量为
的背包中的最大价值。则我们有下面的结果:

(1)v门【0]-v[o]-0;//表示填入表第一行和第一行和第一列是0

(2)当w门》时:v门门-v[i-1]//当准备加入新增的商品的容量大于当前背包的容量
时,就直接使用上一个单元格的装入策略

(3)当j>-w[门时:Math.max(v[ i-1 ] [ j ] , v[ i ] + v[ i-1 ][ j - w[ i ] ] )
i/当准备加入的新增的商品的容量小于等于当前背包的容量

装入的方式: 动态规划背包思路

lvi-110:就是上一个单元格的装入的最大值
lv们:表示当前商品的价值v[-110-w门:装入-1商品,到剩余空间;w目的最大值

在这里插入图片描述
在这里插入图片描述

[NOIP2005 普及组] 采药

题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

第一行有 2 2 2 个整数 T T T 1 ≤ T ≤ 1000 1 \le T \le 1000 1T1000)和 M M M 1 ≤ M ≤ 100 1 \le M \le 100 1M100),用一个空格隔开, T T T 代表总共能够用来采药的时间, M M M 代表山洞里的草药的数目。

接下来的 M M M 行每行包括两个在 1 1 1 100 100 100 之间(包括 1 1 1 100 100 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出在规定的时间内可以采到的草药的最大总价值。

样例 #1

样例输入 #1

70 3
71 100
69 1
1 2

样例输出 #1

3

提示

【数据范围】

  • 对于 30 % 30\% 30% 的数据, M ≤ 10 M \le 10 M10
  • 对于全部的数据, M ≤ 100 M \le 100 M100

【题目来源】

NOIP 2005 普及组第三题

【代码如下】

package exercise.luogu.dp;

import java.util.Scanner;
//暴力
public class P1048 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        int n = sc.nextInt();
        int[] val = new int[n];
        int[] time = new int[n];
        int dp[][] = new int[n + 1][t + 1];

        for (int i = 0; i < n; i++) {
            time[i] = sc.nextInt();
            val[i] = sc.nextInt();
        }

        for (int i = 1; i <= val.length; i++) {
            for (int j = 1; j <= t; j++) {
                if (time[i - 1] > j) {
                    dp[i][j] = dp[i - 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], val[i - 1] + dp[i - 1][j - time[i - 1]]);
                }
            }
        }

        int maxValue = dp[val.length][t];
        System.out.println(maxValue);
    }
}
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/qq_74748121/article/details/136073655

暴力匹配

package lession.arithme;

//暴力匹配
public class ViolenceMatch {
    public static void main(String[] args) {
        String s1 = "硅硅谷尚硅谷你尚硅尚硅谷你尚硅谷你尚硅你好";
        String s2 = "尚硅谷你尚硅你";
        System.out.println(index(s1, s2));
    }

    //暴力匹配1
    public static int violenceMatch(String s1, String s2) {
        char[] charArray1 = s1.toCharArray();
        char[] charArray2 = s2.toCharArray();
        int len1 = charArray1.length;
        int len2 = charArray2.length;

        int i = 0;
        int j = 0;
        while (i < len1 && j < len2) {//保证匹配,不越界
            if (charArray1[i] == charArray2[j]) {
                i++;
                j++;
            } else {
                i = i - (j - 1);//重新赋值i
                j = 0;  //s2重新赋值为开始 即j=0
            }
        }
        if (j == len2) {
            return i - j;
        }
        return -1;
    }
    //暴力匹配2
    private static int index(String main, String child) {
        int i = 0, m = main.length(), n = child.length();
        if (m < n) {
            return 0;
        }
        while (i <= m-n) {
            String substring = main.substring(i, i + n);

            if (!substring.equals(child)) {
                i++;
            } else {
                return i;
            }
        }
        return 0;
    }
}

KMP算法

kmp是一个解决模式串在文本串是否出现过,如果出现过,最早出现的位置的
经典算法,knuth-morris-pratt字符串查找算法,简称为"kmp算法",常用于在一个文本
串s内查找一个模式串p的出现位置,这个算法由donaldknuth,vaughanpratt,.
jamesh.morris三人于1977年联合发表,故取这3人的姓民命名此算法。
kmp方法算法就利用之前判断过信息,通过一个next数组,保存模式事中前后
最长公共子序列的长度,每次回溯时,通过next数组找到,前面匹配过的位置,
省去了大量的计算时间

"部分匹配值"就是"前级"和"后级"的最长的共有元素的长度。以"abcdabd"为例,
一"a"的前缀和后缀都为空集,共有元素的长度为0;
一"ab"的前缀为【a],后缀为【b,共有元素的长度为0;

"abc"的前缀为【ab],后缀为【bc,c],共有元素的长度l0:

  • "abcd"的前缀为【a,abc],后缓为【bcd,cd,d],共有元素的长度为0;
  • “abcda"的前缓为的ab,abc,abcd],后缓为【bcda,da,da,a]: al,共有元素为”,长度为1;
  • “abcdab"的前缓为1a,abc,abcd,abcdal,后缓为【bcdab,cdab,cdab,dab,ab,b),共有元素为"ab”,长度为2;
  • "abcdabd"的前袋为【a,ab,abc,abcd,abcda,abcdab];后缓为【bcdabd,cdabd,cdabd,dabd,abd,d],
    共有元素的长度为0.
    【代码如下】
package lession.arithme;

public class KMP {
    public static void main(String[] args) {
        String s1 = "bbc abcdab abcdabcdabde";
        String s2 = "abcdabd";
        int[] next = kmpNext(s2);
        System.out.println(kmpSearch(s1, s2, next));
    }
    //写出kmp搜索方法

    /**
     * @param s1   原字符串
     * @param s2   字串
     * @param next (字串对应)部分匹配表
     * @return 如果不匹配则返回-1,匹配的起始位置
     */
    public static int kmpSearch(String s1, String s2, int[] next) {

        //遍历
        for (int i = 0, j = 0; i < s1.length(); i++) {
            while (j > 0 && s1.charAt(i) != s2.charAt(j)) {
                j = next[j - 1];
            }
            if (s1.charAt(i) == s2.charAt(j)) {
                j++;
            }
            if (j == s2.length()) {
                return i - j + 1;
            }
        }
        return -1;
    }

    //获取到字串部分匹配
    public static int[] kmpNext(String s2) {
        //船舰一个数组保存匹配表,首先我们都是在找是否有最大公共前后缀
        int[] next = new int[s2.length()];
        next[0] = 0;//如果字符串长度为1,那么他的无前后缀则为0
        //i表示后缀,j表示前缀
        for (int i = 1, j = 0; i < s2.length(); i++) {
            while (j > 0 && s2.charAt(i) != s2.charAt(j)) {
                j = j - 1;// 回溯找到能与当前字符匹配的位置
                // 貌似懂了,但是好迷糊
            }
            //部分匹配需要加1
            if (s2.charAt(i) == s2.charAt(j)) {
                j++;
            }
            next[i] = j;
        }

        return next;
    }
}

【代码如下】

**public class test1 {
    public static void main(String[] args) {
        String text = "ABABDABACDABABCABAB";
        String pattern = "ABABCABAB";
        int[] next = new int[pattern.length()];
        calculateNext(pattern, next);
        int index = match(text, pattern, next);
        if (index != -1) {
            System.out.println("为序:" + index);
        } else {
            System.out.println("找不到为序");
        }
    }

    public static void calculateNext(String pattern, int[] next) {
        int len = pattern.length();
        for (int i = 1; i < len; i++) {
            next[i] = -1;
            for (int j = 0; j < i; j++) {
                if (pattern.charAt(i) == pattern.charAt(j) && (i - j) > next[i]) {
                    next[i] = next[j];
                }
            }
        }
    }

    public static int match(String text, String pattern, int[] next) {
        int m = text.length();
        int n = pattern.length();
        for (int i = 0; i <= m - n; i++) {
            int j;
            for (j = 0; j < n; j++) {
                if (text.charAt(i + j) != pattern.charAt(j)) {
                    break;
                }
            }
            if (j == n) {
                return i; 
            } else if (next[j] != -1) {
                i = i + next[j];
            }
        }
        return -1; // pattern not found in text
    }
}**

贪心算法

贪心算法介绍

  1. 贪婪算法(贪心算法)是指在对问题进行求解时,在每一步选择中都采取最好或
    者最优(即最有利)的选择,从而希望能够导致结果是最好或者最优的算法

  2. 贪婪算法所得到的结果不一定是最优的结果(有时候会是最优解),但是都是相
    对近似(接近)最优解的结果

【深基12.例1】部分背包问题

题目描述

阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N ( N ≤ 100 ) N(N \le 100) N(N100) 堆金币,第 i i i 堆金币的总重量和总价值分别是 m i , v i ( 1 ≤ m i , v i ≤ 100 ) m_i,v_i(1\le m_i,v_i \le 100) mi,vi(1mi,vi100)。阿里巴巴有一个承重量为 T ( T ≤ 1000 ) T(T \le 1000) T(T1000) 的背包,但并不一定有办法将全部的金币都装进去。他想装走尽可能多价值的金币。所有金币都可以随意分割,分割完的金币重量价值比(也就是单位价格)不变。请问阿里巴巴最多可以拿走多少价值的金币?

输入格式

第一行两个整数 N , T N,T N,T

接下来 N N N 行,每行两个整数 m i , v i m_i,v_i mi,vi

输出格式

一个实数表示答案,输出两位小数

样例 #1

样例输入 #1

4 50
10 60
20 100
30 120
15 45

样例输出 #1

240.00

import java.util.*;

class Vw {
    double weight;
    double value;
    double rate;

    public Vw(double weight, double value, double rate) {
        this.weight = weight;
        this.value = value;
        this.rate = rate;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double n = sc.nextInt();
        double t = sc.nextInt();
        List<Vw> list = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            double weight = sc.nextInt();
            double value = sc.nextInt();
            list.add(new Vw(weight, value, value / weight));
        }
        Collections.sort(list, new Comparator<Vw>() {
            @Override
            public int compare(Vw o1, Vw o2) {
                return Double.compare(o2.rate, o1.rate);
            }
        });
        double values = 0;
        for (Vw vw : list) {
            if (t >= 0) {
                if (t >= vw.weight) {
                    values += vw.value;
                    t = t - vw.weight;
                } else {
                    values = values + t * vw.rate;
                    t = 0;
                }
            } else {
                break;
            }
        }
        System.out.printf("%.2f", values);
    }
}

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知意..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值