Unique correspondence for characters in C# - c#

I'm new to programming and I got really stuck on an exercise.
I need to determine whether each character in the first string can be uniquely replaced by a character in the second string. Both strings are equal in length.
For example, "aabc ea" and "ddtf hd" , the result needs to be:
True
a => d
b => t
c => f
=>
e => h
If I have for example "abac ea" and "ddtf hd" , the result needs to be:
False
Since "abac ea" and "ddt hd" don't have an unique replacement.
This is my Code:
using System;
namespace UniqueStrings
{
class Program
{
static void Main(string[] args)
{
string firstPhrase = Console.ReadLine();
string secondPhrase = Console.ReadLine();
bool result = false;
int charsCount = 0;
char[] firstPhraseChars = new char[firstPhrase.Length];
char[] secondPhraseChars = new char[secondPhrase.Length];
if (firstPhrase.Length != secondPhrase.Length)
{
result = false;
}
for (int i = 0; i < firstPhrase.Length; i++)
{
if (firstPhrase[i] == firstPhraseChars[i])
{
firstPhraseChars[i] = firstPhrase[i];
secondPhraseChars[i] = secondPhrase[i];
}
for (int j = 0; j < secondPhrase.Length; j++)
{
if (secondPhrase[j] == secondPhraseChars[j])
{
firstPhraseChars[j] = firstPhrase[j];
secondPhraseChars[j] = secondPhrase[j];
result = false;
}
else
{
result = true;
}
}
}
for (int i = 0; i < firstPhrase.Length; i++)
{
if (result == false)
{
firstPhraseChars[charsCount] = firstPhrase[i];
secondPhraseChars[charsCount] = secondPhrase[i];
charsCount++;
}
}
if (result == false)
Console.WriteLine(result);
else
{
Console.WriteLine(result);
for (int i = 0; i < firstPhrase.Length; i++)
{
Console.WriteLine(firstPhrase[i] + " => " + secondPhrase[i]);
}
}
Console.Read();
}
}
}
Can someone please help me understand what I'm doing wrong? I have no idea anymore and I feel like this code will never work. There needs to be some solution to this, which I'm not understanding.
I'm not supposed to use LINQ, list or dictionary, only System.
If anyone has other questions, feel free to ask.

exemple of non-optimized solution
using System;
namespace UniqueStrings
{
class Program
{
static bool CheckStringSimilarity(string firstPhrase, string secondPhrase)
{
if (firstPhrase.Length != secondPhrase.Length)
{
return false;
}
var length = firstPhrase.Length;
for (var i =0; i<length; i++)
{
for(var j=0; j<length; j++ )
{
if((firstPhrase[i] == firstPhrase[j]) && (secondPhrase[i] != secondPhrase[j]))
{
return false;
}
if((firstPhrase[i] != firstPhrase[j]) && (secondPhrase[i] == secondPhrase[j]))
{
return false;
}
}
}
return true;
}
static void Main(string[] args)
{
Console.WriteLine($"CheckStringSimilarity('aaa','bbb') = {CheckStringSimilarity("aaa", "bbb")}");
Console.WriteLine($"CheckStringSimilarity('aaab','bbbc') = {CheckStringSimilarity("aaab", "bbbc")}");
Console.WriteLine($"CheckStringSimilarity('rrt','aze') = {CheckStringSimilarity("rrt", "aze")}");
Console.WriteLine($"CheckStringSimilarity('rrt dd','aad aa') = {CheckStringSimilarity("rrt dd", "aad aa")}");
}
}
}
DEMO

In your first for loop the result will always be true since both if statements will always return false. When the if statements compare their values "firstPhraseChars[i]" and "secondPhraseChars[j]" are always empty since you never put anything into these arrays before the comparison.
Hope this helps without giving away too much ;)

You can look for a counter example: if you've found it, correspondent doesn't exist:
private static bool HasCorrespondence(string left, string right) {
if (left == null)
return right == null;
if (right == null)
return false;
if (left.Length != right.Length)
return false;
// known correspondence
Dictionary<char, char> correspondence = new Dictionary<char, char>();
for (int i = 0; i < left.Length; ++i)
if (correspondence.TryGetValue(left[i], out char expected)) {
// counter example: we want expected, but have right[i]
if (expected != right[i])
return false;
}
else
// we have nothing for left[i], so we can add (left[i], right[i]) pair
correspondence.Add(left[i], right[i]);
// no counter example exists, return true
return true;
}
If Dictionary is prohibited, you can emulate it with help of array:
private static bool HasCorrespondence(string left, string right) {
if (left == null)
return right == null;
if (right == null)
return false;
if (left.Length != right.Length)
return false;
int[] correspondence = new int[char.MaxValue];
for (int i = 0; i < left.Length; ++i)
if (correspondence[left[i]] != 0) {
if (correspondence[left[i]] != right[i])
return false;
}
else
correspondence[left[i]] = right[i];
return true;
}
If you are looking for one to one correspondence, you can just check twice"
private static bool HasOneToOne(string left, string right) =>
HasCorrespondence(left, right) &&
HasCorrespondence(right, left);

Related

Determine whether each character in the first string can be uniquely replaced by a character in the second string so that the two strings are equal

Give two strings of equal size. Determine whether each character in the first string can be uniquely replaced by a character in the second string so that the two strings are equal. Display also the corresponding character pairs between the two strings. The code works well now.
Example 1:
For input data:
aab
ttd
The console will display:
True
a => t
b => d
Example 2:
For input data:
tab
ttd
The console will display:
False
In the second example the answer is false because there is no unique correspondence for the character 'a': both 't' and 'd' correspond to it.
This is my code:
using System;
namespace problemeJM
{
class Program
{
static void Main(string[] args)
{
string firstPhrase = Convert.ToString(Console.ReadLine());
string secondPhrase = Convert.ToString(Console.ReadLine());
string aux1 = string.Empty, aux2 = string.Empty;
bool x = true;
for (int i = 0; i < firstPhrase.Length; i++)
{
if (!aux1.Contains(firstPhrase[i]))
{
aux1 += firstPhrase[i];
}
}
for (int i = 0; i < secondPhrase.Length; i++)
{
if (!aux2.Contains(secondPhrase[i]))
{
aux2 += secondPhrase[i];
}
}
if (aux1.Length != aux2.Length)
{
Console.WriteLine("False");
}
else
{
for (int i = 0; i < firstPhrase.Length - 2; i++)
{
for (int j = 1; j < secondPhrase.Length - 1; j++)
{
if (firstPhrase[i] == firstPhrase[j] && secondPhrase[i] == secondPhrase[j])
{
x = true;
}
else if (firstPhrase[i] != firstPhrase[j] && secondPhrase[i] != secondPhrase[j])
{
x = true;
}
else if (firstPhrase[i] == firstPhrase[j] && secondPhrase[i] != secondPhrase[j])
{
x = false;
break;
}
else if (firstPhrase[i] != firstPhrase[j] && secondPhrase[i] == secondPhrase[j])
{
x = false;
break;
}
}
}
Console.WriteLine(x);
aux1 = string.Empty;
aux2 = string.Empty;
if (x == true)
{
for (int i = 0; i < firstPhrase.Length; i++)
{
if (!aux1.Contains(firstPhrase[i]))
{
aux1 += firstPhrase[i];
}
}
for (int i = 0; i < secondPhrase.Length; i++)
{
if (!aux2.Contains(secondPhrase[i]))
{
aux2 += secondPhrase[i];
}
}
for (int i = 0; i <= aux1.Length - 1; i++)
{
for (int j = 1; j <= aux2.Length; j++)
{
if (aux1[i] == aux1[j] && aux2[i] == aux2[j])
{
Console.WriteLine(aux1[i] + " => " + aux2[i]);
break;
}
else if (aux1[i] != aux1[j] && aux2[i] != aux2[j])
{
Console.WriteLine(aux1[i] + " => " + aux2[i]);
break;
}
}
}
}
}
}
}
}
I think you should use a Dictionary<char, char> as commented. But you need to check if there's a unique mapping in both string, so from s1 to s2 and from s2 to s1:
static bool UniqueMapping(string s1, string s2)
{
int length = Math.Min(s1.Length, s2.Length);
var dict = new Dictionary<char, char>(length);
for (int i = 0; i < length; i++)
{
char c1 = s1[i];
char c2 = s2[i];
bool contained = dict.TryGetValue(c1, out char c);
if (contained && c2 != c)
{
return false;
}
dict[c1] = c2;
}
return true;
}
Here are your samples. Note that i use UniqueMapping twice(if true after 1st):
static void Main(string[] args)
{
var items = new List<string[]> { new[]{ "aab", "ttd" }, new[] { "tab", "ttd" }, new[] { "ala bala portocala", "cuc dcuc efghficuc" }, new[] { "ala bala portocala", "cuc dcuc efghijcuc" } };
foreach (string[] item in items)
{
bool result = UniqueMapping(item[0], item[1]);
if(result) result = UniqueMapping(item[1], item[0]);
Console.WriteLine($"Word 1 <{item[0]}> Word 2 <{item[1]}> UniqueMapping? {result}");
}
}
.NET Fiddle: https://dotnetfiddle.net/4DtIyH

Find permutation of one string into other string program

Trying to make an program where it just check, if permutation of string s1 exists in string s2 or not.
Created below program and it works for below test case.
Input:
s1 = "ab"
s2 = "eidballl"
Output:
True
Explanation: s2 contains one permutation of s1 (that is ba).
But this get fail when, input s2="sdfdadddbd" , s1="ab", expected as, false, but got true.
I'm trying to figure out what is missing here. Using a sliding window approach. Below my code in c#:
public bool CheckInclusion(string s1, string s2) {
var intCharArray = new int[256];
foreach(char c in s1)
{
intCharArray[c]++;
}
int start=0,end=0;
int count=s1.Length;
bool found=false;
while(end<s2.Length)
{
if (intCharArray[s2[end]]>0) { count--;}
intCharArray[s2[end]]--;
Console.WriteLine("end:" + end + " start:"+ start);
if(end-start==s1.Length) {
if (count==0) {return true;}
if (intCharArray[s2[start]]>=0)
{
count++;
}
intCharArray[s2[start]]++;
start++;
}
end++;
}
return false;
}
you need to check all characters of permutation exist in any range of [i, i + p.Length) of the string
static class StringExtensions
{
public static bool ContainsAnyPermutationOf(this string str, string p)
{
Dictionary<char, int> chars_count = p.CreateChar_CountDictionary();
for (int i = 0; i <= str.Length - p.Length; i++)
{
string subString = str.Substring(i, p.Length);
if (DictionaryMatch(chars_count, subString.CreateChar_CountDictionary()))
{
return true;
}
}
return false;
}
private static bool DictionaryMatch(Dictionary<char, int> dictionary1, Dictionary<char, int> dictionary2)
{
if (dictionary1.Count != dictionary2.Count)
{
return false;
}
foreach (var kvp in dictionary1)
{
if (!dictionary2.ContainsKey(kvp.Key))
{
return false;
}
dictionary2[kvp.Key] = dictionary2[kvp.Key] - 1;
if (dictionary2[kvp.Key] == 0)
{
dictionary2.Remove(kvp.Key);
}
}
return true;
}
private static Dictionary<char, int> CreateChar_CountDictionary(this string str)
{
Dictionary<char, int> dic = new Dictionary<char, int>();
for (int i = 0; i < str.Length; i++)
{
if (!dic.ContainsKey(str[i]))
{
dic.Add(str[i], default);
}
dic[str[i]] = dic[str[i]] + 1;
}
return dic;
}
}
usage:
static void Main(string[] args)
{
Console.WriteLine("sdfdadddbd".ContainsAnyPermutationOf("ab"));
}
I guess the question is similar to LeetCode 567. These are simple, efficient, low-complexity accepted solutions:
C#
class Solution {
public bool CheckInclusion(string s1, string s2) {
int lengthS1 = s1.Length;
int lengthS2 = s2.Length;
if (lengthS1 > lengthS2)
return false;
int[] countmap = new int[26];
for (int i = 0; i < lengthS1; i++)
countmap[s1[i] - 97]++;
int[] bCount = new int[26];
for (int i = 0; i < lengthS2; i++) {
bCount[s2[i] - 97]++;
if (i >= (lengthS1 - 1)) {
if (allZero(countmap, bCount))
return true;
bCount[s2[i - (lengthS1 - 1)] - 97]--;
}
}
return false;
}
private bool allZero(int[] s1, int[] s2) {
for (int i = 0; i < 26; i++) {
if (s1[i] != s2[i])
return false;
}
return true;
}
}
Java
class Solution {
public boolean checkInclusion(String s1, String s2) {
int lengthS1 = s1.length();
int lengthS2 = s2.length();
if (lengthS1 > lengthS2)
return false;
int[] countmap = new int[26];
for (int i = 0; i < lengthS1; i++) {
countmap[s1.charAt(i) - 97]++;
countmap[s2.charAt(i) - 97]--;
}
if (allZero(countmap))
return true;
for (int i = lengthS1; i < lengthS2; i++) {
countmap[s2.charAt(i) - 97]--;
countmap[s2.charAt(i - lengthS1) - 97]++;
if (allZero(countmap))
return true;
}
return false;
}
private boolean allZero(int[] count) {
for (int i = 0; i < 26; i++)
if (count[i] != 0)
return false;
return true;
}
}
Python
class Solution:
def checkInclusion(self, s1, s2):
count_map_s1 = collections.Counter(s1)
count_map_s2 = collections.Counter(s2[:len(s1)])
for i in range(len(s1), len(s2)):
if count_map_s1 == count_map_s2:
return True
count_map_s2[s2[i]] += 1
count_map_s2[s2[i - len(s1)]] -= 1
if count_map_s2[s2[i - len(s1)]] == 0:
del(count_map_s2[s2[i - len(s1)]])
return count_map_s2 == count_map_a
Reference
The codes are explained in the following links:
LeetCode 567 Solution
LeetCode 567 Discussion Board
These two answers are also useful to look into:
Link 1
Link 2
private static bool CheckPermutationInclusion(string s1, string s2)
{
return Enumerable.Range(0, s2.Length - s1.Length)
.Select(i => s2.Substring(i, s1.Length))
.Any(x => x.All(y => s1.Contains(y)));
}
Description:
Enumerable.Range(Int32, Int32) Method: Generates a sequence of integral numbers within a specified range.
Enumerable.Select Method: Projects each element of a sequence into a new form.
Enumerable.All Method: Determines whether all elements of a sequence satisfy a condition.
Enumerable.Any Method: Determines whether any element of a sequence exists or satisfies a condition.
Do not forget using System.Linq;.

C# - Check if string contains characters of another string at the same order

I would like to check if a string contains the characters of another string (returning true or false), but it needs to be in the "right" order but not necessarily contiguous.
Example:
String firstWord = "arm";
String secondWord = "arandomword"; //TRUE - ARandoMword
String thirdWord = "road"; //FALSE - ARanDOmword
The word "arandomword" contains the letters of the word "road" but it's not possible to write it, because they are not at the right order.
Anyone, please?
Use regex. Something simple that passes your tests in linqpad:
void Main()
{
String firstWord = "arm";
String secondWord = "arandomword"; //TRUE - ARandoMword
String thirdWord = "road";
Regex.IsMatch(secondWord,makeRegex(firstWord.ToCharArray())).Dump();
}
// Define other methods and classes here
String makeRegex(char[] chars)
{
StringBuilder sb = new StringBuilder();
foreach (var element in chars.Select(c => Regex.Escape(c.ToString()))
.Select(c => c + ".*"))
{
sb.Append(element);
}
return sb.ToString();
}
you could define an extension method like this:
public static class StringExtensions
{
public static bool ContainsWord(this string word, string otherword)
{
int currentIndex = 0;
foreach(var character in otherword)
{
if ((currentIndex = word.IndexOf(character, currentIndex)) == -1)
return false;
}
return true;
}
}
and call it as expressive as:
String firstWord = "arm";
String secondWord = "arandomword"; //TRUE - ARandoMword
String thirdWord = "road"; //FALSE - ARanDOmword
var ret = secondWord.ContainsWord(firstWord); // true
var ret2 = thirdWord.ContainsWord(firstWord); // false
Something like this?
bool HasLettersInOrder(string firstWord, string secondWord)
{
int lastPos = -1;
foreach (char c in firstWord)
{
lastPos++;
while (lastPos < secondWord.Length && secondWord[lastPos] != c)
lastPos++;
if (lastPos == secondWord.Length)
return false;
}
return true;
}
I can not check right now, but something along the lines:
int i = 0, j = 0;
while(i < first.Length && j < second.Length)
{
while(first[i] != second[j] && j < second.Length) j++;
i++;
j++
}
bool b = i == first.Length;
Thanks for all the replies. I've tried and tried and I did it my way. Definitively it's not the shortest way to do it, but at least it's working:
public static Boolean checkWords(String smallerWord, String biggerWord)
{
int position = 0;
bool gotFirst = false;
bool gotAnother = false;
int positionBigger = 0;
String word = "";
for(int positionSmaller = 0; positionSmaller < smallerWord.Length; positionSmaller++)
{
if(!gotFirst)
{
if(biggerWord.Contains(smallerWord[positionSmaller].ToString()))
{
position = biggerWord.IndexOf(smallerWord[positionSmaller].ToString());
gotFirst = true;
word = smallerWord[positionSmaller].ToString();
}
}
else
{
gotAnother = false;
positionBigger = position + 1;
while(!gotAnother)
{
if(positionBigger < biggerWord.Length)
{
if(biggerWord[positionBigger].ToString().Equals(smallerWord[positionSmaller].ToString()))
{
position = positionBigger;
gotAnother = true;
word += smallerWord[positionSmaller].ToString();
}
else
{
positionBigger++;
}
}
else
{
gotAnother = true;
}
}
}
}
if(smallerWord.Equals(word))
{
return true;
}
else
{
return false;
}
}

Find common parent-path in list of files and directories

I got a list of files and directories List<string> pathes. Now I'd like to calculate the deepest common branch every path is sharing with each other.
We can assume that they all share a common path, but this is unknown in the beginning.
Let's say I have the following three entries:
C:/Hello/World/This/Is/An/Example/Bla.cs
C:/Hello/World/This/Is/Not/An/Example/
C:/Hello/Earth/Bla/Bla/Bla
This should get the result: C:/Hello/ as Earth is breaking this "chain" of subdirectories.
Second example:
C:/Hello/World/This/Is/An/Example/Bla.cs
C:/Hello/World/This/Is/Not/An/Example/
-> C:/Hello/World/This/Is/
How would you proceed? I tried to use string.split(#"/") and start with the first string and check if every part of this array is contained in the other strings. However, this would be a very expensive call as I'm iterating (list_of_entries)^list_of_entries. Is there any better solution available?
My current attempt would be something like the following (C# + LINQ):
public string CalculateCommonPath(IEnumerable<string> paths)
{
int minSlash = int.MaxValue;
string minPath = null;
foreach (var path in paths)
{
int splits = path.Split('\\').Count();
if (minSlash > splits)
{
minSlash = splits;
minPath = path;
}
}
if (minPath != null)
{
string[] splits = minPath.Split('\\');
for (int i = 0; i < minSlash; i++)
{
if (paths.Any(x => !x.StartsWith(splits[i])))
{
return i >= 0 ? splits.Take(i).ToString() : "";
}
}
}
return minPath;
}
A function to get the longest common prefix may look like this:
public static string GetLongestCommonPrefix(string[] s)
{
int k = s[0].Length;
for (int i = 1; i < s.Length; i++)
{
k = Math.Min(k, s[i].Length);
for (int j = 0; j < k; j++)
if (s[i][j] != s[0][j])
{
k = j;
break;
}
}
return s[0].Substring(0, k);
}
Then you may need to cut the prefix on the right hand. E.g. we want to return c:/dir instead of c:/dir/file for
c:/dir/file1
c:/dir/file2
You also may want to normalize the paths before processing. See Normalize directory names in C#.
I dont know whether this is the best performing solution (probably not), but it surely is very easy to implement.
Sort your list alphabetically
compare the first entry in that sorted list to the last in that list, character by character, and terminate when you find a difference (the value before the termination is the longest shared substring of both those strings)
Sample Fiddle
Sample code:
List<string> paths = new List<string>();
paths.Add(#"C:/Hello/World/This/Is/An/Example/Bla.cs");
paths.Add(#"C:/Hello/World/This/Is/Not/An/Example/");
paths.Add(#"C:/Hello/Earth/Bla/Bla/Bla");
List<string> sortedPaths = paths.OrderBy(s => s).ToList();
Console.WriteLine("Most common path here: {0}", sharedSubstring(sortedPaths[0], sortedPaths[sortedPaths.Count - 1]));
And that function of course:
public static string sharedSubstring(string string1, string string2)
{
string ret = string.Empty;
int index = 1;
while (string1.Substring(0, index) == string2.Substring(0, index))
{
ret = string1.Substring(0, index);
index++;
}
return ret;
} // returns an empty string if no common characters where found
First sort the list with the paths to inspect. Then you can split and compare the first and the last item - if they are same proceed to the next dimension until you find a difference.
So you just need to sort once and then inspect two items.
To return c:/dir for
c:/dir/file1
c:/dir/file2
I would code it this way:
public static string GetLongestCommonPrefix(params string[] s)
{
return GetLongestCommonPrefix((ICollection<string>)s);
}
public static string GetLongestCommonPrefix(ICollection<string> paths)
{
if (paths == null || paths.Count == 0)
return null;
if (paths.Count == 1)
return paths.First();
var allSplittedPaths = paths.Select(p => p.Split('\\')).ToList();
var min = allSplittedPaths.Min(a => a.Length);
var i = 0;
for (i = 0; i < min; i++)
{
var reference = allSplittedPaths[0][i];
if (allSplittedPaths.Any(a => !string.Equals(a[i], reference, StringComparison.OrdinalIgnoreCase)))
{
break;
}
}
return string.Join("\\", allSplittedPaths[0].Take(i));
}
And here are some tests for it:
[TestMethod]
public void GetLongestCommonPrefixTest()
{
var str1 = #"C:\dir\dir1\file1";
var str2 = #"C:\dir\dir1\file2";
var str3 = #"C:\dir\dir1\file3";
var str4 = #"C:\dir\dir2\file3";
var str5 = #"C:\dir\dir1\file1\file3";
var str6 = #"C:\dir\dir1\file1\file3";
var res = Utilities.GetLongestCommonPrefix(str1, str2, str3);
Assert.AreEqual(#"C:\dir\dir1", res);
var res2 = Utilities.GetLongestCommonPrefix(str1, str2, str3, str4);
Assert.AreEqual(#"C:\dir", res2);
var res3 = Utilities.GetLongestCommonPrefix(str1, str2, str3, str5);
Assert.AreEqual(#"C:\dir\dir1", res3);
var res4 = Utilities.GetLongestCommonPrefix(str5, str6);
Assert.AreEqual(#"C:\dir\dir1\file1\file3", res4);
var res5 = Utilities.GetLongestCommonPrefix(str5);
Assert.AreEqual(str5, res5);
var res6 = Utilities.GetLongestCommonPrefix();
Assert.AreEqual(null, res6);
var res7 = Utilities.GetLongestCommonPrefix(null);
Assert.AreEqual(null, res7);
}
I would iterate over each character in the first path, comparing it with every character in every path (except the first) in the collection of paths:
public string FindCommonPath(List<string> paths)
{
string firstPath = paths[0];
bool same = true;
int i = 0;
string commonPath = string.Empty;
while (same && i < firstPath.Length)
{
for (int p = 1; p < paths.Count && same; p++)
{
same = firstPath[i] == paths[p][i];
}
if (same)
{
commonPath += firstPath[i];
}
i++;
}
return commonPath;
}
You could iterate through the list first to find the shortest path and possibly improve it slightly.
The function that gives you the longest common directory path with best possible complexity:
private static string GetCommonPath(IEnumerable<string> files)
{
// O(N, L) = N*L; N - number of strings, L - string length
// if the first and last path from alphabetic order matches, all paths in between match
string first = null;//smallest string
string last = null;//largest string
var comparer = StringComparer.InvariantCultureIgnoreCase;
// find smallest and largest string:
foreach (var file in files.Where(p => !string.IsNullOrWhiteSpace(p)))
{
if (last == null || comparer.Compare(file, last) > 0)
{
last = file;
}
if (first == null || comparer.Compare(file, first) < 0)
{
first = file;
}
}
if (first == null)
{
// the list is empty
return string.Empty;
}
if (first.Length > last.Length)
{
// first should not be longer
var tmp = first;
first = last;
last = tmp;
}
// get minimal length
var count = first.Length;
var found = string.Empty;
const char dirChar = '\\';
var sb = new StringBuilder(count);
for (var idx = 0; idx < count; idx++)
{
var current = first[idx];
var x = char.ToLowerInvariant(current);
var y = char.ToLowerInvariant(last[idx]);
if (x != y)
{
// first and last string character is different - break
return found;
}
sb.Append(current);
if (current == dirChar)
{
// end of dir character
found = sb.ToString();
}
}
if (last.Length >= count && last[count] == dirChar)
{
// whole first is common root:
return first;
}
return found;
}
This is considerably more optimized than splitting paths by slash and comparing them:
private static string FindCommonPath(string[] paths) {
var firstPath = paths[0];
var commonPathLength = firstPath.Length;
for (int i = 1; i < paths.Length; i++)
{
var otherPath = paths[i];
var pos = -1;
var checkpoint = -1;
while (true)
{
pos++;
if (pos == commonPathLength)
{
if (pos == otherPath.Length
|| (pos < otherPath.Length
&& (otherPath[pos] == '/' || otherPath[pos] == '\\')))
{
checkpoint = pos;
}
break;
}
if (pos == otherPath.Length)
{
if (pos == commonPathLength
|| (pos < commonPathLength
&& (firstPath[pos] == '/' || firstPath[pos] == '\\')))
{
checkpoint = pos;
}
break;
}
if ((firstPath[pos] == '/' || firstPath[pos] == '\\')
&& (otherPath[pos] == '/' || otherPath[pos] == '\\'))
{
checkpoint = pos;
continue;
}
var a = char.ToLowerInvariant(firstPath[pos]);
var b = char.ToLowerInvariant(otherPath[pos]);
if (a != b)
break;
}
if (checkpoint == 0 && (firstPath[0] == '/' || firstPath[0] == '\\'))
commonPathLength = 1;
else commonPathLength = checkpoint;
if (commonPathLength == -1 || commonPathLength == 0)
return "";
}
return firstPath.Substring(0, commonPathLength);
}

How to find substring from string without using indexof method in C#?

I want to find the position of a substring in a string if present without using any string method including indexof. I tried so much times but failed. Will anybody tell me how to do in C#? We can use .Length operator.
Sorry.. thought this would be a fun exercise for me, so...
Spoiler
class Program
{
static void Main(string[] args)
{
string str = "abcdefg";
string substr = "cde";
int index = IndexOf(str, substr);
Console.WriteLine(index);
Console.ReadLine();
}
private static int IndexOf(string str, string substr)
{
bool match;
for (int i = 0; i < str.Length - substr.Length + 1; ++i)
{
match = true;
for (int j = 0; j < substr.Length; ++j)
{
if (str[i + j] != substr[j])
{
match = false;
break;
}
}
if (match) return i;
}
return -1;
}
}
Assuming this is homework, my suggestion is to bear in mind that a string is an IEnumerable of chars. So you can loop through the characters in your string...
Since any homework that inspired the question is well past due, here's a stab at a reasonably performant answer.
Simply cycling through the larger string, and cycling through the substring comparing each character as one goes takes Θ((n-m+1) m) time where m is the length of the substring, and n the index where the smaller string is found, or if there is no match the length of the larger minus that of the smaller.
There are a few different algorithm that give better performance, which differ among themselves in terms of which cases they work best in. The Knuth-Morris-Pratt algorithm takes Θ(m) to set up and then Θ(n) time to find, because it first creates a table to know how far ahead it can jump on failing to find a match, and on balance this makes for a quicker search.
Consider that if we were looking for "ababcd" and we'd first found "abab…" (possible match so far), if the next character is c we still have a possible match. If it's a we don't have a match, but should jump forward two characters to start looking for a match starting from that. If it's anything else, we should jump ahead five characters and continue looking for there. Preparing the table to tell us how far to jump makes things much faster from then on:
public static int IndexOf(string haystack, string needle)
{
if(haystack == null || needle == null)
throw new ArgumentNullException();
if(needle.Length == 0)
return 0;//empty strings are everywhere!
if(needle.Length == 1)//can't beat just spinning through for it
{
char c = needle[0];
for(int idx = 0; idx != haystack.Length; ++idx)
if(haystack[idx] == c)
return idx;
return -1;
}
if (needle.Length == haystack.Length) return needle == haystack ? 0 : -1;
if (needle.Length < haystack.Length)
{
int m = 0;
int i = 0;
int[] T = KMPTable(needle);
while(m + i < haystack.Length)
{
if(needle[i] == haystack[m + i])
{
if(i == needle.Length - 1)
return m == haystack.Length ? -1 : m;//match -1 = failure to find conventional in .NET
++i;
}
else
{
m = m + i - T[i];
i = T[i] > -1 ? T[i] : 0;
}
}
}
return -1;
}
private static int[] KMPTable(string sought)
{
int[] table = new int[sought.Length];
int pos = 2;
int cnd = 0;
table[0] = -1;
table[1] = 0;
while(pos < table.Length)
if(sought[pos - 1] == sought[cnd])
table[pos++] = ++cnd;
else if(cnd > 0)
cnd = table[cnd];
else
table[pos++] = 0;
return table;
}
Try this:
internal bool SearchWord(string str, string searchKey)
{
int j = 0; bool result = false;
for (int i = 0; i < str.Length; i++)
{
if (searchKey[j] == str[i])
{
j++; //count++;
}
else { j = 0; }
if (j == searchKey.Length)
{
result = true;
break;
}
}
return result;
}
Try this:
public static string BetweenOf(string ActualStr, string StrFirst, string StrLast)
{
return ActualStr.Substring(ActualStr.IndexOf(StrFirst) + StrFirst.Length,
(ActualStr.Substring(ActualStr.IndexOf(StrFirst))).IndexOf(StrLast) + StrLast.Length);
}
string mainString = Console.ReadLine();
string subString = Console.ReadLine();
for (int i = 0; i <= mainString.Length - subString.Length; i++)
{
bool match = true;
for (int j = 0; j < subString.Length && mainString[i + j] != subString[j]; j++)
{
match = false;
}
if (match)
Console.WriteLine(i);
}
public static findindex(String str,String substr)
{
char a[]=str.toCharArray();
char b[]=substr.toCharArray();
int j=0,t=0;
for(int i=0;i<str.length()&&j<substr.length();i++)
{
if(a[i]==b[j])
{
t=i;
j++;
}
else
continue;
}
if(t==0)
return -1;
else
return t-substr.length()+1;
}//in java

Categories