算法系列-字符串匹配-rabin-karp算法

ACM-1381题目-Crazy Search

 

方法

 写道
模式字符串进行一个预处理,并mod,主字符串进行逐个进行简单的hash映射,然后mod比较

 

 写道
比如:子串“421″和源串”4234212456″

首先把423对某个质数取模,比如7,把模值和421对7取模的值进行对比。如果相同,则再用朴素算法逐字符对比,如果不同,把423变成234.可以通过(423-400)*10+4=234计算。其实对于任何位数的xyz(具体xyz是几位,要看子串的长度)都可以划分成(xyz-x*100)*10+m

其中m表示父串的下一位。这里的100是以子串长度为3来作比较的. 其中如果换成字符的话应该就是26了。

 

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * @author frank.lv
 *
 */
public class CS {
        //开多少空间要看情况,不能太小
	private boolean[] hash = new boolean[160000];
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		CS cs = new CS();
		
		while(in.hasNext()) {
			int len = in.nextInt();
			int nc = in.nextInt();
			String s = in.next();
			System.out.println(cs.rabin_karp(nc, len, s));
			
		}

	}
	
	/**
	 * @param nc 字母表的大小
	 * @param len 子串的长度
	 * @param s 源字符串
	 * @return
	 */
	private Integer rabin_karp(int nc, int len, String s) {
		int ht = 0;
		int step = 1;
		int ans = 1;
		int sourceLen = s.length();
		int key = 0;
		//字符分配码表
		Map<Character, Integer> wordMap = new HashMap<Character, Integer>();
		
		//step = NC * (len - 1)
		for(int i =1;i<len;i++) {
			step *= nc;
		}
		//分配字母表
		for (int i = 0;; i++) {
			if(!wordMap.containsKey(s.charAt(i))) {
				wordMap.put(s.charAt(i), ++key);
			}
			if(key == nc)
				break;
		}
		//算出第一个子串的HASH值
		for(int i =0;i<len;i++) {
			ht = nc * ht + wordMap.get(s.charAt(i));
		}
		hash[ht] = true;
		
		//RK算法核心
		for(int i = 0; i < sourceLen - len; i++) {
//朴素算法
//4234212456 中 423->234
//nc * ((ht['423'] - 4 * step[100])) + '4'
			ht = nc * (ht - (wordMap.get(s.charAt(i))) * step) + wordMap.get(s.charAt(i + len));
			if(!hash[ht]) {
				hash[ht] = true;
				ans ++;
			}
		}
		
		return ans;
	}

}

 

 

 

参考

http://www.yqshare.com/rabin-karp-and-crazy-search.html

你可能感兴趣的:(html,算法)