zoukankan      html  css  js  c++  java
  • 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.还有后缀树法,等有时间做

  • 相关阅读:
    Framework 4.0 新关键字dynamic 之我见(二)
    随便歇歇
    最近的一些总结
    一周最新示例代码回顾 (7/16 7/22)
    一周最新示例代码回顾 (5/28–6/3)
    一周最新示例代码回顾 (5/14–5/20)
    一周最新示例代码回顾 (6/25 7/1)
    微软一站式示例代码浏览器本周更新发布
    一周最新示例代码回顾 (6/11 6/17)
    示例代码浏览器5.4功能更新
  • 原文地址:https://www.cnblogs.com/xym4869/p/12681329.html
Copyright © 2011-2022 走看看