Related
I have been trying for days to find a solution for this problem using c#. I was able to sort them by length but I cannot figure out the solution to sort the array by from their left-most to their right-most.
The hint they gave is to define a class Sequence to hold a sequence of elements. We will implement IComparable<Sequence> to compare sequences by length in decreasing order (and by elements in decreasing order when the length is the same). Later we will use our TreeMultiSet class. Inside we will keep the first 10 sub-sequences of S, i.e. multi-set of the lucky sub-sequences of P, kept in decreasing order by length (and in decreasing order of their content when the length is the same). When we have 10 sub-sequences inside the multi-set and we add 11th sequence, it would take its correct place in the order, because of the IComparable<Sequence> defined. After that we can delete the 11th subsequence, because it is not amongst the first 10
Here is the problem:
We are given a sequence P containing L integers L (1 < L < 50,000) and a number N. We call a “lucky sub-sequence within P” every subsequence of integers from P with a sum equal to N. Imagine we have a sequence S, holding all the lucky sub-sequences of P, kept in decreasing order by their length. When the length is the same, the sequences are ordered in decreasing order by their elements: from the leftmost to the rightmost. Write a program to return the first 10 elements of S
Example: We are given N = 5 and the sequence P = {1, 1, 2, 1, -1, 2, 3, -1, 1, 2, 3, 5, 1, -1, 2, 3}. The sequence S consists of the following 13 sub-sequences of P:
[1, -1, 2, 3, -1, 1]
[1, 2, 1, -1, 2]
[3, -1, 1, 2]
[2, 3, -1, 1]
[1, 1, 2, 1]
[1, -1, 2, 3]
[1, -1, 2, 3]
[-1, 1, 2, 3]
[5, 1, -1]
[2, 3]
[2, 3]
[2, 3]
[5]
My solution:
Actually, when reading the hint I was not able to understand the idea so I came up with another way.
class Find
{
//Function to manually create an array with N elements
public static int[] ArrCreate(int n, int[] Arr)
{
for (int i = 0; i < n; i++)
{
Arr[i] = Convert.ToInt32(Console.ReadLine());
}
return Arr;
}
//Create a Dictionary class type to hold sub-array with sum of sub-array equal to given number k
public static Dictionary<int, ArrayList> SubSeqEqual2N()
{
Console.WriteLine("Input k: ");
int k = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Input n element to create an Array: ");
int n = Convert.ToInt32(Console.ReadLine());
int[] Arr = new int[n];
int[] newArr = ArrCreate(n, Arr);
int keyIndex = 0;
//ArrayList arlist = new ArrayList();
Dictionary<int, ArrayList> SeqofLuckyArr = new Dictionary<int, ArrayList> { };
//Create a loop to find sub-array with the sum equal to given number K.
for (int i = 0; i < newArr.Length; i++)
{
int sum = 0;
for (int j = i; j < newArr.Length; j++)
{
sum = sum + newArr[j];
if (sum == k)
{
//When sub-array with the sum equal to given number K is found then add them into a temp Arraylist, also increment the keyIndex.
keyIndex++;
ArrayList temp = new ArrayList();
for (int ko = i; ko <= j; ko++)
{
temp.Add(newArr[ko]);
}
//DEBUG PURPOSE
/*Console.Write("{");
foreach (var hehe in temp)
{
Console.Write("{0}", string.Join(", ", hehe));
}
Console.Write("}");
Console.WriteLine("");
arlist.AddRange(temp);*/
//Then add that temp array as value into a Dictionary <key,value>type with that KeyIndex.
SeqofLuckyArr.Add(keyIndex,temp);
}
}
}
//DEBUG PURPOSE
//My method to sort the sub-array in the Dictionary by sub-array length and by key index.
foreach(KeyValuePair<int,ArrayList> kvp in SeqofLuckyArr.OrderByDescending(x => x.Value.Count).ThenBy(y => y.Key))
{
Console.Write("Key={0} ",kvp.Key);
Console.Write(",");
Console.Write("Value={ ");
foreach (var hoho in kvp.Value)
{
Console.Write("{0} ", string.Join(", ", hoho));
}
Console.WriteLine("}");
Console.WriteLine("");
arlist.AddRange(kvp.Value);
}
//DEBUG PURPOSE
return SeqofLuckyArr;
}
}
I try to find the sub-array with the sum equal to the given number K first then add them into the Dictionary as value with its key as index. Then sort -sub-array by length use OrderByDecreasing method.
The result:
Key=4 ,Value={ 1 -1 2 3 -1 1 }
Key=2 ,Value={ 1 2 1 -1 2 }
Key=1 ,Value={ 1 1 2 1 }
Key=3 ,Value={ 1 -1 2 3 }
Key=6 ,Value={ 2 3 -1 1 }
Key=7 ,Value={ 3 -1 1 2 }
Key=8 ,Value={ -1 1 2 3 }
Key=12 ,Value={ 1 -1 2 3 }
Key=11 ,Value={ 5 1 -1 }
Key=5 ,Value={ 2 3 }
Key=9 ,Value={ 2 3 }
Key=13 ,Value={ 2 3 }
Key=10 ,Value={ 5 }
But the result is not the same as the example. My problem is that I am stuck at "When the length is the same, the sequences are ordered in decreasing order by their elements: from the leftmost to the rightmost". As I thought left-most to right most is the key index of the sub-array from low to high.
Can anyone help me to find the appropriate way to order the sub-array in decreasing order by the elements? If my edition is not also appropriate to ask on SO I will delete my question.
Thank you!
It seems the problem lies solely in your ordering. The contents of the sequences are identical to the example.
First, the line you are ordering doesn't quite follow the rules specified:
foreach(KeyValuePair<int,ArrayList> kvp in SeqofLuckyArr
.OrderByDescending(x => x.Value.Count)
.ThenBy(y => y.Key))
[...] kept in decreasing order by their length. When the length is the same, the sequences are ordered in decreasing order by their elements: [...]
The first ordering seems correct (OrderByDescending(x => x.Value.Count)) by descending order of the sequences' length. The second ordering is currently ordered by the sequences' "key index" and in ascending order. This should have been in descending/decreasing (ThenByDescending) order based on the contents of the "lucky sub-sequences".
One way you can fix all this is by introducing an IComparer implementation a bit similar to the hint given. The IComparer below is able to take two sequences (int[]) as input and tell which of the two should come before the other (see the documentation for an explanation of what the return value of IComparer.Compare means):
public class IntArrayComparer : IComparer<int[]>
{
public int Compare(int[] x, int[] y)
{
// Ensure we don't get a null-ref exception further down
if (x == null || y == null)
// x should come before (-1) or after (1) y (default ascending order)
return y == null ? -1 : 1;
// If the lengths are different, the length is the first ordering priority
if (x.Length != y.Length)
// Use the built-in 'CompareTo' method for the 'int' type
return x.Length.CompareTo(y.Length);
// Lengths are the same, so we compare the contents
for (var i = 0; i < x.Length; i++)
{
var comparison = x[i].CompareTo(y[i]);
// If the elements in the two seq. are different, we return the ordering
if (comparison != 0)
return comparison;
}
return 0;
}
}
Now the previous mentioned line with your ordering becomes a little simpler (subjective opinion :)):
foreach(KeyValuePair<int,ArrayList> kvp in SeqofLuckyArr
.OrderByDescending(x => x.Value, new IntArrayComparer()))
Check out this fiddle for a test run of the ordering part.
Hint: You actually don't even need to store your subsequences in a Dictionary - a List would suffice.
Sorry for late response. After referring the Imcomparer implementation above. I was able to get the output the same as example. Here is my code for anyone facing the same issues as me.
class Find
{
public static int[] ArrCreate(int n, int[] Arr)
{
for (int i = 0; i < n; i++)
{
Arr[i] = Convert.ToInt32(Console.ReadLine());
}
return Arr;
}
public static void SubSeqEqual2N()
{
Console.WriteLine("Input k: ");
int k = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Input n element to create an Array: ");
int n = Convert.ToInt32(Console.ReadLine());
int[] Arr = new int[n];
int[] newArr = ArrCreate(n, Arr);
//int keyIndex = 0;
//ArrayList arlist = new ArrayList();
//Dictionary<int, ArrayList> SeqofLuckyArr = new Dictionary<int, ArrayList> { };
//Create a List of int array to store
List<int[]> luckyArray = new List<int[]>{ };
for (int i = 0; i < newArr.Length; i++)
{
int sum = 0;
for (int j = i; j < newArr.Length; j++)
{
sum = sum + newArr[j];
if (sum == k)
{
//keyIndex++;
ArrayList temp = new ArrayList();
for (int ko = i; ko <= j; ko++)
{
temp.Add(newArr[ko]);
}
//Convert ArrayList temp into int array for applying IComparer.Compare<Int[],Int[]>
int[] luckySubArray = temp.ToArray(typeof(int)) as int[];
luckyArray.Add(luckySubArray);
//SeqofLuckyArr.Add(keyIndex,temp);
}
}
}
var orderedSeq = luckyArray.OrderByDescending(s => s, new IntArrayComparer());
foreach(var seq in orderedSeq)
{
Console.Write("[ ");
foreach (var i in seq)
{
Console.Write("{0} ", string.Join(", ", i));
}
Console.Write(" ]");
Console.WriteLine("");
}
}
}
public class IntArrayComparer : IComparer<int[]>
{
public int Compare(int[] x, int[] y)
{
// Ensure we don't get a null-ref exception further down
if (x == null || y == null)
// x should come before (-1) or after (1) y (default ascending order)
return y == null ? -1 : 1;
// If the lengths are different, the length is the first ordering priority
if (x.Length != y.Length)
// Use the built-in 'CompareTo' method for the 'int' type
return x.Length.CompareTo(y.Length);
// Lengths are the same, so we compare the contents
for (var i = 0; i < x.Length; i++)
{
var comparison = x[i].CompareTo(y[i]);
// If the elements in the two seq. are different, we return the ordering
if (comparison != 0)
return comparison;
}
return 0;
}
}
And the output:
[ 1 -1 2 3 -1 1 ]
[ 1 2 1 -1 2 ]
[ 3 -1 1 2 ]
[ 2 3 -1 1 ]
[ 1 1 2 1 ]
[ 1 -1 2 3 ]
[ 1 -1 2 3 ]
[ -1 1 2 3 ]
[ 5 1 -1 ]
[ 2 3 ]
[ 2 3 ]
[ 2 3 ]
[ 5 ]
static void PrintPartOfArray(int[] array, int from, int to)
{
int x = array.Length;
if (from > x && from < 0)
{
Console.WriteLine("there is an exeption!");
}
if (to > x && to < 0)
{
Console.WriteLine("there is an exeption!");
}
else
{
for (int i = from; i <= to; i++)
{
Console.WriteLine(array[i]);
}
}
}
static void Main(string[] args)
{
int[] array2 = new int[] { 3, 6, 54, 24, -90, 7, 4 };
PrintPartOfArray(array2,2,7);
}
it supposes to show the "exception error when the function receives a number outside the length of the array, for some reason it not working, when I checked with the debugger it simply skipped the if loops, what have I done wrong?
Consider "early return" for things like this.
if (from > array.Length - 1 || to > array.Length - 1 || from < 0 || to < 0)
{
Console.WriteLine("One of your arguments is out of range.");
return;
}
// Normal, error-free code goes here.
If from and to are greater than x, they can't possibly also be less than 0. Recall that x is the length of an array, which can't be negative. That being said, it's literally impossible for either of your if statements to evaluate to true. Did you mean || instead?
Also, the last index of the array is array.Length - 1, not array.Length. Similarly, the first item in the array is at index 0, not index 1. I think that your array indices are off by 1 here.
We are working on the Project Euler problems and there is one part of the code I cannot get to work.
I have displayed and calculated the sum for multiples of 3 and 5 under 10, and I have calculated the sum for the same numbers under 1000 but I cannot initially display the numbers used for the calculation within a textbox or equivalent field.
Here's a link to the code.
http://pastebin.com/MZAA88UP
I think, it's a good task for Linq:
int n = 1000;
var numbers = Enumerable
.Range(1, n - 1)
.Where(item => item % 3 == 0 || item % 5 == 0);
Having numbers as a source you can easily play with it. If you want to sum up:
// 233168
var sum = numbers.Sum();
If you want to print out the numbers:
// 3, 5, 6, 9, 10, 12, ..., 996, 999
string report = string.Join(", ", numbers);
If you want to use loops instead of Linq:
private void BtnDisplay1000_Click(object sender, RoutedEventArgs e)
{
var stringBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
if (i % 3 == 0 || i % 5 == 0)
{
stringBuilder.Append(i);
stringBuilder.Append(", ");
}
}
TxtDisplay1000.Text = (stringBuilder.ToString());
}
I have a class RekenReeks which returns numbers starting from 2, multiplied by 2. So {2,4,8,16,32,64}
Now I learned about the TakeWhile and SkipWhile methods as well as LINQ.
So I have created 3 variables which should store exactly the same but my Console.WriteLine only prints selection1 and not 2 and 3.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
RekenReeks reeks = new RekenReeks(2, n => n * 2);
var selection = from i in reeks
where i > 10
&& i < 1000
select i;
var selection2 = reeks.TakeWhile(n => n < 1000 && n > 10);
var selection3 = reeks.SkipWhile(n => n > 1000 && n < 10);
foreach (int i in selection)
{
Console.WriteLine("selection1 {0}",i);
}
foreach (int i in selection2)
{
Console.WriteLine("selection2 {0}", i);
}
foreach (int i in selection3)
{
Console.WriteLine("selection3 {0}", i);
}
Console.ReadLine();
}
}
public class RekenReeks : IEnumerable<int>
{
Func<int, int> getNew;
int number;
public RekenReeks(int starton, Func<int, int> getNewThing)
{
getNew = getNewThing;
number = starton;
}
public IEnumerator<int> GetEnumerator()
{
yield return number;
for (; ; )
{
yield return getNew(number);
number = getNew(number);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
}
Your sequence is unlimited (theoretically). You assume too much. The functionality of your program cannot possibly know that your sequence is strictly monotonic increasing.
var selection = from i in reeks
where i > 10
&& i < 1000
select i;
This will never stop. Because the where will always pull the next value, it does not know it's condition will be satisfied, it always has to check the next value.
var selection2 = reeks.TakeWhile(n => n < 1000 && n > 10);
This will take values, while they are between 11 and 999. As your sequence starts with 2, it will stop right on the first value.
var selection3 = reeks.SkipWhile(n => n > 1000 && n < 10);
This will skip values while they are between 11 and 999. As the first is 2, it will skip none and therefore yield all.
Both TakeWhile() and SkipWhile() start from very beginning of the sequence and stop taking/skipping when condition doesn't meet.
// I've redesigned your ReekenReeks
// [2, 4, 8, 16, 32, 64, ..., 2**30]
var reeks = Enumerable
.Range(1, 30)
.Select(index => 1 << index);
For instance, if you put
var selection2 = reeks
.TakeWhile(n => n < 1000 && n > 10);
since the 1st item of the reeks is 2 the condition n < 1000 && n > 10 doesn't meet TakeWhile stops and returns an empty sequence. The right implemenation is
var selection2 = reeks
.SkipWhile(n => n <= 10)
.TakeWhile(n => n < 1000);
If you want to cut off values from the middle of the sequence (selection3) you have to use Where:
var selection3 = reeks
.Where(n => !(n > 1000 && n < 10)); // cut theses items off
Be careful when printing out an infinine sequence, .Take() is a good choice here:
var selection3 = reeks
.Where(n => n > 1000 && n < 10)
.Take(100); // First 100 items in case the sequence is too long
var selection = from i in reeks
where i > 10
&& i < 1000
select i;
There's no reason for this to ever end. When i is 1024 it won't be yielded, but it will still check then if 2048 is less than 1000, or 4096 is less than 1000, or 8192 is less than 1000 and so on forever (eventually either overflow exception happens or n wraps around to 0 which then keeps being set to 0 * 2 which is still 0).
reeks.TakeWhile(n => n < 1000 && n > 10)
The first value tried is 2. This does not satisfy the predicate n < 1000 && n > 10 because it is not true that 2 > 10. Therefore the taking stops.
reeks.SkipWhile(n => n > 1000 && n < 10)
There is no value of n for which n > 1000 && n < 10. Therefore this is the same as having no SkipWhile at all.
It seems like what you want is:
reeks.SkipWhile(n => n >= 1000 || n <= 10).TakeWhile(n => n < 1000 && n > 10)
Which skips until the first number that meets the criteria is found, then takes all that meet it until the first that does not.
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.... :-)