1、代码 package dp; import java.util.Random; import java.util.Scanner; /* * 求给定字符串中最长没有重复字符的字串长度。 * 比如abcdefab,对应最长没有重复字符的字串是abcdef或者cdefab,长度都为6 */ public class MaxNoRepeatChar { /* * 一般的方法 */ int subMaxLength(String s){ String sub = ""; for(int i=1;i<s.length();++i){ sub = (s.substring(0,i)); if(sub.indexOf(s.charAt(i)) == -1){ continue; } else{ return i; } } return s.length(); } int maxLength(String s){ String sub = null; int length = s.length(); int result = 0; int[] maxs = new int[length]; for(int i=0;i<length;++i){ sub = s.substring(i); maxs[i] = subMaxLength(sub.toString()); } result = maxs[0]; for(int k=1;k<length;++k){ if(maxs[k] > result){ result = maxs[k]; } } return result; } /* * 2、DP * max[i][j]表示字符串s中第(i+1)开始到第(j+1)个结束的字串中的最大不重复子串的长度 * b[i][j]记录对应字符串s中第(i+1)开始到第(j+1)个结束的字串中的最大不重复子串开始的数组下标 * 问题转化为求max[0][n-1],并输出对应子串s.substring( b[0][n-1], b[0][n-1]+max[0][n-1]) */ public int compute(String s, int[][] max, int[][] b, int i, int j){ int n = s.length(); if(i<0 || j<0 || i>=n || j>= n || i>j) return 0; if(max[i][j] != -1) return max[i][j]; if(i == j){ max[i][j] = 1; b[i][j] = i; return max[i][j]; }else{ boolean flag = false; max[i][j-1] = compute(s, max, b, i, j-1); /* * 查询从j-max[i][j-1]开始到j-1结束的子串里是否包含字符s.charAt(j) */ max[j-max[i][j-1]][j-1] = compute(s, max, b, j-max[i][j-1], j-1); if(max[j-max[i][j-1]][j-1] == max[i][j-1]){ for(int k=j-max[i][j-1]; k<=j-1;++k){ if(s.charAt(k) == s.charAt(j)){ flag = true; break; } } /* * 从j-max[i][j-1]开始到j-1结束的子串里包含字符s.charAt(j) */ if(flag == true){ max[i][j] = max[i][j-1]; b[i][j] = b[i][j-1]; return max[i][j]; } else{ max[i][j] = max[i][j-1]+1; b[i][j] = j-max[i][j-1]; return max[i][j]; } } else{ max[i][j] = max[i][j-1]; b[i][j] = b[i][j-1]; return max[i][j]; } } } /* * 3、DP2 * dp[i]表示从i开始到dp[i]结束的串是串s.substring(i)的最长没有重复字符的子串 * appear(x)表示从右往左扫描时, 最近一次出现的字符'x'的位置(数组下标) * 这里采用简单的Hash法映射为数组下标,顺序是'0'~'9'->0~9, 'A'~'Z'->10~35 */ public int dpMax(String s, int[] dp, int[] appear){ int n =s.length(); int max = 1; for(int i=0;i<n;++i){ appear[i] = n; } dp[n-1] = n-1; appear[Hash(s.charAt(n-1))] = n-1; for(int i=n-2;i>=0;--i){ int appe = appear[Hash(s.charAt(i))]; if(appe > dp[i+1]){ dp[i] = dp[i+1]; }else{ dp[i] = appe-1; } appear[Hash(s.charAt(i))] = i; if((dp[i]-i+1)>max){ max = dp[i]-i+1; } } return max; } int Hash(char c){ if(c>='0' && c<='9'){ return c-'0'; } else if(c>='A' && c<='Z'){ return c-'A'+10; } return -1; } /* * 产生随机字符 */ public char map(char[] c, int seed1, int seed2){ int num = c.length; Random rd = new Random(System.currentTimeMillis()+ seed1*seed2); int a = rd.nextInt(num); return c[a]; } /* * 产生随机字符串,一共5000个,每个长度1000。 * 对应字符集是'0'~'9', 'A'~'Z'共36个字符 */ public String[] generateString(){ int snum = 36; int rnum = 5000; int length = 1000; char[] source = new char[snum]; for(int i=0;i<10;++i){ source[i] = (char)(i+'0'); } for(int i=10;i<snum;++i){ source[i] = (char)(i-10+'A'); } String[] result = new String[rnum]; for(int i=0;i<rnum;++i){ StringBuffer sb = new StringBuffer(); for(int j=0;j<length;++j){ sb.append(map(source,i+1, j+1)); } result[i] = sb.toString(); } return result; } public static void main(String[] args){ Scanner in = new Scanner(System.in); MaxNoRepeatChar mnpc = new MaxNoRepeatChar(); String[] input = mnpc.generateString(); int num = input.length; /* * 一般方法 */ System.out.println("一般方法测试:"); long start1 = System.currentTimeMillis(); while(num-- > 1){ int max = mnpc.maxLength(input[num-1]); // System.out.println(max); } System.out.println(System.currentTimeMillis()-start1); /* * DP */ num = input.length; System.out.println("DP测试:"); long start2 = System.currentTimeMillis(); while(num-- > 1){ int n = input[num-1].length(); int[][] max = new int[n][n]; int[][] b = new int[n][n]; for(int i=0;i<n;++i) for(int j=0;j<n;++j){ max[i][j] = -1; } int maxLength = mnpc.compute(input[num-1], max, b, 0, n-1); // System.out.println(maxLength); // System.out.println(input[num-1].substring(b[0][n-1], b[0][n-1]+maxLength)); } System.out.println(System.currentTimeMillis()-start2); /* * DP2 */ num = input.length; System.out.println("DP2测试:"); long start3 = System.currentTimeMillis(); while(num-- > 1){ int n = input[num-1].length(); int[] dp = new int[n]; int[] appear = new int[n]; int max = mnpc.dpMax(input[num-1], dp, appear); // System.out.println(max); } System.out.println(System.currentTimeMillis()-start3); } } 2、测试结果: 一般方法测试: 1532 DP测试: 73359 DP2测试: 187