【Java】 劍指offer(19) 正則表達式匹配

本文參考自《劍指offer》一書,代碼採用Java語言。html

更多:《劍指Offer》Java實現合集  java

題目

  請實現一個函數用來匹配包含'.'和'*'的正則表達式。模式中的字符'.'表示任意一個字符,而'*'表示它前面的字符能夠出現任意次(含0次)。在本題中,匹配是指字符串的全部字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab*ac*a"匹配,但與"aa.a"及"ab*a"均不匹配。面試

思路

  使用函數matchCore(char[] str, int indexOfStr, char[] pattern, int indexOfPattern) 來實現每一步的比較(遞歸)。正則表達式

  (1)當模式中第二個字符不爲「*」時:若當前字符相等,則字符串和模式都後移一個字符,繼續調用函數進行比較;若不相等,則返回false。數組

  (2)當模式中第二個字符爲「*」時:若當前字符不相等,則模式後移兩個字符,繼續比較;若當前字符相等,則有三種狀況:ide

    1)字符串字符位置不變,模式後移兩個字符,繼續比較;  //x*被忽略函數

    2)字符串後移一個字符,模式後移兩個字符,繼續比較;post

    3)字符串後移一個字符,模式字符位置不變,繼續比較。測試

  三種狀況使用「||」進行並列比較。url

注意點

  時刻要注意數組是否越界!

測試算例

  1.功能測試(模式中包含普通字符、「.」、「*」;匹配狀況;不匹配狀況)

  2.特殊測試(null,空字符串)

完整Java代碼

(含測試代碼)

package _19;

/**
 * 
 * @Description 面試題19:正則表達式匹配
 *
 * @author yongh
 * @date 2018年9月21日 上午8:12:06
 */

// 題目:請實現一個函數用來匹配包含'.'和'*'的正則表達式。模式中的字符'.'
// 表示任意一個字符,而'*'表示它前面的字符能夠出現任意次(含0次)。在本題
// 中,匹配是指字符串的全部字符匹配整個模式。例如,字符串"aaa"與模式"a.a"
// 和"ab*ac*a"匹配,但與"aa.a"及"ab*a"均不匹配。

public class RegularExpressions {
	public boolean match(char[] str, char[] pattern) {
		if (str == null || pattern == null)
			return false;
		return matchCore(str, 0, pattern, 0);
	}

	private boolean matchCore(char[] str, int indexOfStr, char[] pattern, int indexOfPattern) {
		if (indexOfStr == str.length && indexOfPattern == pattern.length)
			return true;
		if (indexOfStr < str.length && indexOfPattern == pattern.length)
			return false;
		if (indexOfPattern + 1 < pattern.length && pattern[indexOfPattern + 1] == '*') {
			if ((indexOfStr < str.length && pattern[indexOfPattern] == '.')
					|| (indexOfStr < str.length && pattern[indexOfPattern] == str[indexOfStr])) {
				return matchCore(str, indexOfStr, pattern, indexOfPattern + 2)
						|| matchCore(str, indexOfStr + 1, pattern, indexOfPattern)
						|| matchCore(str, indexOfStr + 1, pattern, indexOfPattern + 2);
			} else {
				return matchCore(str, indexOfStr, pattern, indexOfPattern + 2);
			}
		}
		if (indexOfStr < str.length && (pattern[indexOfPattern] == str[indexOfStr] || pattern[indexOfPattern] == '.'))
			return matchCore(str, indexOfStr + 1, pattern, indexOfPattern + 1);
		return false;
	}

	// ==========測試代碼=========
	void test(String testName, char[] str, char[] pattern, boolean expected) {
		System.out.print(testName + ":");
		if (match(str, pattern) == expected)
			System.out.println("passed!");
		else
			System.out.println("failed!");
	}

	void test1() {
		char[] str = {};
		char[] pattern = { '.' };
		test("test1", str, pattern, false);
	}

	void test2() {
		char[] str = {};
		char[] pattern = { '.', '*' };
		test("test2", str, pattern, true);
	}

	void test3() {
		char[] str = { 'a' };
		char[] pattern = { '.', '*' };
		test("test3", str, pattern, true);
	}

	void test4() {
		char[] str = {};
		char[] pattern = {};
		test("test4", str, pattern, true);
	}

	void test5() {
		char[] str = null;
		char[] pattern = null;
		test("test5", str, pattern, false);
	}

	void test6() {
		char[] str = { 'a', 'b', 'b' };
		char[] pattern = { 'a', 'b', 'b', '*', 'b' };
		test("test6", str, pattern, true);
	}

	void test7() {
		char[] str = { 'a' };
		char[] pattern = { 'a', 'a', '*' };
		test("test7", str, pattern, true);
	}

	public static void main(String[] args) {
		RegularExpressions demo = new RegularExpressions();
		demo.test1();
		demo.test2();
		demo.test3();
		demo.test4();
		demo.test5();
		demo.test6();
		demo.test7();
	}
}

  

test1:passed!
test2:passed!
test3:passed!
test4:passed!
test5:passed!
test6:passed!
test7:passed!
RegularExpressions

 

收穫

  1.涉及到數組的狀況下,必定要時刻注意數組越界問題!

  2.對於每一步都是採用相同判斷方法的題目,能夠採用遞歸函數來實現

  3.思惟必定要全面,把握住關鍵矛盾,將每種狀況考慮清楚。例如這道題,關鍵就在於第二個字符是否爲「*」,肯定關鍵問題後,分析清楚每一種狀況便可

  4.代碼第29行的 indexOfStr < str.length 必定要記得加,不然可能會出現重複執行第32行的狀況。

 

更多:《劍指Offer》Java實現合集 

相關文章
相關標籤/搜索