最长重复子数组 findLength示例详解
作者:I12BXXXXXLbull
最长重复子数组 findLength
默认格式:
class Solution { public int findLength(int[] A, int[] B) { } }
解题思路:
1,暴力算法
遍历数组1中的每一个元素
用这个元素和数组2的每一个元素对比,如果相同
循环读取两个数组的下一个元素,直到不相同为止
这个算法太复杂,就不做实现了。
2,使用哈希表+链表
遍历一遍数组1,将其每个元素出现的位置存入到一个List中,然后存入hashmap中。
遍历数组2,每个元素在哈希表中是否存在,如果存在,遍历这个List中的所有位置,对这些位置进行测试,找出最大长度
写的时候已经发现了,用哈希表来存并没有减少核心部分的时间,时间复杂度依然很高。
public int findLength(int[] A, int[] B) { int max=0; //构建一个HashMap来存地址 HashMap<Integer, List<Integer>> map=new HashMap<>(); for (int i=0;i<A.length;i++){ if (map.get(A[i])==null){ List<Integer> list=new LinkedList<>(); list.add(i); map.put(A[i],list); }else { map.get(A[i]).add(i); } } for (int i=0;i<B.length;i++){ //如果元素在数组A中存在 if (map.get(B[i])!=null){ //遍历原数组中对应的每一个位置 for(int index:map.get(B[i])){ int a=index,b=i; for (;a<A.length&&b<B.length&&A[a]==B[b];a++,b++){ } max=Integer.max(max,b-i); } } } return max; }
优化1:(失败)
这个HashMap可以使用数组来代替,因为他里面的值不会超过100,我们可以对其进行控制,用数组下标来代替HashMap的键的功能。
public int findLength(int[] A, int[] B) { int max=0; //使用数组来存 // HashMap<Integer, List<Integer>> map=new HashMap<>(); List<Integer>[] lists=new ArrayList[100]; for (int i=0;i<A.length;i++){ if (lists[A[i]]==null){ List<Integer> list=new ArrayList<>(); list.add(i); lists[A[i]]=list; }else { lists[A[i]].add(i); } } for (int i=0;i<B.length;i++){ //如果元素在数组A中存在 if (lists[B[i]]!=null){ //遍历原数组中对应的每一个位置 for(int index:lists[B[i]]){ int a=index,b=i; for (;a<A.length&&b<B.length&&A[a]==B[b];a++,b++){ } max=Integer.max(max,b-i); } } } return max; }
优化2:
还是数据结构上的优化,我们可以使用Set来代替List,这样可以节省一些时间
优化到这我觉得应该是我做题的方向错了,应该有一个巧妙的方法能够解决这个问题但是我目前没有想到,看看官方的解答吧。
官方的解题方法有多种,我这里就选择最巧妙的那一个方式:动态规划。
动态规划的题目之前做过很多,但是对这个概念的理解还不够深刻,还需要多多练习。
动态规划的核心思想就是,一边计算一边记录,并且得到的结果会累计,最后我们累计的结果就是我们需要的值。
在这道题中,我们取出数组A中的一个元素,和B中每个元素比较一遍,如果相等,这能证明什么,这就证明,如果A中这个元素的前一个和B中当前元素的前一个相等,此时这个连续的长度就+1。
用这个结论,我们可以遍历两个数组,构建一个a*b的二维数组,假设A种当前元素地址是a1,B中当前元素的地址是b1,那么当前的长度可以加上(a1-1,b1-1)这个位置的元素的值。
虽然实现了,但不是最优的办法,官方给出的最优算法有一些复杂,没能看懂
public int findLength(int[] A, int[] B) { int[][] map=new int[A.length][B.length]; int max=0; for (int i=0;i<A.length;i++){ for (int j=0;j<B.length;j++){ if (A[i]==B[j]){ if (i-1<0||j-1<0) map[i][j]=1; else map[i][j]=map[i-1][j-1]+1; max=Integer.max(max,map[i][j] ); } } } return max; }
到此这篇关于最长重复子数组 findLength示例详解的文章就介绍到这了,更多相关最长重复子数组 findLength内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!