Reputation: 644
Write an algorithm to check if a given string, s
, can be formed from two other strings, part1
and part2
.
The restriction is that the characters in part1
and part2
are in the same order as in s
.
Example:
'codewars' is a merge from 'cdw' and 'oears':
s: c o d e w a r s = codewars
part1: c d w = cdw
part2: o e a r s = oears
But in the test cases, it's not so easy to make it work..
The rules says they have to be the same length and in same order but with random test cases they are put in random order aswell.. So the rules conflict with the rules so how can I make it work??
Test cases that follow the rules:
[Test]
public void SadPath2()
{
Assert.IsFalse(StringMerger.isMerge("codewars", "code", "wasr"), "Codewars can't be created from code and wasr");
}
SadPath2 == false;
[Test]
public void SadPath1()
{
Assert.IsFalse(StringMerger.isMerge("codewars", "cod", "wars"), "Codewars are not codwars");
}
SadPath1 == false;
[Test]
public void HappyPath2()
{
Assert.IsTrue(StringMerger.isMerge("codewars", "cdwr", "oeas"), "codewars can be created from cdwr and oeas");
}
HappyPath2 == true;
[Test]
public void HappyPath1()
{
Assert.IsTrue(StringMerger.isMerge("codewars", "code", "wars"), "codewars can be created from code and wars");
}
HappyPath1 == true;
Some random tests that might not follow the rules completely:
[Test]
public void RandomTest()
{
Assert.IsTrue(StringMerger.isMerge("[W`meSnw(R1qaLLqc[=]=UAvTa_3%", "W`mnwqaLL]=va%", "[eS(R1qc[=UAT_3"), "'[W`meSnw(R1qaLLqc[=]=UAvTa_3%' is a merge of 'W`mnwqaLL]=va%' and '[eS(R1qc[=UAT_3'");
}
RandomTest == true;
[Test]
public void RandomTest2()
{
Assert.IsTrue(StringMerger.isMerge("]ftUNn7-XoX4AZ3i1+", "U7oX4A1+", "]ftNn-XZ3i"), "']ftUNn7-XoX4AZ3i1+' is a merge of 'U7oX4A1+' and ']ftNn-XZ3i");
}
RandomTest2 == true;
First example on my class where it can successfully run the all the tests Except SadPath2
:
public class StringMerger
{
public static bool isMerge(string s, string part1, string part2)
{
int num = 0;
string txt1 = "";
Console.WriteLine("S - " + s + " - P1 - " + part1 + " - P2 - " + part2);
#region Sorting
foreach (var itm in s)
{
if (part1.Contains(itm.ToString()))
num++;
else if (part2.Contains(itm.ToString()))
num++;
}
#endregion
if (num == s.Length && num == (part1.Length + part2.Length))
return true;
return false;
}
}
Second example where it can run all except for the random tests:
public class StringMerger
{
public static bool isMerge(string s, string part1, string part2)
{
int num = 0;
int P1 = 0;
int P2 = 0;
bool p2 = false;
string txt1 = "";
#region Sorting
foreach (var itm in s)
{
if (part1.Contains(itm.ToString()))
num++;
else if (part2.Contains(itm.ToString()))
num++;
try
{
if (p2 == false)
{
txt1 = txt1 + GetLetterP1(part1, itm.ToString(), P1);
P1++;
p2 = true;
}
else
{
txt1 = txt1 + GetLetterP2(part2, itm.ToString(), P2);
P2++;
p2 = false;
}
}
catch { }
}
#endregion
if (num == s.Length && num == (part1.Length + part2.Length))
{
if (s.Contains(part1 + part2))
return true;
else if (txt1 == s)
return true;
}
return false;
}
static string GetLetterP1(string p1, string letter, int n)
{
string itm = "";
if (p1.Contains(letter))
itm = p1[n].ToString();
return itm;
}
static string GetLetterP2(string p2, string letter, int n)
{
string itm = "";
if (p2.Contains(letter))
itm = p2[n].ToString();
return itm;
}
}
Results with Kvam
answer: (With the latest fixes)
Results with Max
Answer: (With the latest fixes)
Results with codersl
Answer: (With the latest fixes)
Upvotes: 0
Views: 861
Reputation: 2332
My 2 cents
public static void Main()
{
Console.WriteLine(Check("codewars", "code", "wasr")); //false
Console.WriteLine(Check("codewars", "cod", "wars")); //false
Console.WriteLine(Check("codewars", "cdwr", "oeas"));
Console.WriteLine(Check("codewars", "code", "wars"));
Console.WriteLine(Check("[W`meSnw(R1qaLLqc[=]=UAvTa_3%", "W`mnwqaLL]=va%", "[eS(R1qc[=UAT_3"));
Console.WriteLine(Check("]ftUNn7-XoX4AZ3i1+", "U7oX4A1+", "]ftNn-XZ3i"));
Console.WriteLine(Check("acab", "ab", "ac"));
Console.WriteLine(Check("b]aDw- !oKJnOJ", "b]aDwoKJ", "- !nOJ"));
Console.WriteLine(Check("codewars", "codewarss", "")); //false
Console.WriteLine(Check("codewars", "", "")); //false
Console.WriteLine(Check("codewars", "codewars", null));
Console.WriteLine(Check("Bananas from Bahamas", "Bahas", "Bananas from am"));
}
private static bool Check(string s, string part1, string part2)
{
if (part1 == null)
part1 = "";
if (part2 == null)
part2 = "";
var part1Index = 0;
var part2Index = 0;
var bothMatch = "";
foreach(var c in s)
{
// handle both strings matching
if (part1Index < part1.Length && part2Index < part2.Length && c == part1[part1Index] && c == part2[part2Index])
{
bothMatch += c;
part1Index++;
part2Index++;
continue;
}
if (bothMatch.Length > 0 && c == part1[part1Index])
{
// part2 doesn't match anymore so roll back its index
part2Index -= bothMatch.Length;
bothMatch = "";
}
else if (bothMatch.Length > 0 && c == part2[part2Index])
{
// part1 doesn't match anymore so roll back its index
part1Index -= bothMatch.Length;
bothMatch = "";
}
// handle one string matching
if (part1Index < part1.Length && c == part1[part1Index])
{
//Console.WriteLine("c={0}, p1={1}", c, part1[part1Index]);
part1Index++;
continue;
}
if (part2Index < part2.Length && c == part2[part2Index])
{
//Console.WriteLine("c={0}, p2={1}", c, part2[part2Index]);
part2Index++;
continue;
}
//Console.WriteLine("c={0}, p1={1}, p2={2}, both={3}", c, part1[part1Index], part2[part2Index], bothMatch);
return false;
}
return (part1Index == part1.Length) && (part2Index == part2.Length);
}
Upvotes: 0
Reputation: 2218
I think this should cover the requirements, although you might want to rewrite it to avoid string creation all around.
public bool IsMatch(string target, string part1, string part2)
{
if (target.Length != part1.Length + part2.Length)
{
return false;
}
if (target == "")
{
return true;
}
if (part1.Length > 0 && target[0] == part1[0])
{
if (IsMatch(target.Substring(1), part1.Substring(1), part2.Substring(0)))
{
return true;
}
}
if (part2.Length > 0 && target[0] == part2[0])
{
if (IsMatch(target.Substring(1), part1.Substring(0), part2.Substring(1)))
{
return true;
}
}
return false;
}
Upvotes: 2
Reputation: 7100
Here my 2 cents
public bool IsMerge(string target, string part1, string part2)
{
if (String.IsNullOrEmpty(target))
{
throw new ArgumentNullException("target");
}
if (String.IsNullOrEmpty(part1))
{
throw new ArgumentNullException("part1");
}
if (String.IsNullOrEmpty(part2))
{
throw new ArgumentNullException("part2");
}
if (target.Length == (part1.Length + part2.Length))
{
return this.IsPart(target, part1) && this.IsPart(target, part2);
}
return false;
}
private bool IsPart(string target, string part)
{
int idx = -1;
int lastIdx = 0;
for (int i = 0; i < part.Length; i++)
{
idx = (target.IndexOf(part[i], lastIdx));
if (!(idx > -1))
{
return false;
}
lastIdx = idx;
}
return true;
}
Upvotes: 0