How to determine that one array is a part of another one? - c#

For instance: I have array
var src = new byte[] {1, 2, 3, 4, 5};
var tag = new byte[] {3, 4};
Who know fast method to find index of tag's array?
I need something as following:
int FindIndexOfSeq(byte[] src, byte[] sequence);
a sequence can be in more than one times in src.
Solution: How to find index of sublist in list?

The best you can get is O(m), but that I slightly complex implementation. If you satisfy with a solution that has O(m*n) as worst case you can go with the solution below. If your sequences are ordered and the starting item in the tag array is only present one time in src this will also result in O(m).
class Program
{
static void Main(string[] args)
{
var src = new byte[] { 1, 2, 3, 4, 5 };
var tag = new byte[] { 3, 4 };
var index = FindIndexOfSeq(src, tag);
Console.WriteLine(index);
Console.ReadLine();
}
static int FindIndexOfSeq<T>(T[] src, T[] seq)
{
int index = -1;
for (int i = 0; i < src.Length - seq.Length + 1; i++)
{
bool foundSeq = true;
for (int j = 0; j < seq.Length; j++)
{
foundSeq = foundSeq && src[i + j].Equals(seq[j]);
}
if (foundSeq)
{
index = i;
break;
}
}
return index;
}
}
I assumed the sequence have to be in that order and I have only compiled it in firefox, so not sure if it works :). Also, I made it generic so it handles any type of arrays not just bytes.
UPDATE: The updated code compiles and work... or my simple test worked.

Here's one way to the get the index
for (int i = 0; i < (src.Length - tag.Length); i++ )
{
if (tag.SequenceEqual(src.Skip(i).Take(tag.Length)))
Console.WriteLine("It's at position " + i);
}
Unfortunately it's very slow.
If you just want to know if all of items in tag can be found in src (in any order) then
var src = new byte[] { 1, 2, 3, 4, 5 };
var tag = new byte[] { 4, 3 };
if (src.Intersect(tag).Count() == tag.Length)
Console.WriteLine("tag can be found in src!");

int FindIndexOfSeq<T>(byte[] src, byte[] tag)
{
Int32 tagCount = tag.Count();
// If `tag` is not empty and `src` contains `tag`
if (tagCount > 0 && src.Intersect(tag).Count() == tagCount)
{
// Find index of first element in `tag`
Int32 tagStartIndex = Array.IndexOf(src, tag.First());
// Get the matching slice of `tag` from `src`
var newSrc = src.Skip(tagStartIndex).Take(tag.Count()).ToList();
// Zip them together using their difference
var sum = Enumerable.Zip(tag, newSrc, (i1, i2) => Convert.ToInt32(i2 - i1)).Sum();
// If total of their differences is zero, both sequences match
if (sum == 0)
{
// return starting index of `tag` in `src`
return tagStartIndex;
}
}
// return `Not Found`
return -1;
}

This task is equal to searching substring in string. For this you may use any KMP algorithm for better performance:
http://exclusiveminds.com/2009/12/09/kmp-string-searching-algorithm-in-c/

Solution found.
How to find index of sublist in list?

Related

getting the index of an array, multiple times, then storing them in an array c#

I want to get the index of an array which I have done with Array.IndexOf(array, value). This works good with one value but I want to get every occurrence of the value and store the index's into another array. For example, the name 'tom' appears 5 times in an array, I want to find the index positions of each one.
Maybe something like this? This uses a list rather than an array, but it follows the same idea.
List<int> Indexes = new List<int>();
for (int i = 0; i < array.Count(); i++)
{
if (array[i] == "tom")
{
Indexes.Add(i);
}
}
This solution is like the previous one, but will run faster:
string value = "tom";
int[] indices = stringArray.Where(s => s != null)
.Select((s, i) => s.Equals(value) ? i: -1)
.Where(i => i >= 0)
.ToArray();
If I'm not mistaken, you can add another parameter to IndexOf(), which will let you specify where in the array to start. This should give you more or less what you need:
var indices = new List<int>();
int i = Array.IndexOf(array, val);
while(i > -1){
indices.Add(i);
i = Array.IndexOf(array, val, i+1);
}
// ... and if it is important to have the result as an array:
int[] result = indices.ToArray();
Practical example:
var array = new int[]{ 1, 2, 3, 3, 4, 5, 3, 6, 7, 8, 3};
int val = 3;
var indices = new List<int>();
int i = Array.IndexOf(array, val);
while(i > -1){
indices.Add(i);
i = Array.IndexOf(array, val, i+1);
}
// ... and if it is important to have the result as an array:
int[] result = indices.ToArray();
Edit: Just realized a while-loop may well be a lot cleaner than a for-loop for this.
Edit 2: Due to popular demand (see comment below), here`s the original beautiful non-basic for-loop, re-introduced just for your reading pleasure:
for(int i = Array.IndexOf(array, val); i > -1; i = Array.IndexOf(array, val, i+1)){
indices.Add(i);
}
Could create an extension method to do it
namespace Extensions
{
public static class ArrayExtension
{
public static IEnumerable<int> GetIndicesOf<T>(this T[] target, T val, int start = 0)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = start; i < target.Length; i++)
{
if (comparer.Equals(target[i], val))
{
yield return i;
}
}
}
}
}
Add the using statement for your namespace with the extension method using Extensions; in the file you want to call it in.
Then to call it just do the following to get the indices.
IEnumerable<int> indices = array.GetIndicesOf(value);
or to get an array just do
int[] indicies = array.GetIndicesOf(value).ToArray();
You can use LINQ's Select overload which uses elements index as well, like:
var indices = stringArray.Select((s, i) => new {Value = s, Index = i})
.Where(r => r.Value == "tom")
.Select(r => r.Index);

Shifting A single element in an array

I want to shift one element in an array to the right each time whilst leaving the original elements in their specific order in C#.
Ok so I've been asked to reword the code I can understand why so here we go:
I might have a number 48390
//the ar elements have been commented out to show that we never know what ar contains but only the that I will always want to shift; ar[4]
int[] ar = new int[5];
//ar[0] = 4
//ar[1] = 8
//ar[2] = 3
//ar[3] = 9
//ar[4] = 0
while(ar != 04839)
{
Shift code
}
I might input 5 numbers 48390 if you notice its the same number but one digit is out. I want a while loop to rotate that 4 ar[1] to shift until the number forms 04839
I hope this makes sense. I am posting this question because most pages posting information about shifting based on shifting all elements to the right and I only really want to shift one specific element.
Thanks for looking.
edit: I should have been more specific. What if you don't know what each of the array elements could be? So I couldn't depend on "0" as an anchor. as another set of numbers might include another number for example "00238."
This method will give you a sequence of arrays made by inserting a single element into (between) each position in a given array:
public static IEnumerable<T[]> InsertElementBetweenAllPositions<T>(
T[] array, T element)
{
int newLength = array.Length + 1;
for (int i = 0; i < newLength; i++)
{
T[] rtn = new T[newLength];
rtn[i] = element;
Array.Copy(array, 0, rtn, 0, i);
Array.Copy(array, i, rtn, i + 1, array.Length - i);
yield return rtn;
}
}
For your example, you might call it as
foreach (int[] arr in InsertElementBetweenAllPositions(new[] { 6, 7, 8, 9 }, 0))
{
foreach (int i in arr)
Console.Write(i + " ");
Console.WriteLine();
}
How about this:
List<int> l = new List<int>(){0,6,7,8,9};
for (int i=1;i<5;i++)
{
l.Remove(0);
l.Insert(i, 0);
}
What's in your example is a swap, which can be implemented like:
private void Swap(ref int[] array, int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
Calling Swap(ref source, 0, 1) would exchange the first and second element. What you want then is:
for (int i = 0; i < a.Length-1; i++)
{
Swap(ref a, i, i+1);
}
This "bubbles" the first element up to the last position in each iteration.
From the example you need to shift elements around, and the example is a bit confusing over whether you need to loop them around to the start again. I have provided the below example that will loop around to the start - If you do not need to do that, the you can rework the if the statement.
private int[] Shift(int[] a)
{
int zeroPos = Array.IndexOf(a, 0);
int[] rtn = new int[a.Length];
a.CopyTo(rtn, 0);
if (zeroPos + 1 == a.Length)
{
rtn[0] = 0;
for (int i = 0; i < a.Length - 1; i++)
{
rtn[i + 1] = a[i];
}
}
else
{
rtn[zeroPos] = rtn[zeroPos + 1];
rtn[zeroPos + 1] = 0;
}
return rtn;
}
r=ar[0];
for (int i = 0; ar.lenght;i++)
{
ar[i]=ar[i + 1];
}
ar[ar.lenght] = r;
Have you thought about using a LinkedList instead? A linked list data structure is probably more suited to what you are trying to do than an array. The AddFirst, AddLast, AddAfter and AddBefore methods allow you to insert elements into the list in a much more efficient way than re-organizing your array each time.
The disadvantage of linked lists is that you need to read the elements in order. So, it's very efficient for inserting/deleting elements but inefficient for accessing elements randomly.
There is a good overview of LinkedLists here.
Perhaps
int oldLast = ar[ar.Length - 1];
for (int i = ar.Length - 1; i >= 0; i--)
ar[i] = i == 0 ? oldLast : ar[i - 1];
Demo
It is just a permutation of an item , below is the full source code of permutation algorithm.
static List<string> Put(char s1, string list)
{
List<string> str =new List<string>();
for (int i = 0; i < list.Length+1; i++)
{
string s = list.Substring(0, i) + s1.ToString() + list.Substring(i);
str.Add(s);
}
return str;
}
static List<string> Permute(string list,int x)
{
List<string> Result = new List<string>();
if (list.Length == 1)
{
Result.Add(list[0].ToString());
return Result;
}
else
{
char first = list[0];
list = list.Substring(x+1);
List<string> part = Permute(list,0);
foreach (string str in part)
{
List<string> hasBeenPlaced = Put(first, str);
foreach (string str2 in hasBeenPlaced)
{
Result.Add(str2);
}
}
}
return Result;
}
static void Main(string[] args)
{
List<string> per = Permute("abc",0);
for (int i = 0; i < per.Count; i++)
{
Console.WriteLine(per[i]);
}
Console.ReadKey();
}
Now if I add a break after the foreach , your problem has been solved . (it will writes all permuation for just an item which you want , not all of them....)
So change that to :
foreach (string str in part)
{
List<string> hasBeenPlaced = Put(first, str);
foreach (string str2 in hasBeenPlaced)
{
Result.Add(str2);
}
break;
}
Hope to helps you
If you you linq, that's simple :-) But you need a size larger than the array.
ShiftLeft(ar, 1);
private static int[] ShiftLeft(int[] value, int countOfShift = 1)
{
var length = value.Length;
if (countOfShift > length)
{
throw new InvalidOperationException("countOfShift must less then value's length.");
}
var tempList = new List<int>(value);
tempList.RemoveRange(length - countOfShift, countOfShift);
tempList.InsertRange(0, value.Skip(length - countOfShift));
return tempList.ToArray();
}

inserting element into a list, if condition is met with C#

How to insert some number into the middle of the list, if there is no such number present?
In the example below I'm trying to insert number 4
List<int> list1 = new List<int>(){ 0, 1, 2, 3, 5, 6 };
int must_enter = 4;
if (!list1.Contains(must_enter))
{
list1.Add(must_enter);
}
As the result number will be entered at the end of the list, but I want it right after 3 (before 5).
please note that due to project's specifics I can't use sorted list, but all numbers in the list are guaranteed to be in ascending order (0,2,6,9,10,...)
EDIT: I knew about an error and that's what I did:
List<int> list0 = new List<int>() { 1, 2, 3, 5, 6 };
int must_enter = 7;
if (!list0.Contains(must_enter))
{
if (must_enter < list0.Max())
{
int result = list0.FindIndex(item => item > must_enter || must_enter > list0.Max());
list0.Insert(result, must_enter);
}
else
{
list0.Add(must_enter);
}
}
edit2: anyway I've switched to BinarySearch method due to several factors. Everyone thanks for your help!
You could do something like this:
int index = list1.BinarySearch(must_enter);
if (index < 0)
list1.Insert(~index, must_enter);
This way you will keep the list sorted with the best possible performance.
You can do:
list1.Add(must_enter);
And then order the list:
list1 = list1.OrderBy(n => n).ToList();
The result will be:
0, 1, 2, 3, 4, 5, 6
EDIT:
Or use an extesion method:
static class Utility
{
public static void InsertElement(this List<int> list, int n)
{
if(!list.Contains(n))
{
for(int i = 0; i < list.Count; i++)
{
if(list[i] > n)
{
list.Insert(i-1, n);
break;
}
if(i == list.Count - 1)
list.Add(n);
}
}
}
}
And then:
list1.InsertElement(must_enter);
You are looking for
list1.Insert(index, must_enter);
To insert an element at a specific index rather than at the end of the list.
You'll have to find the index to insert at first which is easily done with a binary search. Start with the value in the middle of the list and compare it to your number to insert. If it's greater, search the lower half of the list, if it's more, search the upper half of the list. Repeat the process, dividing the list in half each time until you find the spot where the item before is less than the one you are inserting and the item after is more than the one you are inserting. (edit: of course, if you list is always very small, it's probably less hassle just to iterate through the list from the beginning to find the right spot!)
List<int> list1 = new List<int>() { 0, 1, 2, 3, 5, 6 };
int must_enter = 4;
for (int i = 0; i < list1.Count; i++)
{
if (must_enter >= list1[i])
{
list1.Insert(i + 1, must_enter);
}
}
Edit: I like sarwar026, implementation better.
list1.Insert(4, 4)
List<T>.Insert Method - Inserts an element into the List at the specified index.
Quick Note-
the Insert instance method on the List type does not have good performance in many cases. because for Insert, list has to adjust the following elements.
here is the original post from where i got this answer try it out may help you : Finding best position for element in list
List<int> list = new List<int>{0,2,6,9,10};
for (int i = 0; i < list1.Count; i++)
{
int index = list.BinarySearch(i);
if( i < 0)
{
int insertIndex = ~index;
list.Insert(insertIndex, i);
}
}
just for one missing element as op needs
int index = list.BinarySearch(4);
if( index < 0)
{
int insertIndex = ~index;
list.Insert(insertIndex, 4);
}
or
List<int> list1 = new List<int>() { 0,2,6,9,10 };
int must_enter = 4;
for (int i = 0; i < list1.Count; i++)
{
if (!list1.Contains(i))
{
list1.Insert(i , i);
}
}
just for one element as op needs
if (!list1.Contains(4))
{
list1.Insert(4 , 4);
}
List<int> list1 = new List<int>(){ 0, 1, 2, 3, 5, 6 };
int must_enter = 4;
if (!list1.Contains(must_enter))
{
int result = list.FindIndex(item => item > must_enter);
if(result!=-1)
list1.Insert(result, must_enter);
else // must_enter is not found
{
if(must_enter > list.Max()) // must_enter > max value of list
list1.Add(must_enter);
else if(must_enter < list.Min()) // must_enter < min value of list
list1.Insert(0, must_enter);
}
}
First, find the index of the number which is greater than must_enter(4) and then insert the must_enter to that position
if (!list1.Contains(must_enter))
{
SortedSet<int> sorted = new SortedSet<int>( list1 );
sorted.Add( must_enter );
list1 = sorted.ToList();
}

Find the smallest window of input array that contains all the elements of query array

Problem: Given an input array of integers of size n, and a query array of integers of size k, find the smallest window of input array that contains all the elements of query array and also in the same order.
I have tried below approach.
int[] inputArray = new int[] { 2, 5, 2, 8, 0, 1, 4, 7 };
int[] queryArray = new int[] { 2, 1, 7 };
Will find the position of all query array element in inputArray.
public static void SmallestWindow(int[] inputArray, int[] queryArray)
{
Dictionary<int, HashSet<int>> dict = new Dictionary<int, HashSet<int>>();
int index = 0;
foreach (int i in queryArray)
{
HashSet<int> hash = new HashSet<int>();
foreach (int j in inputArray)
{
index++;
if (i == j)
hash.Add(index);
}
dict.Add(i, hash);
index = 0;
}
// Need to perform action in above dictionary.??
}
I got following dictionary
int 2--> position {1, 3}
int 1 --> position {6}
int 7 --> position {8}
Now I want to perform following step to findout minimum window
Compare int 2 position to int 1 position. As (6-3) < (6-1)..So I will store 3, 6 in a hashmap.
Will compare the position of int 1 and int 7 same like above.
I cannot understand how I will compare two consecutive value of a dictionary. Please help.
The algorithm:
For each element in the query array, store in a map M (V → (I,P)), V is the element, I is an index into the input array, P is the position in the query array. (The index into the input array for some P is the largest such that query[0..P] is a subsequence of input[I..curr])
Iterate through the array.
If the value is the first term in the query array: Store the current index as I.
Else: Store the value of the index of the previous element in the query array, e.g. M[currVal].I = M[query[M[currVal].P-1]].I.
If the value is the last term: Check if [I..curr] is a new best.
Complexity
The complexity of this is O(N), where N is the size of the input array.
N.B.
This code expects that no elements are repeated in the query array. To cater for this, we can use a map M (V → listOf((I,P))). This is O(NhC(Q)), where hC(Q) is the count of the mode for the query array..
Even better would be to use M (V → listOf((linkedList(I), P))). Where repeated elements occur consecutively in the query array, we use a linked list. Updating those values then becomes O(1). The complexity is then O(NhC(D(Q))), where D(Q) is Q with consecutive terms merged.
Implementation
Sample java implementation is available here. This does not work for repeated elements in the query array, nor do error checking, etc.
I don't see how using HashSet and Dictionary will help you in this. Were I faced with this problem, I'd go about it quite differently.
One way to do it (not the most efficient way) is shown below. This code makes the assumption that queryArray contains at least two items.
int FindInArray(int[] a, int start, int value)
{
for (int i = start; i < a.Length; ++i)
{
if (a[i] == value)
return i;
}
return -1;
}
struct Pair
{
int first;
int last;
}
List<Pair> foundPairs = new List<Pair>();
int startPos = 0;
bool found = true;
while (found)
{
found = false;
// find next occurrence of queryArray[0] in inputArray
startPos = FindInArray(inputArray, startPos, queryArray[0]);
if (startPos == -1)
{
// no more occurrences of the first item
break;
}
Pair p = new Pair();
p.first = startPos;
++startPos;
int nextPos = startPos;
// now find occurrences of remaining items
for (int i = 1; i < queryArray.Length; ++i)
{
nextPos = FindInArray(inputArray, nextPos, queryArray[i]);
if (nextPos == -1)
{
break; // didn't find it
}
else
{
p.last = nextPos++;
found = (i == queryArray.Length-1);
}
}
if (found)
{
foundPairs.Add(p);
}
}
// At this point, the foundPairs list contains the (start, end) of all
// sublists that contain the items in order.
// You can then iterate through that list, subtract (last-first), and take
// the item that has the smallest value. That will be the shortest sublist
// that matches the criteria.
With some work, this could be made more efficient. For example, if 'queryArray' contains [1, 2, 3] and inputArray contains [1, 7, 4, 9, 1, 3, 6, 4, 1, 8, 2, 3], the above code will find three matches (starting at positions 0, 4, and 8). Slightly smarter code could determine that when the 1 at position 4 is found, since no 2 was found prior to it, that any sequence starting at the first position would be longer than the sequence starting at position 4, and therefore short-circuit the first sequence and start over at the new position. That complicates the code a bit, though.
You want not a HashSet but a (sorted) tree or array as the value in the dictionary; the dictionary contains mappings from values you find in the input array to the (sorted) list of indices where that value appears.
Then you do the following
Look up the first entry in the query. Pick the lowest index where it appears.
Look up the second entry; pick the lowest entry greater than the index of the first.
Look up the third; pick the lowest greater than the second. (Etc.)
When you reach the last entry in the query, (1 + last index - first index) is the size of the smallest match.
Now pick the second index of the first query, repeat, etc.
Pick the smallest match found from any of the starting indices.
(Note that the "lowest entry greater" is an operation supplied with sorted trees, or can be found via binary search on a sorted array.)
The complexity of this is approximately O(M*n*log n) where M is the length of the query and n is the average number of indices at which a given value appears in the input array. You can modify the strategy by picking that query array value that appears least often for the starting point and going up and down from there; if there are k of those entries (k <= n) then the complexity is O(M*k*log n).
After you got all the positions(indexes) in the inputArray:
2 --> position {0,2} // note: I change them to 0-based array
1 --> position {5,6} // I suppose it's {5,6} to make it more complex, in your code it's only {5}
7 --> position {7}
I use a recursion to get all possible paths. [0->5->7] [0->6->7] [2->5->7] [2->6->7]. The total is 2*2*1=4 possible paths. Obviously the one who has Min(Last-First) is the shortest path(smallest window), those numbers in the middle of the path don't matter. Here comes the code.
struct Pair
{
public int Number; // the number in queryArray
public int[] Indexes; // the positions of the number
}
static List<int[]> results = new List<int[]>(); //store all possible paths
static Stack<int> currResult = new Stack<int>(); // the container of current path
static int[] inputArray, queryArray;
static Pair[] pairs;
After the data structures, here is the Main.
inputArray = new int[] { 2, 7, 1, 5, 2, 8, 0, 1, 4, 7 }; //my test case
queryArray = new int[] { 2, 1, 7 };
pairs = (from n in queryArray
select new Pair { Number = n, Indexes = inputArray.FindAllIndexes(i => i == n) }).ToArray();
Go(0);
FindAllIndexes is an extension method to help find all the indexes.
public static int[] FindAllIndexes<T>(this IEnumerable<T> source, Func<T,bool> predicate)
{
//do necessary check here, then
Queue<int> indexes = new Queue<int>();
for (int i = 0;i<source.Count();i++)
if (predicate(source.ElementAt(i))) indexes.Enqueue(i);
return indexes.ToArray();
}
The recursion method:
static void Go(int depth)
{
if (depth == pairs.Length)
{
results.Add(currResult.Reverse().ToArray());
}
else
{
var indexes = pairs[depth].Indexes;
for (int i = 0; i < indexes.Length; i++)
{
if (depth == 0 || indexes[i] > currResult.Last())
{
currResult.Push(indexes[i]);
Go(depth + 1);
currResult.Pop();
}
}
}
}
At last, a loop of results can find the Min(Last-First) result(shortest window).
Algorithm:
get all indexes into the inputArray
of all queryArray values
order them ascending by index
using each index (x) as a starting
point find the first higher index
(y) such that the segment
inputArray[x-y] contains all
queryArray values
keep only those segments that have the queryArray items in order
order the segments by their lengths,
ascending
c# implementation:
First get all indexes into the inputArray of all queryArray values and order them ascending by index.
public static int[] SmallestWindow(int[] inputArray, int[] queryArray)
{
var indexed = queryArray
.SelectMany(x => inputArray
.Select((y, i) => new
{
Value = y,
Index = i
})
.Where(y => y.Value == x))
.OrderBy(x => x.Index)
.ToList();
Next, using each index (x) as a starting point find the first higher index (y) such that the segment inputArray[x-y] contains all queryArray values.
var segments = indexed
.Select(x =>
{
var unique = new HashSet<int>();
return new
{
Item = x,
Followers = indexed
.Where(y => y.Index >= x.Index)
.TakeWhile(y => unique.Count != queryArray.Length)
.Select(y =>
{
unique.Add(y.Value);
return y;
})
.ToList(),
IsComplete = unique.Count == queryArray.Length
};
})
.Where(x => x.IsComplete);
Now keep only those segments that have the queryArray items in order.
var queryIndexed = segments
.Select(x => x.Followers.Select(y => new
{
QIndex = Array.IndexOf(queryArray, y.Value),
y.Index,
y.Value
}).ToArray());
var queryOrdered = queryIndexed
.Where(item =>
{
var qindex = item.Select(x => x.QIndex).ToList();
bool changed;
do
{
changed = false;
for (int i = 1; i < qindex.Count; i++)
{
if (qindex[i] <= qindex[i - 1])
{
qindex.RemoveAt(i);
changed = true;
}
}
} while (changed);
return qindex.Count == queryArray.Length;
});
Finally, order the segments by their lengths, ascending. The first segment in the result is the smallest window into inputArray that contains all queryArray values in the order of queryArray.
var result = queryOrdered
.Select(x => new[]
{
x.First().Index,
x.Last().Index
})
.OrderBy(x => x[1] - x[0]);
var best = result.FirstOrDefault();
return best;
}
test it with
public void Test()
{
var inputArray = new[] { 2, 1, 5, 6, 8, 1, 8, 6, 2, 9, 2, 9, 1, 2 };
var queryArray = new[] { 6, 1, 2 };
var result = SmallestWindow(inputArray, queryArray);
if (result == null)
{
Console.WriteLine("no matching window");
}
else
{
Console.WriteLine("Smallest window is indexes " + result[0] + " to " + result[1]);
}
}
output:
Smallest window is indexes 3 to 8
Thank you everyone for your inputs. I have changed my code a bit and find it working. Though it might not be very efficient but I'm happy to solve using my head :). Please give your feedback
Here is my Pair class with having number and position as variable
public class Pair
{
public int Number;
public List<int> Position;
}
Here is a method which will return the list of all Pairs.
public static Pair[] GetIndex(int[] inputArray, int[] query)
{
Pair[] pairList = new Pair[query.Length];
int pairIndex = 0;
foreach (int i in query)
{
Pair pair = new Pair();
int index = 0;
pair.Position = new List<int>();
foreach (int j in inputArray)
{
if (i == j)
{
pair.Position.Add(index);
}
index++;
}
pair.Number = i;
pairList[pairIndex] = pair;
pairIndex++;
}
return pairList;
}
Here is the line of code in Main method
Pair[] pairs = NewCollection.GetIndex(array, intQuery);
List<int> minWindow = new List<int>();
for (int i = 0; i <pairs.Length - 1; i++)
{
List<int> first = pairs[i].Position;
List<int> second = pairs[i + 1].Position;
int? temp = null;
int? temp1 = null;
foreach(int m in first)
{
foreach (int n in second)
{
if (n > m)
{
temp = m;
temp1 = n;
}
}
}
if (temp.HasValue && temp1.HasValue)
{
if (!minWindow.Contains((int)temp))
minWindow.Add((int)temp);
if (!minWindow.Contains((int)temp1))
minWindow.Add((int)temp1);
}
else
{
Console.WriteLine(" Bad Query array");
minWindow.Clear();
break;
}
}
if(minWindow.Count > 0)
{
Console.WriteLine("Minimum Window is :");
foreach(int i in minWindow)
{
Console.WriteLine(i + " ");
}
}
It is worth noting that this problem is related to the longest common subsequence problem, so coming up with algorithms that run in better than O(n^2) time in the general case with duplicates would be challenging.
Just in case someone is interested in C++ implementation with O(nlog(k))
void findMinWindow(const vector<int>& input, const vector<int>& query) {
map<int, int> qtree;
for(vector<int>::const_iterator itr=query.begin(); itr!=query.end(); itr++) {
qtree[*itr] = 0;
}
int first_ptr=0;
int begin_ptr=0;
int index1 = 0;
int queptr = 0;
int flip = 0;
while(true) {
//check if value is in query
if(qtree.find(input[index1]) != qtree.end()) {
int x = qtree[input[index1]];
if(0 == x) {
flip++;
}
qtree[input[index1]] = ++x;
}
//remove all nodes that are not required and
//yet satisfy the all query condition.
while(query.size() == flip) {
//done nothing more
if(queptr == input.size()) {
break;
}
//check if queptr is pointing to node in the query
if(qtree.find(input[queptr]) != qtree.end()) {
int y = qtree[input[queptr]];
//more nodes and the queue is pointing to deleteable node
//condense the nodes
if(y > 1) {
qtree[input[queptr]] = --y;
queptr++;
} else {
//cant condense more just keep that memory
if((!first_ptr && !begin_ptr) ||
((first_ptr-begin_ptr)>(index1-queptr))) {
first_ptr=index1;
begin_ptr=queptr;
}
break;
}
} else {
queptr++;
}
}
index1++;
if(index1==input.size()) {
break;
}
}
cout<<"["<<begin_ptr<<" - "<<first_ptr<<"]"<<endl;
}
here the main for calling it.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main() {
vector<int> input;
input.push_back(2);
input.push_back(5);
input.push_back(2);
input.push_back(8);
input.push_back(0);
input.push_back(1);
input.push_back(4);
input.push_back(7);
vector<int> query1;
query1.push_back(2);
query1.push_back(8);
query1.push_back(0);
vector<int> query2;
query2.push_back(2);
query2.push_back(1);
query2.push_back(7);
vector<int> query3;
query3.push_back(1);
query3.push_back(4);
findMinWindow(input, query1);
findMinWindow(input, query2);
findMinWindow(input, query3);
}

Merging two lists into one and sorting the items

Is there a way to merge(union without dupes) two given lists into one and store the items in sorted way by using ONE for loop?
Also, i am looking for a solution which does not makes use of API methods ( like, union, sort etc).
Sample Code.
private static void MergeAndOrder()
{
var listOne = new List<int> {3, 4, 1, 2, 7, 6, 9, 11};
var listTwo = new List<int> {1, 7, 8, 3, 5, 10, 15, 12};
//Without Using C# helper methods...
//ToDo.............................
//Using C# APi.
var expectedResult = listOne.Union(listTwo).ToList();
expectedResult.Sort();//Output: 1,2,3,4,5,6,7,8,9,10,11,12,15
//I need the same result without using API methods, and that too by iterating over items only once.
}
PS: I have been asked this question in an interview, but couldn't find answer as yet.
Why can't you use the api methods? Re-inventing the wheel is dumb. Also, it's the .ToList() call that's killing you. Never call .ToList() or .ToArray() until you absolutely have to, because they break your lazy evaluation.
Do it like this and you'll enumerate the lists with the minimum amount necessary:
var expectedResult = listOne.Union(listTwo).OrderBy(i => i);
This will do the union in one loop using a hashset, and lazy execution means the base-pass for the sort will piggyback on the union. But I don't think it's possible finish the sort in a single iteration, because sorting is not a O(n) operation.
Without the precondition that both lists are sorted before the merge + sort operation, you can't do this in O(n) time (or "using one loop").
Add that precondition and the problem is very easy.
Keep two iterators, one for each list. On each loop, compare the element from each list and choose the smaller. Increment that list's iterator. If the element you are about to insert in the final list is already the last element in that list, skip the insert.
In pseudocode:
List a = { 1, 3, 5, 7, 9 }
List b = { 2, 4, 6, 8, 10 }
List result = { }
int i=0, j=0, lastIndex=0
while(i < a.length || j < b.length)
// If we're done with a, just gobble up b (but don't add duplicates)
if(i >= a.length)
if(result[lastIndex] != b[j])
result[++lastIndex] = b[j]
j++
continue
// If we're done with b, just gobble up a (but don't add duplicates)
if(j >= b.length)
if(result[lastIndex] != a[i])
result[++lastIndex] = a[i]
i++
continue
int smallestVal
// Choose the smaller of a or b
if(a[i] < b[j])
smallestVal = a[i++]
else
smallestVal = b[j++]
// Don't insert duplicates
if(result[lastIndex] != smallestVal)
result[++lastIndex] = smallestVal
end while
private static void MergeTwoSortedArray(int[] first, int[] second)
{
//throw new NotImplementedException();
int[] result = new int[first.Length + second.Length];
int i=0 , j=0 , k=0;
while(i < first.Length && j <second.Length)
{
if(first[i] < second[j])
{
result[k++] = first[i++];
}
else
{
result[k++] = second[j++];
}
}
if (i < first.Length)
{
for (int a = i; a < first.Length; a++)
result[k] = first[a];
}
if (j < second.Length)
{
for (int a = j; a < second.Length; a++)
result[k++] = second[a];
}
foreach (int a in result)
Console.Write(a + " ");
Console.WriteLine();
}
Using iterators and streaming interface the task is not that complicated:
class MergeTwoSortedLists
{
static void Main(string[] args) {
var list1 = new List<int?>() {
1,3,5,9,11
};
var list2 = new List<int?>() {
2,5,6,11,15,17,19,29
};
foreach (var c in SortedAndMerged(list1.GetEnumerator(), list2.GetEnumerator())) {
Console.Write(c+" ");
}
Console.ReadKey();
}
private static IEnumerable<int> SortedAndMerged(IEnumerator<int?> e1, IEnumerator<int?> e2) {
e2.MoveNext();
e1.MoveNext();
do {
while (e1.Current < e2.Current) {
if (e1.Current != null) yield return e1.Current.Value;
e1.MoveNext();
}
if (e2.Current != null) yield return e2.Current.Value;
e2.MoveNext();
} while (!(e1.Current == null && e2.Current == null));
}
}
Try this:
public static IEnumerable<T> MergeWith<T>(IEnumerable<T> collection1, IEnumerable<T> collection2,
IComparer<T> comparer)
{
using (var enumerator1 = collection1.GetEnumerator())
using (var enumerator2 = collection2.GetEnumerator())
{
var isMoveNext1 = enumerator1.MoveNext();
var isMoveNext2 = enumerator2.MoveNext();
do
{
while (comparer.Compare(enumerator1.Current, enumerator2.Current) < 0 || !isMoveNext2)
{
if (isMoveNext1)
yield return enumerator1.Current;
else
break;
isMoveNext1 = enumerator1.MoveNext();
}
if (isMoveNext2)
yield return enumerator2.Current;
isMoveNext2 = enumerator2.MoveNext();
} while (isMoveNext1 || isMoveNext2);
}
}
You could write a loop that merges and de-dups the lists and uses a binary-search approach to insert new values into the destination list.
var listOne = new List<int> { 3, 4, 1, 2, 7, 6, 9, 11 };
var listTwo = new List<int> { 1, 7, 8, 3, 5, 10, 15, 12 };
var result = listOne.ToList();
foreach (var n in listTwo)
{
if (result.IndexOf(n) == -1)
result.Add(n);
}
The closest solution I see would be to allocate an array knowing that integers are bounded to some value.
int[] values = new int[ Integer.MAX ]; // initialize with 0
int size1 = list1.size();
int size2 = list2.size();
for( int pos = 0; pos < size1 + size2 ; pos++ )
{
int val = pos > size1 ? list2[ pos-size1 ] : list1[ pos ] ;
values[ val ]++;
}
Then you can argue that you have the sorted array in a "special" form :-) To get a clean sorted array, you need to traverse the values array, skip all position with 0 count, and build the final list.
This will only work for lists of integers, but happily that is what you have!
List<int> sortedList = new List<int>();
foreach (int x in listOne)
{
sortedList<x> = x;
}
foreach (int x in listTwo)
{
sortedList<x> = x;
}
This is using the values in each list as the index position at which to store the value. Any duplicate values will overwrite the previous entry at that index position. It meets the requirement of only one iteration over the values.
It does of course mean that there will be 'empty' positions in the list.
I suspect the job position has been filled by now though.... :-)

Categories