1. 程式人生 > >LeetCode題解:Interleaving String的幾種思路

LeetCode題解:Interleaving String的幾種思路

題目要求

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

Example 1:

Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
Output: true

Example 2:

Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
Output: false

注意到interleaving的含義是交錯,也就是說s1、s2在相互交錯以連線為s3時,必須要保證其內部的字元是有序且不可跳過的。

極其簡單的遞迴法

class Solution {
public:

	bool find(string s1, string s2, string s3) {
		if (s1+s2 == s3) {
			return true;
		}
		if (s1[0] == s3[0] && find(s1.substr(1), s2, s3.substr(1))) {
			return true;
		}
		if (s2[0] == s3[0] && find(s1, s2.substr(1), s3.substr(1))) {
			return true;
} return false; } bool isInterleave(string s1, string s2, string s3) { if (s1.size() + s2.size() != s3.size()) { return false; } return find(s1, s2, s3); } };

雖然演算法很優美,但奈何還是倒在了timelimit這一關。
在這裡插入圖片描述

改進了一丟丟的深搜法

所以我們要想一下,為什麼一開始的深搜會跑得那麼慢,時間都消耗在哪一步了呢?遞迴最大的弊端在於重複計算,考慮這樣一種情況:某時刻s1和s2的前5和前4個字串構成了s3的前九個,記為(5,4)。接下來,是(6,4),(6,5)…但最終無法完成匹配。於是程式重新回到了(5,4),接下來是(5,5),(6,5),在上述那種演算法下,就會重複計算(6,5)之後註定會錯誤的解。

改進思路:

  • 記錄所走過的路徑。
  • 考慮當s1已經全部加入s3時,只需比較s2和s3剩餘的部分是否一致。
class Solution {
   int m[200][200];
public:

   bool dfs(string s1, string s2, string s3, int i1, int i2, int i3) {
   	if (m[i1][i2]) {
   		return false;
   	}
   	if (i2 == s2.size()) {
   		return (s1.substr(i1)==s3.substr(i3));
   	}
   	if (i1 == s1.size()) {
   		return (s2.substr(i2)==s3.substr(i3));
   	}
   	if (s1[i1] == s3[i3] && dfs(s1, s2, s3, i1+1, i2, i3+1)) {
   		return true;
   	}
   	if (s2[i2] == s3[i3] && dfs(s1, s2, s3, i1, i2+1, i3+1)) {
   		return true;
   	}
   	m[i1][i2] = 1;
   	return false;
   }

   bool isInterleave(string s1, string s2, string s3) {
   	if (s1.size() + s2.size() != s3.size()) {
   		return false;
   	}
   	return dfs(s1, s2, s3, 0, 0, 0);
   }
};

在這裡插入圖片描述

嘻嘻嘻,撒花兒~