I was learning DSA to improve my logic in programming, i was solving this problem to find 2nd largest element in the array using C#. i couldnt do it for first time but idk how a logic clicked in my mind so i tried this i dont know if it is a good algorithm or fast but i wants to tell all the newbies that its the easiest way to find 2nd largest element in the array.
int[] arr = new int[8];
int secondlarge;
int temp;
for (int i = 0; i < arr.Length; i++)
{
Console.Write("Index - {0} :", i);
arr[i] = Convert.ToInt32(Console.ReadLine());
}
Console.WriteLine("Elemnts in array are: ");
for (int i = 0; i < arr.Length; i++)
{
Console.Write("{0} ", arr[i]);
}
Console.WriteLine();
temp = arr[0];
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > temp)
{
temp = arr[i];
}
}
secondlarge = arr[0];
for (int i = 0; i < arr.Length; i++)
{
if (temp == arr[i])
{
continue;
}
if (arr[i] > secondlarge)
{
secondlarge = arr[i];
}
}
Console.WriteLine("Second Largest Number is : " + secondlarge);
You can keep the max item and the next one:
int max = Math.Max(arr[0], arr[1]);
int result = Math.Min(arr[0], arr[1]);
for (int i = 2; i < arr.Length; ++i)
if (arr[i] >= max)
(result, max) = (max, arr[i]);
else if (arr[i] > result)
result = arr[i];
This approach can help in case of long arr: it's a bit faster then sorting (O(n) vs. O(n * log(n))) and doesn't require additional memory for sorted data (in case of Linq OrderByDescending)
Related
I've been working on a sorting algorithm and one condition says that the elements in the array should be program generated.
This is the code I've been working on.
int f;
Console.WriteLine("Enter how many elements you want to be sorted:");
f = Convert.ToInt32(Console.ReadLine());
int[] myArray = new int[f];
int smallest, tmp;
Console.WriteLine("Unsorted List");
foreach (int a in myArray)
Console.Write(a + " ");
for (int i = 0; i < myArray.Length - 1; i++)
{
smallest = i;
for (int j = i + 1; j < myArray.Length; j++)
{
if (myArray[j] < myArray[smallest])
{
smallest = j;
}
tmp = myArray[smallest];
myArray[smallest] = myArray[i];
myArray[i] = tmp;
}
}
Console.WriteLine("\nSorted List Using Selection Sort:");
for (int i=0; i < myArray.Length; i++)
{
Console.Write(myArray[i] + " ");
The result of this program is just 0. How can I make the elements in array program generated? Is there a specific code block?
Please note we should use i < myArray.Length to Iterate the array instead of i < myArray.Length-1.
You can try the following code to add the elements in program generated array.
static void Main(string[] args)
{
int f;
Console.WriteLine("Enter how many elements you want to be sorted:");
f = Convert.ToInt32(Console.ReadLine());
int[] myArray = new int[f];
int temp = 0;
int minIndex = 0;
Console.WriteLine("Unsorted List");
for (int i = 0; i < myArray.Length; i++)
{
myArray[i] = Convert.ToInt32(Console.ReadLine());
}
for (int i = 0; i < myArray.Length; i++)
{
minIndex = i;
for (int j = i; j < myArray.Length; j++)
{
if (myArray[j] < myArray[minIndex])
{
minIndex = j;
}
}
temp = myArray[minIndex];
myArray[minIndex] = myArray[i];
myArray[i] = temp;
}
Console.WriteLine("\nSorted List Using Selection Sort:");
for (int i = 0; i < myArray.Length; i++)
{
Console.Write(myArray[i] + " ");
}
Console.ReadKey();
}
Besides, I have modified the related code about Selection Sort, which makes it can produce the correct sort.
Result:
Update for generate the random array:
int f;
Console.WriteLine("Enter how many elements you want to be sorted:");
f = Convert.ToInt32(Console.ReadLine());
int[] myArray = new int[f];
Random randNum = new Random();
for (int i = 0; i < myArray.Length; i++)
{
myArray[i] = randNum.Next(1, 100);
}
Console.WriteLine("The radnom array is ");
foreach (var item in myArray)
{
Console.WriteLine(item);
}
I wrote this simple program:
class Program
{
static void Main(string[] args)
{
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
int[] array = new int[numberOfElements];
for(int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i+1}: ");
array[i] = int.Parse(Console.ReadLine());
}
for(int i = 0; i < array.Length; i++)
{
int count = 0;
for(int j = 0; j < array.Length; j++)
{
if(array[i] == array[j])
{
count++;
}
}
Console.WriteLine($"{array[i]} appears " + count + " times");
}
}
}
}
Is there any option to make the displayed values print only once?
For example, if there are three occurrences - the message displays three times. Is it possible to make it display once when there are more occurrences though?
You could use a GroupBy instead of the for loop
Groups the elements of a sequence.
var results = array
.GroupBy(x => x)
.Select(x => new {Value = x, Count = x.Count()});
foreach(var g in results)
Console.WriteLine($"{g.Value} appears {g.Count} times");
Or another way it to use a HashSet to keep track of what you have displayed. A HashSet is basically a collection that contains no duplicate elements. The Add methods returns true if it can add an element or false otherwise
HashSet<T>.Add(T) Method
returns true if the element is added to the HashSet object; false if the
element is already present.
var hashSet = new HashSet<int>();
for (int i = 0; i < array.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
if (array[i] == array[j])
count++;
// Add to the hashset, if the add method returns true,
// it means the value was uniquely added, ergo you have not displayed yet
if (hashSet.Add(array[i]))
Console.WriteLine($"{array[i]} appears " + count + " times");
}
Full Demo Here
Or another approach is to use a Dictionary. The premise is to iterate over the array, try an add each item to the dictionary with TryAdd if it's already found increment the value
var dictionary = new Dictionary<int,int>();
foreach(var item in array)
if(!dictionary.TryAdd(item,1))
dictionary[item]++;
foreach(var item in dictionary)
Console.WriteLine($"{item.Key} appears {item.Value} times");
Full Demo Here
The first idea I had was the same of the comment from Jon Skeet, since the simplicity it implies.
The idea is to set null for the value we have already counted (matched).
From a developer point of view it is very simple and doesn't deviate too much from the OP's code.
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
int?[] array = new int?[numberOfElements];
for (int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i + 1}: ");
array[i] = int.Parse(Console.ReadLine());
}
for (int i = 0; i < array.Length; i++)
{
int count = 0;
int? current = array[i];
if (array[i] != null)
{
for (int j = 0; j < array.Length; j++)
{
if (current == array[j])
{
count++;
array[j] = null;
}
}
Console.WriteLine($"{current} appears " + count + " times");
}
}
int?[] defines a nullable value type. Therefore each item in the array can have either a null or int value - documentation here.
An approach using Dictionary with O(n) complexity.
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
var dictionary = new Dictionary<int, int>();
for (int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i + 1}: ");
var value = int.Parse(Console.ReadLine());
if (!dictionary.ContainsKey(value)) dictionary.Add(value, 0);
dictionary[value] = dictionary[value] + 1;
}
foreach (var item in dictionary)
{
Console.WriteLine($"{item.Key} appears {item.Value} times");
}
One simple way would be to swap your outer for loop with a foreach using a set to obtain distinct values.
So replace this:
for (int i = 0; i < array.Length; i++)
With this:
foreach (int i in new HashSet<int>(array))
And this:
if (array[i] == array[j])
With this:
if (i == array[j])
Other approach more suited for you would be too take only unique values from array, i.e.:
var unique = array.Distinct().ToArray();
for (int i = 0; i < unique.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
{
if (array[i] == array[j])
{
count++;
}
}
Console.WriteLine($"{unique[i]} appears " + count + " times");
}
In the inner loop, try to check if there were already any occurrences of the current element until you exceed the outer index.
for(int i = 0; i < array.Length-1; i++)
{
int count = 1;
bool appeared = false;
for(int j = 0; j < array.Length; j++)
{
// until we are not at the same index as the outer loop
// check if we haven't already met the current element
if(j < i)
{
if (array[i] == array[j])
{
// set current value appearance to true
// to know if current element should be displayed
appeared = true;
// break the loop because there is no sense of continuing
// current look
break;
}
}
// if we are ahead of outer index
// check if there are occurences of the element
else if(j > i)
{
if (array[i] == array[j])
count++;
}
}
// don't print the current element if it has appeared before
if(!appeared)
Console.WriteLine($"{array[i]} appears {count} times");
}
I believe there should be a more optimal solution, as this one's time complexity is linear... You can think of some optimization. For example, you can store occurred elements in the array and check through the array at each iteration, so you don't need to start the inner loop from the beginning, but instead start it from the outer loop's position + 1 but it's also not the best solution.
P.S check out about string interpolation, because you don't need to concatenate strings when you use it.
You can also use Lookup here:
var sb = new StringBuilder();
foreach (var value in array.ToLookup(item => item))
{
sb.AppendLine($"{value.Key} appears " + value.Count() + " times");
}
Console.WriteLine(sb.ToString());
I keep receiving the error:
Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection
When the count of array elements is not even at directions.RemoveRange(i, 2);
public static string[] way(String[] arr)
{
int[] secondaryArr = new int[arr.Length];
for (int j = 0; j < arr.Length; j++)
{
switch (arr[j])
{
case "NORTH":
secondaryArr[j] = 1;
break;
case "SOUTH":
secondaryArr[j] = -1;
break;
case "WEST":
secondaryArr[j] = 2;
break;
case "EAST":
secondaryArr[j] = -2;
break;
}
}
var directions = arr.ToList();
for (int i = 0; i < directions.Count / 2; i++)
{
for (int j = 0; j < secondaryArr.Length - 1; j++)
{
if (secondaryArr[j] + secondaryArr[j + 1] == 0)
{
directions.RemoveRange(i, 2);
i = 0;
j = 0;
}
}
}
arr = directions.ToArray();
return arr;
}
I need to reduce the directions when the route is not reasonable. For example when I receive input like: [NORTH],[SOUTH],[WEST], it should be reduced to: [WEST], because going NORTH and SOUTH is not reasonable. The problem is that I get stuck at sorting the array.
Consider the following code:
int max = 1000;
int min = 0;
// Code sample A
for(int i = 0; i < array.Length; i++)
{
if (array[i] < min) min = array[i];
else if (array[i] > max) max = array[i];
}
and,
// Code Sample B
for (int i = 0; i < array.Length; i++)
{
if (array[i] < min) min = array[i];
}
for (int i = 0; i < array.Length; i++)
{
if (array[i] > max) max = array[i];
}
Of the above two code samples which one is more efficient?
I know some people would say that the first code sample would be faster as it does two instructions in one iteration. while, the second does it in two separate for loops. I am not so sure if that is true. Please explain.
To keep it simple,
in case A,
your program has to initialize i only once.
Assign values to i only array.Length times.
Increase i values only array.Length times.
do the line execution and comparison 2*array.Length times.
In case B,
initialize i twice.
Assign values to i 2*array.Length times.
Increase i values 2*array.Length times.
do line execution and comparison 2*array.Length times.
So, which one you would prefer?
Prajwal's answer is pretty accurate.
It is not difficult to test this (in Java):
public static void main(String[] args) {
int max = 1000;
int min = 0;
long start, stop, diff;
int[] arr = new int[100_000];
for (int i = 0; i < arr.length; i++)
arr[i] = (int) (-500_000 + Math.random() * 1_000_000);
start = System.nanoTime();
// Code sample A
for(int i = 0; i < arr.length; i++) {
if (arr[i] < min)
min = arr[i];
else if (arr[i] > max)
max = arr[i];
}
stop = System.nanoTime();
diff = stop - start;
System.out.println("nanoseconds needed for A: " + diff);
min = 0; max = 1000;
start = System.nanoTime();
// Code Sample B
for (int i = 0; i < arr.length; i++) {
if (arr[i] < min)
min = arr[i];
}
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max)
max = arr[i];
}
stop = System.nanoTime();
diff = stop - start;
System.out.println("nanoseconds needed for B: " + diff);
}
The result of it:
nanoseconds needed for A: 563581
nanoseconds needed for B: 1018710
I have written a console application
Int64 sum = 0;
int T = Convert.ToInt32(Console.ReadLine());
Int64[] input = new Int64[T];
for (int i = 0; i < T; i++)
{
input[i] = Convert.ToInt32(Console.ReadLine());
}
for (int i = 0; i < T; i++)
{
int[,] Matrix = new int[input[i], input[i]];
sum = 0;
for (int j = 0; j < input[i]; j++)
{
for (int k = 0; k < input[i]; k++)
{
Matrix[j, k] = Math.Abs(j - k);
sum += Matrix[j, k];
}
}
Console.WriteLine(sum);
}
When I gave input as
2
1
999999
It gave Out of memory exception. Can you please help.
Look at what you are allocating:
input[] is allocated as 2 elements (16 bytes) - no worries
But then you enter values: 1 and 999999 and in the first iteration of the loop attempt to allocate
Matrix[1,1] = 4 bytes - again no worries,
but the second time round you try to allocate
Matrix[999999, 999999]
which is 4 * 10e12 bytes and certainly beyond the capacity of your computer even with swap space on the disk.
I suspect that this is not what you really want to allocate (you'd never be able to fill or manipulate that many elements anyway...)
If you are merely trying to do the calculations as per your original code, there is not need to allocate or use the array, as you only ever store one value and immediately use that value and then never again.
Int64 sum = 0;
int T = Convert.ToInt32(Console.ReadLine());
Int64[] input = new Int64[T];
for (int i = 0; i < T; i++)
input[i] = Convert.ToInt32(Console.ReadLine());
for (int i = 0; i < T; i++)
{
// int[,] Matrix = new int[input[i], input[i]];
sum = 0;
for (int j = 0; j < input[i]; j++)
for (int k = 0; k < input[i]; k++)
{
//Matrix[j, k] = Math.Abs(j - k);
//sum += Matrix[j, k];
sum += Math.Abs(j - k);
}
Console.WriteLine(sum);
}
But now beware - a trillion sums is going to take forever to calculate - it won't bomb out, but you might like to take a vacation, get married and have kids before you can expect a result.
Of course instead of doing the full squared set of calculations, you can calculate the sum thus:
for (int i = 0; i < T; i++)
{
sum = 0;
for (int j = 1, term = 0; j < input[i]; j++)
{
term += j;
sum += term * 2;
}
Console.WriteLine(sum);
}
So now the calculation is O(n) instead of O(n^2)
And if you need to know what the value in Matrix[x,y] would have been, you can calculate it by the simple expression Math.Abs(x - y) thus there is no need to store that value.