赞
踩
1.二分查找(非递归)
2.分治算法
3.动态规划算法
4.KMP算法
5.贪心算法
6.普里姆算法
7.克鲁斯卡尔算法
8.迪杰斯特拉算法
9.弗洛伊德算法
就是不使用递归的二分查找,这里不做介绍
public class BinarySearchNoRecur { public static void main(String[] args) { int[] arr = { 1, 3, 8, 10, 11, 67, 100 }; int i = binarySearch(arr, 11); System.out.println(i); } 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; } }
比起算法,更像是一种思维
分治算法应用场景:
汉诺塔:
问题分析:
public class Hanoitower { public static void main(String[] args) { hanoiTower(6, 'a', 'b', 'c'); } public static void hanoiTower(int num, char a, char b, char c) { // 如果只有一个盘 if (num == 1) { System.out.println("第1个盘从 " + a + "->" + c); } else { // 如果我们有n >= 2情况,我们总是可以看做是两个盘1.最下面一个盘2.上面的盘 // 1.先把最上面的所有盘A -> B //将b参数和c参数互换,下一次递归的任务就是将a移动到b,而不会使用到c,c的使用在下下次递归中 hanoiTower(num - 1, a, c, b); // 2.将最下面的盘A->C System.out.println("第" + num + "个盘从 " + a + "->" + c); // 3.把B塔的所有盘从B -> C,移动过程使用A塔 hanoiTower(num - 1, b, a, c); } } }
背包问题(0-1背包):
左表有基本信息,右表为最优解表
import java.util.Arrays; public class KnapsackProblem { public static void main(String[] args) { // 物品的重量 int[] weight = { 1, 4, 3 }; // 物品的价值 int[] value = { 1500, 3000, 2000 }; // 背包的容量 int capacity = 4; // 物品的个数 int num = weight.length; // 创建一个最优解数组(二维数组) // v[][]的每一个值都表示一种最优解 // 例如: // v[2][3]表示:当容量为3时,只有前两种物品可选时存在的最优解 // v[1][2]表示:当容量为2时,只有第一种物品可选时存在的最优解 int[][] v = new int[num + 1][capacity + 1]; // 为了记录放入商品的路径,定义一个二维数组 //如果有新商品加入时,则对应商品数值置为1,否则不处理 int[][] path = new int[num + 1][capacity + 1]; // 初始化第一行和第一列,为0 for (int i = 0; i < v.length; i++) { v[i][0] = 0; } for (int i = 0; i < v[0].length; i++) { v[0][i] = 0; } // 根据公式进行动态规划处理 for (int i = 1; i < v.length; i++) {// 不处理第一行 for (int j = 1; j < v[0].length; j++) {// 不处理第一列 // 如果重量比容量大,则无法放入,最优解为之前的值 // if (weight[i - 1] > j) { v[i][j] = v[i - 1][j]; } else { // 如果容量足够,那么最优解可能有两种情况 // 1.放入物品的价值 + 剩余空间的最优解 // 2.即使能放入物品,但是最优解不比上次的最优解大 // v[i][j] = Math.max(v[i - 1][j], value[i - 1] + v[i - 1][j - weight[i - 1]]); if (v[i - 1][j] < value[i - 1] + v[i - 1][j - weight[i - 1]]) { v[i][j] = value[i - 1] + v[i - 1][j - weight[i - 1]]; path[i][j] = 1; } else { // 如果只是用之前的值替换,则表示没有出现最优解 v[i][j] = v[i - 1][j]; } } } } for (int[] i : v) { System.out.println(Arrays.toString(i)); } for (int[] i : path) { System.out.println(Arrays.toString(i)); } int i = path.length - 1; int j = path[0].length - 1; while (i > 0) {// 逆向遍历 if (path[i][j] == 1) { System.out.printf("第%d个商品放入到背包\n", i); j -= weight[i - 1]; } i--; } } }
参考资料:https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html
public class Kmp { public static void main(String[] args) { String string1 = "BBC ABCDAB ABCDABCDABDE"; String string2 = "ABCDABD"; int[] next = kmpNext("ABCDABD"); System.out.println(kmpSearch(string1, string2, next)); } /** * * @param str1 原字符串 * @param str2 子串 * @param next 部分匹配表,是子串对应的部分匹配表 * @return 如果是-1就是没有匹配到,否则返回第一个匹配的位置 */ public static int kmpSearch(String str1, String str2, int[] next) { // 遍历 for (int i = 0, j = 0; i < str1.length(); i++) { // KMP核心算法 while (j > 0 && str1.charAt(i) != str2.charAt(j)) { j = next[j - 1]; } if (str1.charAt(i) == str2.charAt(j)) { j++; } if (j == str2.length()) { return i - j + 1; } } return -1; } // 获取到一个字符串的部分匹配值表 public static int[] kmpNext(String dest) { // 创建一个next数组保存部分匹配值 int[] next = new int[dest.length()]; // 第一个肯定是0,因为长度为一,没有前缀和后缀 next[0] = 0;// 如果字符串时长度为1部分匹配值就是0 for (int i = 1, j = 0; i < dest.length(); i++) { // 当dest.chatAt(i) != dest.chatAt(j),我们需要从next[j-1]获取新的j // 直到发现有dest.chatAt(i) == dest.chatAt(j)时退出、 // 要j大于0才走这里 while (j > 0 && dest.charAt(i) != dest.charAt(j)) { j = next[j - 1]; } // 当dest.chatAt(i) == dest.chatAt(j)满足时,部分匹配值就是+1 if (dest.charAt(i) == dest.charAt(j)) { j++; } next[i] = j; } return next; } // 暴力匹配 public static int violenceMatch(String str1, String str2) { char[] s1 = str1.toCharArray(); char[] s2 = str2.toCharArray(); boolean flag = false; int s1len = s1.length; int s2len = s2.length; int i = 0; int j = 0; while (i < s1len && j < s2len) { if (s1[i] == s2[j]) { i++; j++; } else { i = i - (j - 1); j = 0; } } if (j == s2len) { return i - j; } else { return -1; } } }
import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; public class Greedy { public static void main(String[] args) { HashMap<String, HashSet<String>> broadcasts = new HashMap<String, HashSet<String>>(); HashSet<String> hashset1 = new HashSet<String>(); hashset1.add("北京"); hashset1.add("上海"); hashset1.add("天津"); HashSet<String> hashset2 = new HashSet<String>(); hashset2.add("北京"); hashset2.add("广州"); hashset2.add("深圳"); HashSet<String> hashset3 = new HashSet<String>(); hashset3.add("成都"); hashset3.add("上海"); hashset3.add("杭州"); HashSet<String> hashset4 = new HashSet<String>(); hashset4.add("天津"); hashset4.add("上海"); HashSet<String> hashset5 = new HashSet<String>(); hashset5.add("杭州"); hashset5.add("大连"); broadcasts.put("K1", hashset1); broadcasts.put("K2", hashset2); broadcasts.put("K3", hashset3); broadcasts.put("K4", hashset4); broadcasts.put("K5", hashset5); // allAreas,如果覆盖到其中一个地区,就会移除地区,如果全覆盖,则为空 HashSet<String> allAreas = new HashSet<String>(); allAreas.add("北京"); allAreas.add("上海"); allAreas.add("天津"); allAreas.add("杭州"); allAreas.add("大连"); allAreas.add("成都"); allAreas.add("广州"); allAreas.add("深圳"); // 创建ArrayList,存放选择的电台集合 ArrayList<String> selects = new ArrayList<String>(); String maxKey = null; HashSet<String> tempSet = new HashSet<String>(); while (allAreas.size() != 0) { maxKey = null; for (String key : broadcasts.keySet()) { tempSet.clear(); HashSet<String> areas = broadcasts.get(key); tempSet.addAll(areas); // 求出交集 tempSet.retainAll(allAreas); // 求交集后,如果大小大于0,则表示还能覆盖新的地区,如果不大于零,就没有必要加入 //如果maxKey为空,则赋值当前的key //如果maxKey不为空,则保存的是上次的最大覆盖地区key //如果当前这个集合包含的未覆盖地区的数量,比maxKey指向的集合未覆盖的地区还多,就重置maxKey if (tempSet.size() > 0 && (maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())) { maxKey = key; } } if (maxKey != null) { //加入选择 selects.add(maxKey); //移除已添加的地区 allAreas.removeAll(broadcasts.get(maxKey)); } } //当退出循环后,则就按照贪心算法得到一个解 System.out.println(selects); } }
import java.util.Arrays; public class Prim { public static void main(String[] args) { char[] data = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; int verxs = data.length; int[][] weight = new int[][] { { 10000, 5, 7, 10000, 10000, 10000, 2 }, { 5, 10000, 10000, 9, 10000, 10000, 3 }, { 7, 10000, 10000, 10000, 8, 10000, 10000 }, { 10000, 9, 10000, 10000, 10000, 4, 10000 }, { 10000, 10000, 8, 10000, 10000, 5, 4 }, { 10000, 10000, 10000, 4, 5, 10000, 6 }, { 2, 3, 10000, 10000, 4, 6, 10000 } }; MGraph mGraph = new MGraph(verxs); MinTree minTree = new MinTree(); minTree.createGraph(mGraph, verxs, data, weight); minTree.showGaph(mGraph); minTree.prim(mGraph, 1); } } //创建最小生成树 -> 村庄的图 class MinTree { /** * * @param graph 图对象 * @param verxs 图对应的顶点个数 * @param data 图的各个顶点的值 * @param weight 图的邻接矩阵 */ public void createGraph(MGraph graph, int verxs, char data[], int[][] weight) { int i, j; for (i = 0; i < verxs; i++) { graph.data[i] = data[i]; for (j = 0; j < verxs; j++) { graph.weight[i][j] = weight[i][j]; } } } public void showGaph(MGraph graph) { for (int i = 0; i < graph.weight.length; i++) { System.out.println(Arrays.toString(graph.weight[i])); } } /** * * @param graph 图 * @param value 表示从图的第一个顶点开始生成,就是起点的下标 */ public void prim(MGraph graph, int value) { int[] visited = new int[graph.verxs]; visited[value] = 1; int h1 = -1; int h2 = -1; int minWeight = 10000; for (int k = 1; k < graph.verxs; k++) {//因为有graph.verxs顶点,普利姆算法借宿后,有graph.verxs-1边 // 这个是确定每一次生成的子图,和那个结点的距离最近 // 以下的双重循环是为了遍历每一条边,i为起点的下标,j为终点的下标 for (int i = 0; i < graph.verxs; i++) {// i结点表示被访问的结点 for (int j = 0; j < graph.verxs; j++) {// j结点表示还没有访问过的结点 //当然这样做有点冗余 //这里需要过滤一下,i已访问,j未访问才是需要的 //并在这些条件下挑出距离最小的那一个 if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight) { // 替代minWeight minWeight = graph.weight[i][j]; //记录下距离最小边的记录 h1 = i; h2 = j; } } } // 找到一条边 System.out.println("边<" + graph.data[h1] + "," + graph.data[h2] + ">权值:" + minWeight); visited[h2] = 1; // minWeight 重新设置为最大值10000 minWeight = 10000; } } } class MGraph { int verxs;// 表示圆的结点个数 char[] data;// 存放节点数据 int[][] weight;// 存放边,就是我们的邻接矩阵 public MGraph(int verxs) { this.verxs = verxs; data = new char[verxs]; weight = new int[verxs][verxs]; } }
import java.util.Arrays; public class Kruskal { public int edgeNum;// 边的个数 public char[] vertexs;// 顶点数组 public int[][] matrix;// 邻接矩阵 public static final int INF = Integer.MAX_VALUE; public static void main(String[] args) { char[] vertexs = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; int matrix[][] = { /* A *//* B *//* C *//* D *//* E *//* F *//* G */ /* A */ { 0, 12, INF, INF, INF, 16, 14 }, /* B */ { 12, 0, 10, INF, INF, 7, INF }, /* C */ { INF, 10, 0, 3, 5, 6, INF }, /* D */ { INF, INF, 3, 0, 4, INF, INF }, /* E */ { INF, INF, 5, 4, 0, 2, 8 }, /* F */ { 16, 7, 6, INF, 2, 0, 9 }, /* G */ { 14, INF, INF, INF, 8, 9, 0 } }; Kruskal kruskal = new Kruskal(vertexs, matrix); kruskal.kruskal(); // kruskal.print(); } public Kruskal(char[] vertexs, int[][] matrix) { int vlen = vertexs.length; this.vertexs = new char[vlen]; // 使用复制的方式 this.vertexs = vertexs.clone(); this.matrix = matrix.clone(); for (int i = 0; i < matrix.length; i++) { for (int j = i + 1; j < matrix[0].length; j++) { if (matrix[i][j] != INF) { edgeNum++; } } } } public void print() { System.out.println("邻接矩阵:"); for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[0].length; j++) { System.out.printf("%10d\t", matrix[i][j]); } System.out.println(); } } public void sortEdges(EData[] edges) { for (int i = 0; i < edges.length - 1; i++) { for (int j = 0; j < edges.length - 1 - i; j++) { if (edges[j].weight > edges[j + 1].weight) { EData tempData = edges[j]; edges[j] = edges[j + 1]; edges[j + 1] = tempData; } } } } /** * * @param ch * @return 返回下标 */ public int getPosition(char ch) { for (int i = 0; i < vertexs.length; i++) { if (vertexs[i] == ch) { return i; } } return -1; } /** * 功能:获取图中的边, 通过matrix 邻接矩阵类获取 * * @return */ public EData[] getEdges() { int index = 0; EData[] edges = new EData[edgeNum]; for (int i = 0; i < vertexs.length; i++) { for (int j = i + 1; j < vertexs.length; j++) { if (matrix[i][j] != INF) { edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]); } } } return edges; } /** * 功能:获取下标 为 i 的顶点的终点,用于后面判断两个顶点的终点是否相同 * * @param ends:数组就是记录了各个顶点对应的终点是哪个,ends数组是在遍历过程中,逐步形成 * @param i:表示传入的顶点对应的下标 * @return 返回的就是下标为 i 的这个顶点对应的终点的下标 * */ public int getEnd(int[] ends, int i) { while (ends[i] != 0) { i = ends[i]; } System.out.println("End:"+Arrays.toString(ends)); return i; } public void kruskal() { int index = 0;// 表示最后结果数组的索引 int[] ends = new int[edgeNum];// 用于保存 EData[] rets = new EData[edgeNum]; EData[] edges = getEdges(); sortEdges(edges); for (int i = 0; i < edgeNum; i++) { int p1 = getPosition(edges[i].start); int p2 = getPosition(edges[i].end); int m = getEnd(ends, p1);// m = 4 int n = getEnd(ends, p2);// n = 5 // 是否构成回路 if (m != n) { ends[m] = n; rets[index++] = edges[i]; } } for (int i = 0; i < index; i++) { System.out.println(rets[i]); } } } //创建边的类 class EData { char start;// 起点 char end;// 终点 int weight;// 权值 public EData(char start, char end, int weight) { this.start = start; this.end = end; this.weight = weight; } @Override public String toString() { return "[EData <" + start + ", " + end + "> weight=" + weight + "]"; } }
import java.util.Arrays; public class Dijkstra { public static void main(String[] args) { char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; final int N = 65535; int[][] matrix = new int[][] { { N, 5, 7, N, N, N, 2 }, { 5, N, N, 9, N, N, 3 }, { 7, N, N, N, 8, N, N }, { N, 9, N, N, N, 4, N }, { N, N, 8, N, N, 5, 4 }, { N, N, N, 4, 5, N, 6 }, { 2, 3, N, N, 4, 6, N }, }; Graph graph = new Graph(vertex, matrix); // graph.showGraph(); graph.dsj(6); graph.showDjs(); } } class Graph { public char[] vertex; public int[][] matrix; // 已经访问的顶点的集合 public VisitedVertex vv; public Graph(char[] vertex, int[][] matrix) { this.vertex = vertex; this.matrix = matrix; } public void showDjs() { vv.show(); } public void showGraph() { for (int[] i : matrix) { System.out.println(Arrays.toString(i)); } } /** * * @param index 表示出发顶点对应的下标 */ public void dsj(int index) { //新创建的已访问数组 vv = new VisitedVertex(vertex.length, index); //首先更新一下起点 update(index); for (int j = 1; j < vertex.length; j++) { index = vv.updateArr(); update(index); } } // 更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点 public void update(int index) { int len = 0; // 根据遍历我们的邻接矩阵的 matrix[index]行 for (int j = 0; j < matrix[index].length; j++) { // len含义是:出发顶点到index顶点的距离 + 从index顶点到j顶点的距离的和 //一开始dis的值都是65535 len = vv.getDis(index) + matrix[index][j]; // 如果j没有被访问过,并且len小于出发顶点到j顶点的距离,就需要更新 if (!vv.in(j) && len < vv.getDis(j)) { vv.updatePre(j, index);// 更新j顶点的前驱为index顶点 vv.updateDis(j, len);// 更新出发顶点到j顶点的距离 } } } } //已访问顶点的集合 class VisitedVertex { // 记录各个顶点是否访问过,1表示访问过,0表示未访问,会动态更新 public int[] already_arr; // 每个小标对应的值为前一个顶点下标,会动态更新 public int[] pre_visited; // 记录出发顶点到其他所有顶点的距离,比如G为出发顶点,就会记录G到其他顶点的距离,会动态更新,求的最短距离就会存放到dis public int[] dis; /** * * @param lenght 表示顶点的个数 * @param index 表示出发顶点对应的下标 */ public VisitedVertex(int lenght, int index) { this.already_arr = new int[lenght]; this.pre_visited = new int[lenght]; this.dis = new int[lenght]; // 初始化dis数组 Arrays.fill(dis, 65535); // 设置出发顶点的访问距离为0 this.dis[index] = 0; this.already_arr[index] = 1; } /** * 功能:判断index顶点是否访问过 * * @param index * @return 如果访问过,就放回true,否则返回false */ public boolean in(int index) { return already_arr[index] == 1; } /** * 功能:更新出发顶点到index顶点的距离 * * @param index * @param len */ public void updateDis(int index, int len) { dis[index] = len; } /** * 功能:更新顶点的前驱为index结点 * * @param pre * @param index */ public void updatePre(int pre, int index) { pre_visited[pre] = index; } /** * 功能:返回出发顶点到index顶点的距离 * * @param index */ public int getDis(int index) { return dis[index]; } /** * 继续选择并返回新的访问顶点,比如这里的G,就是A点作为新的访问顶点(不是出发点) * * @return */ public int updateArr() { int min = 65535, index = 0; for (int i = 0; i < already_arr.length; i++) { if (already_arr[i] == 0 && dis[i] < min) { min = dis[i]; index = i; } } already_arr[index] = 1; return index; } public void show() { char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'D', 'G' }; int count = 0; for (int i : dis) { if (i != 65535) { System.out.print(vertex[count++] + "(" + i + ")"); } } } }
import java.util.Arrays; public class Floyd { public static void main(String[] args) { char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; int[][] matrix = new int[vertex.length][vertex.length]; final int N = 65535; matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 }; matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 }; matrix[2] = new int[] { 7, N, 0, N, 8, N, N }; matrix[3] = new int[] { N, 9, N, 0, N, 4, N }; matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 }; matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 }; matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 }; Graph2 graph = new Graph2(vertex.length, matrix, vertex); graph.floyd(); graph.show(); } } class Graph2 { public char[] vertex;// 存放顶点 public int[][] dis;// 保存,从各个顶点出发到其他顶点的距离,最后的结构,也是保存在该数组 public int[][] pre;// 前驱 public Graph2(int length, int[][] matrix, char[] vertex) { this.vertex = vertex; this.dis = matrix; this.pre = new int[length][length]; // 对pre数组初始化 // 一开始前驱是本身 for (int i = 0; i < length; i++) { Arrays.fill(pre[i], i); } } public void show() { char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; for (int k = 0; k < dis.length; k++) { for (int i = 0; i < dis.length; i++) { System.out.print(vertex[pre[k][i]] + " "); } System.out.println(); for (int i = 0; i < dis.length; i++) { System.out.print("(" + vertex[k] + "到" + vertex[i] + "的最短路径是" + dis[k][i] + ")"); } System.out.println(); System.out.println(); } } public void floyd() { int len = 0; // 从中间顶点的遍历 for (int k = 0; k < dis.length; k++) { // 从i顶点出发a、b、c、d、。。。 for (int i = 0; i < dis.length; i++) { for (int j = 0; j < dis.length; j++) { len = dis[i][k] + dis[k][j];// 求出i顶点出发,经过k中间点,到达j顶点距离 if (len < dis[i][j]) {// 如果小于直连距离 dis[i][j] = len; pre[i][j] = pre[k][j]; } } } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。