문자열 일치 --BM 알고리즘

저는 최근 인터뷰를 준비하고 있었는데, BM 알고리즘에 대해 알기 전에 문자열 매칭에 대한 질문을 보았습니다 (규칙에서 일부 알고리즘을 깊이 연구하지 않은 것에 대한 책임 만 있습니다)! ! !

잘! BM 알고리즘이 무엇인지 소개하고 Baidu Encyclopedia의 설명을 살펴 보겠습니다.

에서 컴퓨터 과학 , 보이어 - 무어 문자열 검색 알고리즘은 매우 효율적이다 문자열 검색 알고리즘 . 1977 년 Bob Boyer와 J Strother Moore가 디자인했습니다. 알고리즘 은 검색된 문자열이 아닌 검색 대상 문자열 (키워드) 전처리 합니다. Boyer-Moore 알고리즘의 실행 시간도 검색된 문자열의 크기에 따라 선형 적으로 달라 지지만 일반적으로 다른 알고리즘의 작은 부분 일뿐입니다. 검색된 문자열의 문자를 하나씩 비교할 필요가 없습니다. 그것의 일부를 건너 뜁니다. 일반적으로 검색 키워드가 길수록 알고리즘이 더 빠릅니다. 그 효율성은 모든 실패한 일치 시도에 대해 알고리즘이이 정보를 사용하여 일치하지 않는 위치를 가능한 한 많이 제거 할 수 있다는 사실에서 비롯됩니다.

그럼 아래에서 BM 알고리즘에 대해 자세히 소개하겠습니다. 물론이 블로그에서는 다른 기사를 사용하여 요약을 작성합니다. 또한 BM 알고리즘을 이해하기위한 저자의 노트입니다. 독자들에게 도움이되기를 바랍니다. 즉, 주제로 직접 이동하십시오!

알고리즘을 이해하려면 먼저 알고리즘의 원리와 개념을 알아야합니다. 이것은 매우 중요하므로 먼저 BM 알고리즘의 원리에 대한 진입 점을 만드십시오.

BM 알고리즘에 기초 접미사 비교 (왼쪽 비교법에 오른쪽)과 BM 알고리즘은 실제로 포함 된 두 개의 병렬 알고리즘 : 나쁜 문자 규칙좋은 접미사 규칙.

(모든 사람이 BM 알고리즘의 아이디어에 대한 블로그를 읽을 것을 권장합니다 : 문자열 매칭 BM 알고리즘 학습 )

우선, 두 가지 알고리즘 규칙을 명확히해야합니다.

1. 잘못된 문자 규칙 :

백 시프트 번호 = 잘못된 문자 위치-패턴 문자열에서 잘못된 문자의 마지막 발생 위치

 패턴 문자열에 "잘못된 문자"가 포함되지 않은 경우 마지막 발생 위치는 -1입니다. 다음 두 문자열을 예로 들어 보겠습니다.

"G"와 "H"가 일치하지 않기 때문에 "G"를 "불량 문자"라고합니다. 패턴 문자열 (패턴 문자열은 FGH)의 두 번째 위치 (0부터 번호 지정)에 나타나며 패턴 문자열입니다. 마지막 발생 위치는 1이므로 2-1 = 1 자리가 뒤로 이동합니다.

 2. 좋은 접미사 규칙 

 백 시프트 번호 = 패턴 문자열에서 좋은 접미사 위치-마지막 발생 위치

예를 들어, 패턴 문자열 "ABCDEFABCD"의 마지막 "AB"가 "좋은 접미사"인 경우. 그런 다음 위치는 6 (0부터 계산, 마지막 "B"값 사용)이고 패턴 문자열의 마지막 발생 위치는 1 (첫 번째 "B"의 위치)이므로 6-1 = 5 비트, 이전 "AB"가 다음 "AB"위치로 이동합니다.

다른 예를 들자면, 패턴 문자열 "ABCDEFGH"의 "EF"가 좋은 접미사이면 "EF"의 위치는 5이고 마지막 발생 위치는 -1입니다 (즉, 나타나지 않음). 즉, 전체 문자열이 "F"의 마지막 자리로 이동합니다.

      이 규칙에 대해주의해야 할 세 가지 사항이 있습니다.

  1. "좋은 접미사"의 위치는 마지막 문자를 기반으로합니다. "ABCDEF"의 "EF"가 좋은 접미사라고 가정하면 위치는 "F"(0부터 계산) 인 "F"의 적용을받습니다.
  2. "좋은 접미사"가 패턴 문자열에 한 번만 나타나면 마지막 발생 위치는 -1입니다. 예를 들어, "EF"가 "ABCDEF"에서 한 번만 나타나면 마지막 발생 위치는 -1입니다 (즉, 나타나지 않음).
  3. "양호한 접미사"가 여러 개있는 경우 가장 긴 "양호한 접미사"를 선택하고 마지막 발생 위치가 헤드에 있어야합니다. 예를 들어, "BABCDAB"의 "좋은 접미사"가 "DAB", "AB", "B"인 경우 현재 "좋은 접미사"의 마지막 항목은 무엇입니까? 대답은 이때 사용 된 좋은 접미사는 "B"이고 마지막에 나타나는 위치는 머리, 즉 0 번째 위치이고 다른 좋은 접미사의 마지막 위치는 머리에 없다는 것입니다.

이제 그러한 요구가 있습니다. 문자열이 다음과 같은 다른 문자열에 나타나는지 여부를 알고 싶습니다.

String originText = "ABCDEFGHHH"
String moduleText = "FGGH";

moduleText가 originText에 표시되는지 여부를 확인하고 표시되면 표시되는 위치의 인덱스를 반환하고 표시되지 않으면 -1을 반환합니다. (물론, 여기서는 당분간 문자열 객체 API의 시나리오를 포기하고 알고리즘으로 시작하겠습니다 !!!). 동시에 패턴 문자열 (검색어라고도 함)이라고도하는 일치 문자열 인 moduleText와 기본 문자열이라고도하는 검색된 문자열 인 originText의 문제도 설명해야합니다.

1. 먼저 메인 스트링이 패턴 스트링의 머리에 정렬되고 비교가 꼬리부터 시작됩니다. 이 아이디어는 매우 효율적입니다. 왜냐하면 후행 문자가 일치하지 않으면 처음 10 개의 문자 (전체)가 단 한 번의 비교만으로 원하는 결과가 아님을 알 수 있기 때문입니다. "C"는 "H"와 일치하지 않습니다. 이때 "C"를 "나쁜 문자"라고합니다. 이때, 나쁜 문자 규칙은 3, 좋은 접미사 규칙은 -1, 백 쉬프트 번호로 큰 것을 선택합니다. 여기에서 선택 3

2. 여전히 끝에서 비교해 보면 "F"와 "H"가 일치하지 않으므로 "F"는 "불량 문자"입니다.

비유, 그리고 마침내

구현 코드는 다음과 같습니다.

package www.supermaster.cn.text;

/**
 * 坏字符规则: 后移位数 = 坏字符的位置 - 模式串中的坏字符上一次出现位置
 * 
 * 好后缀规则:后移位数 = 好后缀的位置 - 模式串中的上一次出现位置
 * 
 */
public class BMTest
{

	public static void main(String[] args)
	{
		// 主串
		String originText = "ABCDEFGHHFGHH";
		// 模式串
		String moduleText = "FGH";
		// 坏字符规则表
		//	        int[] badCharacterArray = badCharacter(originString,moduleString);

		System.out.println("主串:" + originText);
		System.out.println("模式串:" + moduleText);

		int index = bmMatch(originText, moduleText);
		System.out.println("匹配的下标:" + index);
	}

	/**
	 * @Description:[BM匹配字符串]
	 * @Method: bmMatch
	 * @param originText
	 *            主串
	 * @param moduleText
	 *            模式串
	 * @return 若匹配成功,返回下标,否则返回-1
	 */
	public static int bmMatch(String originText, String moduleText)
	{
		// 主串
		if (originText == null || originText.length() <= 0)
		{
			return -1;
		}
		// 模式串
		if (moduleText == null || moduleText.length() <= 0)
		{
			return -1;
		}

		//如果模式串的长度大于主串的长度,那么一定不匹配
		if (moduleText.length() > originText.length())
		{
			return -1;
		}

		int moduleSuffix = moduleText.length() - 1;// 模式串最大长度值
		int moduleIndex = moduleSuffix; // 初始化模式串起始Index
		int originIndex = moduleSuffix; // 初始化主串初始化Index
		//
		for (int index = originIndex; originIndex < originText.length() && moduleIndex >= 0;)
		{
			char och = originText.charAt(originIndex); // 主串某个位置的Char
			char mch = moduleText.charAt(moduleIndex); // 模式串某个位置的Char
			//
			if (och == mch)
			{
				originIndex--;
				moduleIndex--;
			}
			else
			{
				// 坏字符规则
				int badMove = badCharacterRule(moduleText, och, moduleIndex);
				// 好字符规则
				int goodMove = goodCharacterRule(moduleText, moduleIndex);

				// 主串位置不动,模式串向右移动
				originIndex = index + Math.max(badMove, goodMove);
				moduleIndex = moduleSuffix;
				// index就是中间变量
				index = originIndex;
			}
		}

		if (moduleIndex < 0)
		{
			// 多减了一次
			return originIndex + 1;
		}

		return -1;
	}

	/**
	 * @Description:[利用好后缀规则计算移动位数]
	 * @Method: goodCharacterRule
	 * @param moduleText
	 * @param charSuffix
	 * @return
	 */
	private static int goodCharacterRule(String moduleText, int charSuffix)
	{
		int result = -1;
		// 模式串长度
		int moduleMax = moduleText.length();

		// 好字符数
		int charSize = moduleMax - 1 - charSuffix;

		for (; charSize > 0; charSize--)
		{
			String startText = moduleText.substring(0, charSize);
			String endText = moduleText.substring(moduleMax - charSize, moduleMax);
			if (startText.equals(endText))
			{
				result = moduleMax - charSize;
			}
		}

		return result;
	}

	/**
	 * @Description:[利用坏字符规则计算移动位数]
	 * @Method: badCharacterRule
	 * @param moduleText
	 * @param badChar
	 * @param charSuffix
	 * @return
	 */
	private static int badCharacterRule(String moduleText, char badChar, int charSuffix)
	{
		return charSuffix - moduleText.lastIndexOf(badChar, charSuffix);
	}

}

이 기사는 주로 인터뷰 상황에 대한 것이며 코드는 메인 디스플레이 및 디스플레이이며 후속 조치는 계속 개선 될 것입니다! 독자들에게 좋은 제안이 있으시면 함께 발전 할 수 있도록 메시지를 남겨주세요! !

지속적인 개선..............

-------------------------------------------------- --------------------------------------
작성자 : 세계 코딩
출처 : CSDN
원본 : HTTPS : / /blog.csdn.net/dgxin_605/article/details/92360040
저작권 성명 :이 기사는 블로거의 원본 기사입니다. 재 인쇄 할 경우 블로그 게시물에 링크를 첨부하세요!

 

추천

출처blog.csdn.net/dgxin_605/article/details/92360040