京東 2019實習生Java筆試題目2,求T串中最多的不相交Sm子串的個數

1. 題目

在這裏插入圖片描述
樣例輸入:

3
aa
b
ac
bbaac

樣例輸出:

3

樣例解釋:把T中字符從1開始編號,用[L,R]表示從第L個字符到第R個字符所構成的子串。一種選擇子串的方法是[1,1],[2,2],[3,4] (b、b、aa) 一共3個串,另一種選法是[1,1],[2,2],[4,5] (b、b、ac) 一共也是3個串。注意不能同時選擇子串[3,4],[4,5]因爲它們相交了。


2. 解法

DP算法

dp[n] = max(dp[n-1], dp[n-len(Si)] + 1) , n >= len(Si), dp[0] = 0
# 1. n表示T串的前n個字符
# 2. 當有Si屬於Sm的時候滿足匹配,纔會有max的第二個參數,不然選擇dp[n-1]

2.1 遞歸算法

package xyz.cglzwz.jd.t2;

import java.util.Scanner;

public class Copy {
	static int[] dp;
	
	public static void main(String[] args) {
		// 輸入部分
		Scanner in = new Scanner(System.in);
		int m = Integer.valueOf(in.nextLine());
		String[] Sm = new String[m];
		for (int i = 0; i < Sm.length; ++i) {
			Sm[i] = in.nextLine();
		}
		String T = in.nextLine();
		
		// 對輸入的Sm串從小到大選擇排序
		for (int i = 0; i < Sm.length; ++i) {
			int flag = i;
			for (int j = i + 1; j < Sm.length; ++j) {
				if (Sm[j].length() < Sm[flag].length())
					flag = j;
			}
			if (flag != i) {
				String temp = Sm[flag];
				Sm[flag] = Sm[i];
				Sm[i] = temp;
			}
		}
		
		// 定義數據
		int n = T.length();
		dp = new int[n+1];
		for (int i = 0; i < dp.length; ++i)
			dp[i] = 0;
		int ans = 0;
		
		// 調用遞歸
		ans = find(Sm, T, n);
		
		System.out.println(ans);
	}
	
	
	/**
	 * 遞歸法
	 * 
	 * @param Sm Sm子串集合
	 * @param T  
	 * @param n  
	 * @return
	 */
	static int find(String[] Sm, String T, int n) {
		// 出口
		if (n == 0)
			return 0;
		
		for (int i = 0; i < Sm.length && Sm[i].length() <= n; ++i) {
			int len = Sm[i].length();
			if (T.substring(n-len, n).equals(Sm[i])) {
				dp[n-len] = find(Sm, T, n-len);
				dp[n] = Math.max(dp[n-len] + 1, dp[n]);
			}
		}
		
		if (dp[n - 1] == 0)
			dp[n-1] = find(Sm, T, n - 1);
		return Math.max(dp[n], dp[n - 1]);
	}
}

比較簡單,但是時間空間肯定不允許,case通過率不會超過10%;

2.2 遞推法

package xyz.cglzwz.jd.t2;

import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		// 輸入部分
		Scanner in = new Scanner(System.in);
		int m = Integer.valueOf(in.nextLine());
		String[] Sm = new String[m];
		for (int i = 0; i < Sm.length; ++i) {
			Sm[i] = in.nextLine();
		}
		String T = in.nextLine();
		
		// 對輸入的Sm串從小到大排序
		for (int i = 0; i < Sm.length; ++i) {
			int flag = i;
			for (int j = i + 1; j < Sm.length; ++j) {
				if (Sm[j].length() < Sm[flag].length())
					flag = j;
			}
			if (flag != i) {
				String temp = Sm[flag];
				Sm[flag] = Sm[i];
				Sm[i] = temp;
			}
		}
		
		// 定義數據
		int n = T.length();
		int[] dp = new int[n+1];
		for (int i = 0; i < dp.length; ++i)
			dp[i] = 0;
		int ans = 0;
		
		// 遞推
		for (int k = 1; k <= n; ++k) {
			for (int i = 0; i < Sm.length && Sm[i].length() <= k; ++i) {
				int len = Sm[i].length();
				if (T.substring(k-len, k).equals(Sm[i])) {
					dp[k] = Math.max(dp[k-len] + 1, dp[k]);
				}
			}
			dp[k] = Math.max(dp[k], dp[k-1]);
		}
				
		ans = dp[n];
		System.out.println(ans);
	}	
}

這樣就全部AC了,注意的是dp數組別定義爲全局的,不然卡內存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章