import java.util.*;
/**
* Created by qililong on 2020/7/6.
* 程序员常用的十种算法
*/
public class ShiSuanFa {
//1、非递归方式二分查找,arr有序的数组,target要查找的目标
public static int binarySearch(int[] arr , int target){
int left =0;
int right = arr.length-1;
while (left<=right){//说明继续查找
int mind = (left+right)/2;
if(arr[mind]==target){
return mind;
}else if(arr[mind]<target){
left=mind+1;
}else if(arr[mind]>target){
right=mind-1;
}
}
return -1;//表示没找到
}
//2分治算法,大问题分解成小问题,合并排序、快速排序、汉诺塔、循环赛日程表、棋盘覆盖等经典问题都可利用
//汉诺塔:不管有多少个,最大的上边那些可以看做一个
public static void hanoiTower(int num ,char a, char b, char c){
if(num ==1){//如果只有一个塔
System.out.println("第一个盘从"+a+"->"+c);
}else{
//如果我们有n>2个盘
//1先把最上边的所有盘A-》B,移动过程会使用到C
hanoiTower(num-1, a, c, b);
//2将A最下边的移动到C
System.out.println("第"+num+"个盘从"+a+"->"+c);
//3将B塔的搬到C塔,中间可能用到A塔
hanoiTower(num-1, b, a, c);
}
}
//动态规划;
// 背包问题:一个背包,三个物品,吉他重1价值1500,音响重4价值3000,电脑重3,价值2000,
// 重量不超出的情况下,总价值最大(物品不重复是01背包,如果每件物品可以无限件使用则是完全背包)
//求解过程类似分治算法,但子问题不是互相独立的,可用填表的方式得到最优解。
//w表示每个物品的重量,v表示每个物品的价值,m表示背包的最大容量,dp[i][j]表示在前i个物品中装入容量为j的背包的最大价值。
public static void KnapsackProblem(int[] w, int[] v, int m, int[][] dp){
for(int i =1;i<dp.length;i++){
for(int j=1;j<dp[1].length;j++){
//公式
if(w[i-1]>j){
dp[i][j]=dp[i-1][j];
}else{
//公式:dp[i][j]=Math.max(dp[i-1][j],v[i]+dp[i-1][j-w[i]]);第一行和第一列都是0,所以i和j从1开始
// 因为我们i和j从1开始的所以v[i]+dp[i-1][j-w[i]]换成v[i-1]+dp[i-1][j-w[i-1]]
dp[i][j]=Math.max(dp[i-1][j],v[i-1]+dp[i-1][j-w[i-1]]);
}
}
}
}
//暴力匹配算法
public static int baoliSearch(String str1, String str2){
int i=0;
int j=0;
while (i<str1.length() && j<str2.length()){
if(str1.charAt(i)==str2.charAt(j)){
i++;
j++;
}else{
i=i-(j-1);
j=0;
}
}
if(j==str2.length()){
return i-j;
}else {
return -1;
}
}
//KMP算法,匹配两个字符串(暴力匹配算法或者KMP算法,暴力匹配算法会有很多回溯:如果str1[i]=Str2[j]则i++,j++;否则i=i-(j-1),j=0)
//KMP算法是为了不让i回退这么多,利用部分匹配表进行回退:移动位置=已匹配的字符数-对应的部分匹配值。部分匹配值通过分析前缀后缀得到
//ABCDAB的前缀是[A,AB,ABC,ABCD,ABCDA];后缀是[BCDAB,CDAB,DAB,AB,B],共有元素AB,AB的长长度为2
public static int kmpSearch(String str1, String str2, int[] next){//next是部分匹配表
for(int i=0,j=0;i<str1.length();i++){
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){
int[] next = new int[dest.length()];
next[0]=0;//字符串长度是0则匹配值是0
for(int i=1,j=0;i<dest.length();i++){
while (j>0 && dest.charAt(i)!=dest.charAt(j)){
j=next[j-1];//获取新的j
}
if(dest.charAt(i)==dest.charAt(j)){
j++;
}
next[i]=j;
}
return next;
}
//贪心算法,每一步选择都选择最优解,从而期望得到最优结果,但结果不一定是最优解;
//集合覆盖问题,不同的广播台可以覆盖不同的地区,如何选择最少的广播台让左右地区都接收到信号
//遍历所有电视台,每次都找覆盖了最多为覆盖地区的电台,电台加入集合中,电台覆盖的地区则去掉,直到覆盖了全部地区
public static void GreedyAlgorithm(HashMap<String ,HashSet<String>> broadcasts, HashSet<String> allAreas, ArrayList<String> selects){
//临时的集合,保存当前电台覆盖的还没有覆盖的地区
HashSet<String> tempSet = new HashSet<>();
while (allAreas.size()>0){
//定义maxKey保存每次遍历中覆盖最大区域的电台的Key
String maxKey=null;
for(String key : broadcasts.keySet()){
tempSet.clear();
tempSet.addAll(broadcasts.get(key));
tempSet.retainAll(allAreas);//这个电台能覆盖的地区
//如果覆盖的城市大于0,并且是初次遍历或者本次覆盖的城市比上一次循环覆盖的城市多则取本电台
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);//[K1,K2,K3,K5]
}
//马踏棋盘算法(骑士周游问题)
//弗洛伊德算法,加权图最短路径问题
//迪杰斯特拉算法,加权图最短路径问题,利用了广度优先
//普里姆算法(求最小生成树)带权的无向连接图,选择一颗生成树,使树上的所有边上权的总和为最小,就叫最小生成树
//最小生成树有普里姆算法和克鲁斯卡尔算法,一个从顶点考虑,一个从边考虑
//普里姆算法从顶点考虑,修路问题:7个村庄{A,B,C,D,E,F,G},修路将7村联通,路最短
public static void main(String[] args){
/*int[] arr = {1,3,4,7,9,134,666};
int index = binarySearch(arr,1);
System.out.println("########"+index);*/
// hanoiTower(5,'A','B','C');
/*int[] w={1,4,3};
int[] v = {1500,3000,2000};
int m = 4;
int n = v.length;//物品个数
int[][] dp = new int[n+1][m+1];
KnapsackProblem(w,v,m,dp);
System.out.println(dp[n][m]);*/
/*String str1= "BBC ABCDAB ABCDABCDABDE";
String str2 = "ABCDABD";
//求部分匹配表
int[] next = kmpNext(str2);
System.out.println("next="+ Arrays.toString(next));
int index = kmpSearch(str1,str2,next);
System.out.println("index="+index);
//暴力匹配算法
int index2 = baoliSearch(str1,str2);
System.out.println("index="+index2);*/
//每个电台覆盖的地区
/*HashMap<String ,HashSet<String>> broadcasts = new HashMap<String,HashSet<String>>();
HashSet<String> hash1 = new HashSet<>();
hash1.add("北京");
hash1.add("上海");
hash1.add("天津");
HashSet<String> hash2 = new HashSet<>();
hash2.add("广州");
hash2.add("北京");
hash2.add("深圳");
HashSet<String> hash3 = new HashSet<>();
hash3.add("成都");
hash3.add("上海");
hash3.add("杭州");
HashSet<String> hash4 = new HashSet<>();
hash4.add("上海");
hash4.add("天津");
HashSet<String> hash5 = new HashSet<>();
hash5.add("杭州");
hash5.add("大连");
broadcasts.put("K1",hash1);
broadcasts.put("K2",hash2);
broadcasts.put("K3",hash3);
broadcasts.put("K4",hash4);
broadcasts.put("K5",hash5);
//所有地区
HashSet<String> allAreas = new HashSet<String>();
allAreas.add("北京");
allAreas.add("上海");
allAreas.add("天津");
allAreas.add("广州");
allAreas.add("深圳");
allAreas.add("成都");
allAreas.add("杭州");
allAreas.add("大连");
//所选电台
ArrayList<String> selects = new ArrayList<>();
GreedyAlgorithm(broadcasts,allAreas,selects);*/
}
}