1,最长公共前缀问题
有点类似冒泡算法,每次都要找最小的串的长度,然后进行截取,代码如下
public String longestCommonPrefix(String[] strs) { if(strs.length==0) return ""; String s=strs[0]; for (int i = 1; i < strs.length; i++) { if(s.length()==0||strs[i].length()==0) return ""; int len=Math.min(s.length(), strs[i].length()); /* int count=0;//临时变量,记录比较时候到哪一位就停止 for ( int j = 0; j <len; j++) { //这里不能是== if (s.charAt(j)!=strs[i].charAt(j)) {count=j;break;} } s=s.substring(0, count);*/ //上面错在多加了一个count,但是在实际的时候当"a""b的时候,count为0 截取的子串还是“a” int j; for ( j = 0; j <len; j++) { //这里不能是== if (s.charAt(j)!=strs[i].charAt(j)) break; } s=s.substring(0, j);//0到j-1的位置 } return s; }
与上面的前缀类似,只是一些简单的坐标要变
public static String longestCommonLastfix(String[] strs) { if(strs. length==0) return ""; //s总是暂时放求的的当前的值 String s=strs[0]; for ( int i = 1; i < strs. length; i++) { if(strs[i].length()==0||s.length()==0) return ""; int len1=strs[i].length(); int len2= s.length(); int len=Math. min(len1,len2); int j; for ( j=0;j<len; j++) { if(s.charAt(len2-1-j)!=strs[i].charAt(len1-1-j)) break; } s=s.substring(len2-j); } return s; }
3,最长公共子串(返回子串长度或序列)
关于子串与子序列的问题,不想赘述了,分不清的话自己百度
思路:
public static int longestCommonSubString(String s1,String s2) { int len1=s1.length(),len2=s2.length(); if(len1==0||len2==0) return 0; //初始化的时候数组为0,所以后面只需要判断不为0的一些情况 int[][] dp=new int[len1][len2]; int max=0; for (int i = 0; i < len1; i++) { for ( int j = 0; j < len2; j++) { if(s1.charAt(i)==s2.charAt(j)){ //i或j中有一个为0,情况特殊 if(i==0||j==0){ dp[i][j]=1; } else if(i!=0&&j!=0) dp[i][j]=dp[i-1][j-1]+1; if(dp[i][j]>max){ max=dp[i][j]; //可以知道最大的起始索引下标为i+1-max } } } } return max; }在求最大长度的时候,顺便也把最大子串的起始坐标也知道了i+1-max,所以不论是返回子串还是子串的长度都不怕怕
4,最长回文子串
这里先给出我自己实现的算法,看不懂的慢慢看
/* * str_s = a b a a b a; Index = 0 1 2 3 4 5 6 7 8 9 10 11 12 str[] = # a # b # a # a # b # a #; P[] = 0 0 0 2 0 1 5 1 0 3 0 1 0; */ //最长公共子串,manacher 算法 public static String longestPalindrome(String s) { if(s.length()==0||s== null) return ""; if(s.length()==1) return s; int len=s.length(); char[] ch= new char[2*len+1]; int[] p= new int [2*len+1]; //max是坐标id影响的最远的index,不是最大距离 int max=0; //id表示的是影响到最远id的index,但不一定是最大的,所以后面还要寻找 int id=0; //对称中心 //添加特殊字符,一般是"#" for ( int i = 0; i < s.length(); i++) { ch[2*i+1]=s.charAt(i); ch[2*i]= '#'; } ch[2*len]= '#'; //进行判断 for ( int i = 1; i < ch. length; i++) { //先把能进行扩展的p[i]值找到 if(max>i) p[i]=Math. min(p[2*id-i], max-i); //对i点进行扩展 while ((1+i+p[i])<ch.length&&(i-p[i]-1)>0&&(ch[1+i+p[i]]==ch[i-p[i]-1])) { p[i]++; } if(p[i]+i>max){ max=p[i]+i; id=i; } } //寻找最大值 max=0; id=0; for ( int i = 0; i < p. length; i++) { if(max<p[i]){ max=p[i]; id=i; } } //最大长度为原来的max+1 StringBuffer sb= new StringBuffer(); for ( int i = id-max; i <=id+max; i++) { if(ch[i]!= '#') sb.append(ch[i]); } return sb.toString(); }
public static String longestPalindrome1(String s) { if(s.length()==0||s== null) return ""; if(s.length()==1) return s; int maxLen=1,maxIndex=0; int len=s.length(); int[][] dp= new int[len][len]; //长度为1的时候 for ( int i = 0; i < len; i++) { dp[i][i]=1; } //长度为2 for ( int i = 0; i < len-1; i++) { if(s.charAt(i)==s.charAt(i+1)) dp[i][i+1]=1; maxIndex=i; maxLen=2; } //长度大于1的时候 for ( int len1=3 ; len1<=len ; len1++) { for ( int i = 0; i <=len-len1; i++) { int j=i+len1-1; //dp[i+1][j-1]!=0判断不可少 if(s.charAt(i)==s.charAt(j)&&dp[i+1][j-1]!=0) {dp[i][j]=1; maxIndex=i; maxLen=len1; } } } return s.substring(maxIndex,maxIndex+maxLen); }
5,最长公共子序列
public static int LCSubseq(String s1,String s2){ if(s1.length()==0||s2.length()==0) return 0; int len1=s1.length(); int len2=s2.length(); int[][] dp= new int[len1+1][len2+1]; for ( int i = 1; i <=len1; i++) { for ( int j = 1; j <=len2; j++) { if(s1.charAt(i-1)==s2.charAt(j-1)) dp[i][j]=dp[i-1][j-1]+1; else{ if(dp[i-1][j]>=dp[i][j-1]) dp[i][j]=dp[i-1][j]; else dp[i][j]=dp[i][j-1]; } } } return dp[len1][len2]; }2,返回一个子序列版本的,代码大致差不多
//最长公共子序列,输出序列 public static String LCSubseq1(String s1,String s2){ if(s1.length()==0||s2.length()==0) return ""; int len1=s1.length(); int len2=s2.length(); int[][] dp= new int[len1+1][len2+1]; StringBuffer sb= new StringBuffer(); for ( int i = 1; i <=len1; i++) { for ( int j = 1; j <=len2; j++) { if(s1.charAt(i-1)==s2.charAt(j-1)) {dp[i][j]=dp[i-1][j-1]+1; } else{ if(dp[i-1][j]>=dp[i][j-1]) dp[i][j]=dp[i-1][j]; else dp[i][j]=dp[i][j-1]; } } } int max=dp[len1][len2]; System. out.println( "最大长度为:" +max); //随便输出一个序列 while(len1>=1&&len2>=1){ if(s1.charAt(len1-1)==s2.charAt(len2-1)&&dp[len1][len2]==dp[len1-1][len2-1]+1){ sb.append(s1.charAt(len1-1)); len1--; len2--; } else if(s1.charAt(len1-1)!=s2.charAt(len2-1)&&dp[len1-1][len2]>=dp[len1][len2-1]){ len1--; } else{ len2--; } } return sb.reverse().toString(); }很明显,这里的动态规划是根据序列长度来规划的,下面来一个根据坐标动态规划的
<pre name="code" class="java">//最长公共子序列,输出长度就行 public static int LCSubseq1(String s1,String s2){ if(s1.length()==0||s2.length()==0) return 0; int len1=s1.length(); int len2=s2.length(); int[][] dp=new int[len1][len2]; StringBuffer sb=new StringBuffer(); //初始化 for (int i = 0; i < len1; i++) { if(s1.charAt(i)==s2.charAt(0)) dp[i][0]=1; } //初始化 for (int i = 0; i < len2; i++) { if(s1.charAt(0)==s2.charAt(i)) dp[0][i]=1; } for (int i = 1; i <len1; i++) { for (int j = 1; j <len2; j++) { if(s1.charAt(i)==s2.charAt(j)) {dp[i][j]=dp[i-1][j-1]+1; } else{ if(dp[i-1][j]>=dp[i][j-1]) dp[i][j]=dp[i-1][j]; else dp[i][j]=dp[i][j-1]; } } } int max=dp[len1-1][len2-1]; System.out.println("最大长度为:"+max); /*//随便输出一个长度,有点bug,输不出String,以后再来改 int i=len1-1,j=len2-1; while(i>=1&&j>=1){ if(s1.charAt(i)==s2.charAt(j)&&dp[i][j]==dp[i-1][j-1]+1){ sb.append(s1.charAt(i)); i--; j--; }else if(s1.charAt(i)!=s2.charAt(j)&&dp[i-1][j]>=dp[i][j-1]){ i--; }else{ j--; } } //有点Bug, if(i==0&&j==0){ if(s1.charAt(i)==s2.charAt(0)) sb.append(s1.charAt(0)); }else if(i>j){ while(i>=0) if(s1.charAt(i--)==s2.charAt(0)) sb.append(s2.charAt(0)); }else if(i<j){ while(j>=0) if(s1.charAt(0)==s2.charAt(j--)) sb.append(s1.charAt(0)); } return sb.reverse().toString();*/ return max; }
public static String LonPaliSubse(String s){ int maxLength= Lps(s, 0, s.length()-1); System. out.println( "最大回文子序列的长度为:" +maxLength); //寻找最长子序列,并输出 return null; } public static int Lps(String s, int begin, int last){ if(begin==last) return 1; if(begin>last) return 0; if(s.charAt(begin)==s.charAt(last)) return Lps(s, begin+1, last-1)+2; return Math. max(Lps(s, begin, last-1), Lps(s, begin+1, last)); }
public static int LonPaliSubse1(String s){ if(s.length()==0||s== null) return 0; int len=s.length(); int[][] dp= new int[len][len]; int max=0; //序列长度为1 for ( int i = 0; i <len; i++) dp[i][i]=1; //长度大于等于i+1的序列 dp[j][j+i] for ( int i = 1; i < len; i++) { for ( int j = 0; j+i<len; j++) { //如果首位相同 if(s.charAt(j)==s.charAt(j+i)) max=dp[j+1][j+i-1]+2; else max=Math. max(dp[j+1][j+i], dp[j][j+i-1]); dp[j][j+i]=max; } } return dp[0][len-1]; }
public static String LonPaliSubse2(String s){ if(s.length()==0||s== null) return ""; StringBuffer sb= new StringBuffer(s); String s1=sb.reverse().toString(); return LCSubseq2(s1, s); }后面还有需要改进的和优化的,先到这把