• LeetCode——最长重复子串?


    Q:给出一个字符串 S,考虑其所有重复子串(S 的连续子串,出现两次或多次,可能会有重叠)。返回任何具有最长可能长度的重复子串。(如果 S 不含重复子串,那么答案为 ""。)
    示例 1:
    输入:"banana"
    输出:"ana"
    示例 2:
    输入:"abcd"
    输出:""

    提示:
    2 <= S.length <= 10^5
    S 由小写英文字母组成。
    通过次数1,383提交次数7,906

    A:
    1.字符串编码法:具体可以去看Rabin-Karp 字符串编码


    代码:

    public String longestDupSubstring(String S) {
            int len = S.length();
            int a = 26;
            if (len <= 1)
                return "";
            int[] nums = new int[len];
            for (int i = 0; i < len; i++) {
                nums[i] = S.charAt(i) - 'a';
            }
            for (int i = len - 1; i > 0; i--) {
                //i是子串长度
                HashMap<Long, Integer> map = new HashMap<>();
                long tmp = 0;
                long aL = 1;
                //算第一个hashcode
                for (int j = 0; j < i; j++) {
                    tmp = (tmp * a + nums[j]) % MOD;
                    aL = aL * a;
                }
                map.put(tmp, 0);
                for (int j = 1; j <= len - i; j++) {
                    tmp = (tmp * a - nums[j - 1] * aL % MOD + nums[j + i - 1]) % MOD;
                    if (map.containsKey(tmp)) {//这里做了一个判断,因为哈希表毕竟是有可能冲突的。但我没想好冲突发生怎么解决
                        String sub = S.substring(j, j + i);
                        String sub2 = S.substring(map.get(tmp), map.get(tmp) + i);
                        if (sub.equals(sub2))
                            return sub;
                    }
                    map.put(tmp, j);
    
                }
            }
            return "";
        }
    

    但……超出时间限制了。

    2.二分查找+字符串编码法

        public String longestDupSubstring(String S) {
    		int len = S.length();
            int a = 26;  // 26进制
            long module = (long) Math.pow(2, 32);  // 取一个足够大的数,用以取模
            if(len <= 1)
                return "";
            int[] nums = new int[len];
            for(int i = 0; i < len; i++){
                nums[i] = (int) S.charAt(i) - (int) 'a';  // 只考虑小写字母
            }
            int low = 1;
            int high = len;
            while(low != high) {
            	int L = (high-low)/2 + low;
            	if(search(L, a, module, nums) != -1)
            		low = L + 1;
            	else
            		high = L;
            }
            int start = search(low-1, a, module, nums);
            if(start == -1)
            	return "";
            else
            	return S.substring(start, start+low-1);
        }
    	// 返回重复字符串的起始位置
    	// 参数:L-重复字符串的长度,a-进制,module-取模数,nums-字符串的编码数组
    	public int search(int L, int a, long module, int[] nums) {
    		int len = nums.length;
    		HashSet<Long> hashSet = new HashSet<Long>(); 
            long tmp = 0;
            long aL = 1;
            for(int j = 0; j < L; j++){
                tmp = (tmp *a + nums[j]) % module;  // 防止溢出
                //System.out.println(tmp);
                aL = (aL*a) % module;
            }
            hashSet.add(tmp);
            for(int j = 1; j <= len - L; j++){  // 长度为i的窗口
                tmp = (tmp*a - nums[j-1]*aL%module + module) % module;  // 去掉前一位
                tmp = (tmp + nums[j+L-1]) % module;
                if(hashSet.contains(tmp))
                    return j;
                hashSet.add(tmp);
            }
    		return -1;
    	}
    

    3.还有后缀树法,等有时间做

  • 相关阅读:
    Java-继承,多态练习09-22-01
    Java-类与类之间的关系
    Java-继承 共3题
    设计模式-访问者模式
    设计模式-策略模式
    JAVA-初步认识-常用对象API(集合框架-List常用子类的特点)
    JAVA-初步认识-常用对象API(集合框架-ListIterator接口)
    JAVA-初步认识-常用对象API(集合框架-List集合的常用方法)
    JAVA-初步认识-常用对象API(集合框架-List和Set的特点)
    JAVA-初步认识-常用对象API(集合框架-迭代器的原理)
  • 原文地址:https://www.cnblogs.com/xym4869/p/12681329.html
Copyright © 2020-2023  润新知