详情请点击html
源码:二分查找(非递归)java
public static int search(int[] arr, int val) { int left = 0; int right = arr.length - 1; while (left <= right) { int mid = (left + right) / 2; if (arr[mid] == val) { return mid; } else if (arr[mid] > val) { right = mid - 1; } else { left = mid + 1; } } return -1; }
源码:汉诺塔git
分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分红两个或更多的相同或类似的子问题,再把子问题分红更小的子问题……直到最后子问题能够简单的直接求解,原问题的解即子问题的解的合并。算法
分治算法求解的经典问题:二分搜索、大整数乘法、归并排序、快排、汉诺塔等数组
分治法在每一层递归上都有三个步骤:app
以下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数优化
/** * 移动盘子 * @param num 一共有多少个盘子 * @param a 开始的柱子 * @param b 辅助的柱子 * @param c 目标柱子 */ public static void hanoitower(int num, char a, char b, char c) { if (num == 1) { System.out.println("第1个盘为: " + a + " -> " + c); } else { hanoitower(num - 1, a, c, b); System.out.println("第" + num + "个盘为: " + a + " -> " + c); hanoitower(num - 1, b, a, c); } }
源码:背包问题spa
小灰版动态规划详解code
背包问题主要是指一个给定容量的背包、若干具备必定价值和重量的物品,如何选择物品放入背包使物品的价值最大。其中又分 01 背包和彻底背包(彻底背包指的是:每种物品都有无限件可用)htm
背包问题:有一个背包,容量为 4 磅 , 现有以下物品
代码实现
/** * 求解01背包问题 * * @param v 商品的价值 * @param w 商品的重量(体积) * @param c 商品的最大容量 */ public static void knapsackDim(int[] v, int[] w, int c) { //初始化二维数组,行表示商品的体积w 列表示容量从0->c int size = w.length; int[][] dp = new int[size + 1][c + 1]; for (int i = 1; i <= size; i++) { for (int j = 0; j <= c; j++) { //当前商品的体积 大于 容量j 时 直接取上一行的数据 dp[i][j] = dp[i - 1][j]; if (w[i-1] <= j) { //①dp[i - 1][j - w[i - 1]]为上一行的当前可用体积-当前商品体积 获得减去当前商品重量以后的最大价值 + v[i-1] //②dp[i][j]实则为上一行的数据 与①直接比较大小 dp[i][j] = Math.max(dp[i][j], v[i - 1] + dp[i - 1][j - w[i - 1]]); } } } }
优化为一维数组
/** * 背包问题优化 使用一维数组 * * @param v 商品的价值 * @param w 商品的重量(体积) * @param c 商品的最大容量 */ public static void knapsackSingle(int[] v, int[] w, int c) { int[] dp = new int[c + 1]; //第一次初始化dp for (int i = 0; i < c + 1; i++) { dp[i] = w[0] > i ? 0 : v[0]; } for (int i = 1; i < w.length; i++) { //防止前面数据被覆盖,从后往前进行遍历 for (int j = c; j >=0; j--) { if (w[i] <= j) { dp[j] = Math.max(dp[j], v[i] + dp[j - w[i]]); } } } }
源码:暴力匹配
若是用暴力匹配的思路,并假设如今 str1 匹配到 i 位置,子串 str2 匹配到 j 位置,则有: 1) 若是当前字符匹配成功(即 str1[i] == str2[j]),则 i++,j++,继续匹配下一个字符 2) 若是失配(即 str1[i]! = str2[j]),令 i = i - (j - 1),j = 0。至关于每次匹配失败时,i 回溯,j 被置为 0。 3) 用暴力方法解决的话就会有大量的回溯,每次只移动一位,如果不匹配,移动到下一位接着判断,浪费了大量 的时间。
/** * 暴力匹配 * @param str1 原始字符串 * @param str2 匹配字符串 */ public static int violenceMatch(String str1,String str2) { //表示字符串str2的匹配的索引位置 int j; for (int i = 0; i < str1.length();) { j = 0; while (i < str1.length() && j < str2.length() && str1.charAt(i) == str2.charAt(j)) { i++; j++; } //将j匹配到最后一个字符 if (j==str2.length()) { return i-j; } i = i - j + 1; } return -1; }
源码:KMP算法
寻找最长前缀后缀“ABCDABD”
/** * 求出一个字符数组的next数组 * * @param p 字符数组 * @return next数组 */ public static int[] getNextArray(char[] p) { int[] next = new int[p.length]; next[0] = -1; int k = -1; int j = 0; while (j < p.length - 1) { //p[k]表示前缀 p[j]表示后缀 if (k == -1 || p[j] == p[k]) { // k++; // j++; next[++j] = ++k; } else { k = next[k]; } } return next; }
移动两位以后,A 跟空格不匹配,模式串后移1 位。
匹配成功,过程结束。
匹配过程如出一辙。也从侧面佐证了,next 数组确实是只要将各个最大前缀后缀的公共元素的长度值右移一位,且把初值赋为-1 便可。
/** * 对主串s和模式串t进行KMP模式匹配 * * @param s 主串 * @param t 模式串 * @return 若匹配成功,返回t在s中的位置(第一个相同字符对应的位置),若匹配失败,返回-1 */ public static int kmpMatch(String s, String t) { char[] s_arr = s.toCharArray(); char[] t_arr = t.toCharArray(); int[] next = getNextArray(t_arr); int i = 0, j = 0; while (i < s_arr.length && j < t_arr.length) { if (j == -1 || s_arr[i] == t_arr[j]) { i++; j++; } else j = next[j]; } if (j == t_arr.length) return i - j; else return -1; }
假设存在下面须要付费的广播台,以及广播台信号能够覆盖的地区。 如何选择最少的广播台,让全部的地区均可以接收到信号。
public static void main(String[] args) { Map<String, Set<String>> map = new HashMap<>(); Set<String> set1 = new HashSet<>(); set1.add("北京"); set1.add("上海"); set1.add("天津"); Set<String> set2 = new HashSet<>(); set2.add("广州"); set2.add("北京"); set2.add("深圳"); Set<String> set3 = new HashSet<>(); set3.add("成都"); set3.add("上海"); set3.add("杭州"); Set<String> set4 = new HashSet<>(); set4.add("上海"); set4.add("天津"); Set<String> set5 = new HashSet<>(); set5.add("杭州"); set5.add("大连"); map.put("K1", set1); map.put("K2", set2); map.put("K3", set3); map.put("K4", set4); map.put("K5", set5); Set<String> allAreas = new HashSet<>(); allAreas.addAll(set1); allAreas.addAll(set2); allAreas.addAll(set3); allAreas.addAll(set4); allAreas.addAll(set5); //存储选择的key List<String> selects = new ArrayList<>(); //定义此时最大的key String maxKey; //临时存储的set集合 Set<String> tempSet = new HashSet<>(); //若是allArea不为空则一直删除 while (allAreas.size() != 0) { //清空临时set tempSet.clear(); // maxSize = 0; maxKey = null; for (Map.Entry<String, Set<String>> entry : map.entrySet()) { tempSet = entry.getValue(); tempSet.retainAll(allAreas); if (tempSet.size() > 0 && (maxKey == null || tempSet.size() > map.get(maxKey).size())) { maxKey = entry.getKey(); } } if (maxKey != null) { tempSet = map.get(maxKey); selects.add(maxKey); allAreas.removeAll(tempSet); //此时能够将对应的key去除,这样能在遍历map的时候提升效率 map.remove(maxKey); } } System.out.println(selects); }