Getting a timeout with Big Numbers - c#

I was solving CodeWars task(https://www.codewars.com/kata/5e4bb05b698ef0001e3344bc/train/csharp) and faced a problem. In it you are given the array of numbers, which length is multiply of 4, you need to visualise it as a (x1^2 + x2^2) * (x3^2 + x4^2) .... * (xn^2 + xn+1^2). Calculate the result of this and find 2 numbers, which squares in sum, gives the result of initial sequance. For example, you are given an array of ( 2, 1, 3, 4): (2^2 + 1^2) * (3^2 + 4^2) = 125; 2 numbers, which squares in sum will give 125, is 2 and 11 because 4 + 121 = 125; I wrote the code and it works with most of examples, but when i use big arrays such as (5, 4, 4, 5, 5, 4, 2, 4, 7, 6, 5, 9, 8, 7, 6, 5, 4, 9, 6, 5, 7, 9, 5, 8, 9, 6, 8, 4, 9, 2, 5, 5, 3, 9, 7, 9, 2, 6, 3, 2) in result i receive a timeout. How can i avoid timeouts? If u can use simplified english cause i am from Russia. Here is my code:
using System;
using System.Numerics;
using System.Collections.Generic;
public class ProdSeq
{
public static BigInteger[] solve(int[] arr)
{
bool simplified = false;
var result = new BigInteger[2];
var index = 0;
BigInteger sequenceSum = 1;
for (int i = 0; i < arr.Length - 1; i+=2)
sequenceSum *= arr[i] * arr[i] + arr[i + 1] * arr[i + 1];
if (sequenceSum >= 1000000)
{
sequenceSum /= 10000;
simplified = true;
}
var list = new List<BigInteger>();
for (BigInteger i = 0; i <= (BigInteger)Math.Sqrt((double)sequenceSum + 1); i++)
list.Add(BigInteger.Multiply(i, i));
for (int i = 0; i < list.Count; i++)
{
var second = sequenceSum - list[i];
index = list.BinarySearch(second);
if (index > -1)
{
if (simplified)
{
result[0] = (BigInteger)(Math.Sqrt((double)list[i]) * 100);
result[1] = (BigInteger)(Math.Sqrt((double)list[index]) * 100);
break;
}
result[0] = (BigInteger)(Math.Sqrt((double)list[i]));
result[1] = (BigInteger)(Math.Sqrt((double)list[index]));
break;
}
}
Console.WriteLine($"A: {result[0]} B: {result[1]}");
return result;
}
}

To avoid to waste time to build the list of square number and/or to have an out of memory exception, you just test directly if the big number is the sum of 2 square number like this : (its basic solution)
//method which calulates the sqrt of bigInteger
public static BigInteger Sqrt(BigInteger number)
{
BigInteger n = 0, p = 0;
if (number == BigInteger.Zero)
{
return BigInteger.Zero;
}
var high = number >> 1;
var low = BigInteger.Zero;
while (high > low + 1)
{
n = (high + low) >> 1;
p = n * n;
if (number < p)
{
high = n;
}
else if (number > p)
{
low = n;
}
else
{
break;
}
}
return number == p ? n : low;
}
public static BigInteger[] solve(int[] arr)
{
var result = new BigInteger[2];
BigInteger sequenceSum = BigInteger.One;
for (int i = 0; i < arr.Length - 1; i += 2)
sequenceSum = BigInteger.Multiply(sequenceSum, BigInteger.Add(BigInteger.Multiply(arr[i], arr[i]), BigInteger.Multiply(arr[i + 1], arr[i + 1])));
var range = BigInteger.Add(Sqrt(sequenceSum), BigInteger.One);
var isq = BigInteger.Zero;
var second = BigInteger.Zero;
for (BigInteger first = 1; first <= range; first++)
{
isq = BigInteger.Multiply(first, first);
var diff = BigInteger.Subtract(sequenceSum, isq);
second = Sqrt(diff);
if (BigInteger.Multiply(second, second) == diff)
{
result[0] = first;
result[1] = second;
break;
}
}
Console.WriteLine($"A: {result[0]} B: {result[1]}");
return result;
}
var r = solve(new int[] { 5, 4, 4, 5, 5, 4, 2, 4, 7, 6, 5, 9, 8, 7, 6, 5, 4, 9, 6, 5, 7, 9, 5, 8, 9, 6, 8, 4, 9, 2, 5, 5, 3, 9, 7, 9, 2, 6, 3, 2 });
//one solution is 17123330522880 and 1190972610311564160 after 20 minutes
you could check quickly the solution by setting:
for (BigInteger i = 17123330522870; i <= range; i++)
to increase performance to trap the result:
check if number could be the sum of 2 square number (see differents algorythm on internet)
use parallel for loop to speed the solution (you cut the main for loop by 10 for loops for example)
but for this type of big number, the time to find solution is very long in c# or ypu have to be lucky...
Matlab should speed up really the calculus...

Related

How to add the current iteration's value to the previous iteration's value in a loop C#

I can find a Java version for my question, but not C#. My current attempt goes crazy when attempting to add them. I feel like there is a simple fix, but I'm struggling to think of it.
// See https://aka.ms/new-console-template for more information
int[] input = { 28, 2, 3, -3, -2, 1, 2, 35, -1, 0, 0, -1 };
for (int i = 0; i < input.Length; i++)
{
int x = input[i];
int y = input[i++];
int output = x + y;
Console.WriteLine(output);
}
If I understand your task answer is (updated):
var sum = 0;
var input = new int[] { 28, 2, 3, -3, -2, 1, 2, 35, -1, 0, 0, -1 };
for (var i = 0; i < input.Length - 1; i++)
{
sum += input[i];
Console.WriteLine(sum);
}
This is the correct code :
int[] input = { 28, 2, 3, -3, -2, 1, 2, 35, -1, 0, 0, -1 };
for (int i = 0; i < input.Length - 1; i++)
{
int x = input[i];
int y = input[i + 1];
int output = x + y;
Console.WriteLine(output);
}

Present Sequence as a sum of 2 squares

I was solving a CodeWars task and faced a problem.
In it you are given the array of numbers, which length is a multiple of 4, you need to visualise it as a (x1^2 + x2^2) * (x3^2 + x4^2) .... * (xn^2 + xn+1^2).
Calculate the result of this and find 2 numbers, which squares in sum, gives the result of initial sequance.
For example, you are given an array of ( 2, 1, 3, 4):
(2^2 + 1^2) * (3^2 + 4^2) = 125;
2 numbers, which squares in sum will give 125, is 2 and 11 because 4 + 121 = 125;
I wrote the code and it works with most of examples, but when i use big arrays such as
(3, 9, 8, 4, 6, 8, 7, 8, 4, 8, 5, 6, 6, 4, 4, 5) in result i receive (0,0);
I can't get the problem, help me pls and if u can use simplified english cause i am from Russia.
Here is my code:
using System;
using System.Numerics;
using System.Collections.Generic;
public class ProdSeq
{
public static BigInteger[] solve(int[] arr)
{
bool simplified = false;
var result = new BigInteger[2];
var index = 0;
BigInteger sequenceSum = 1;
for (int i = 0; i < arr.Length - 1; i+=2)
sequenceSum *= arr[i] * arr[i] + arr[i + 1] * arr[i + 1];
if (sequenceSum >= 1000000)
{
sequenceSum /= 10000;
simplified = true;
}
var list = new List<BigInteger>();
for (BigInteger i = 0; i <= (BigInteger)Math.Sqrt((double)sequenceSum + 1); i++)
list.Add(BigInteger.Multiply(i, i));
for (int i = 0; i < list.Count; i++)
{
var second = sequenceSum - list[i];
index = list.BinarySearch(second);
if (index > -1)
{
if (simplified)
{
result[0] = (BigInteger)(Math.Sqrt((double)list[i]) * 100);
result[1] = (BigInteger)(Math.Sqrt((double)list[index]) * 100);
break;
}
result[0] = (BigInteger)(Math.Sqrt((double)list[i]));
result[1] = (BigInteger)(Math.Sqrt((double)list[index]));
break;
}
}
Console.WriteLine($"A: {result[0]} B: {result[1]}");
return result;
}
}
it seems your error is coming from this line:
for (int i = 0; i <= (int)Math.Sqrt((double)sequenceSum + 1); i++)
list.Add(BigInteger.Multiply(i , i));
you have to use Biginteger.Multiply method
result = 302400 and 29092800 (lot of solutions i think)

How to return an array fibonaci numbers in C #?

I want to make a function that takes an array of integers as input and print an array of int as Fibonaci series like: third element= second element + first element.
Here is my code so far:
static void Result(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] < 0)
Console.WriteLine("arr[i]", arr[i], " number to get must be greater or equal than 0");
var n = arr[i] + 1;
var a = new int[n];
arr[0] = 0;
if (arr[i] == 0)
{
a[1] = 1;
}
for ( i = 2; i < n; i++)
{
a[i] = a[i - 2] + a[i - 1];
}
}
}
public static void Main()
{
int[] arr = {7, 8, 3, 9, 11,16,14,91, };
Result(arr);
}
if input is : 1 ,3 ,4 ,6, 7 ,8 10, 11, 15 ,25 output should be: 1, 3, 4, 7, 11 so 1+3=4, 4+3=7 and so on.
I took a look at your code and you were very close.
The biggest issue was you were starting at i = 0 which would cause errors if you attempted to access arr[-1] and arr[-2].
We can solve that by starting with i = 2.
For example:
static int[] Result(int[] arr)
{
int[] result = arr;
for (int i = 2; i < arr.Length; i++)
{
result[i] = result[i-1] + result[i-2];
}
return result;
}
int[] arr = { 1 ,3 ,4 ,6, 7 ,8, 10, 11, 15 ,25 };
arr = Result(arr);
Console.WriteLine(string.Join(", ",arr));
// outputs: 1, 3, 4, 7, 11, 18, 29, 47, 76, 123
Another side note is that unless you're passing the int[] arr as a reference you will need to return a new int[] as the result since Result()'s changes to arr are not reflected on the array.

How to combine two arrays of integers and return average?

Ok so I have two arrays of integers, and I have to return the average rating of the two days. This is the code that I have come up with thus far, but apparently it does not meet the expectations. Result:
Message: Expected: 5.0d
But was: 3.0d
Unit:
public double WeekendAverage(int[] saturday, int[] sunday)
{
int[] n = { saturday.Length, sunday.Length };
int sum = 0;
for (int i = 0; i < n.Length; i++)
{
sum = saturday[i] + sunday[i];
return sum / n.Length;
}
return sum;
}
UnitTest:
[TestCase(new[] { 1, 2, 3, 4, 5, 7, 8, 5, 10 }, new[] { 9, 9, 9, 8, 9, 8, 9, 9, 9, 10, 10 }, 7)]
public void WeekendAverage(int[] saturday, int[] sunday, double expected)
{
var actual = warmups.WeekendAverage(saturday, sunday);
Assert.AreEqual(expected, actual);
}
You can do it with System.Linq
var saturday = new[] { 1, 2, 3, 4, 5, 7, 8, 5, 10 };
var sunday = new[] { 9, 9, 9, 8, 9, 8, 9, 9, 9, 10, 10 };
var average = saturday.Concat(sunday).DefaultIfEmpty(0).Average();
Without Linq. Just calculate the sum and divide with the length of the combined array.
public double WeekendAverage(int[] saturday, int[] sunday)
{
double sum = 0;
for (int i = 0; i < saturday.Length; i++)
{
sum += saturday[i];
}
for (int i = 0; i < sunday.Length; i++)
{
sum += sunday[i];
}
return sum / (saturday.Length + sunday.Length);
}
The length of n is 2 as an array. You want an int that stores the total of the two array lengths, not an array of integers representing the lengths of your parameters.
Change that to n = saturday.length + sunday.length and i < n in your loop.
Using Linq (adapted from Theodor's answer) :
public double WeekendAverage(int[] saturday, int[] sunday)
{
double sum = saturday.Sum() + sunday.Sum();
return sum / (saturday.Length + sunday.Length);
}

How do I find duplicates in an array and display how many times they occurred?

I'm working on a code that prints out duplicated integers from an array with the number of their occurrence. I'm not allowed to use LINQ, just a simple code. I think I'm so close but confused about how to get a correct output:
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int count = 1;
for (int i = 0; i < array.Length; i++)
{
for (int j = i; j < array.Length - 1 ; j++)
{
if(array[j] == array[j+1])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + "occurse" + count);
Console.ReadKey();
}
}
}
Since you can't use LINQ, you can do this with collections and loops instead:
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
var dict = new Dictionary<int, int>();
foreach(var value in array)
{
// When the key is not found, "count" will be initialized to 0
dict.TryGetValue(value, out int count);
dict[value] = count + 1;
}
foreach(var pair in dict)
Console.WriteLine("Value {0} occurred {1} times.", pair.Key, pair.Value);
Console.ReadKey();
}
Use Group by:
int[] values = new []{1,2,3,4,5,4,4,3};
var groups = values.GroupBy(v => v);
foreach(var group in groups)
Console.WriteLine("Value {0} has {1} items", group.Key, group.Count());
Let's take a look at a simpler example. Let's say we have the array {0, 0, 0, 0}.
What will your code do?
It will first look to see how many items after the first item are equal to it. There are three items after the first that are equal to it.
Then it goes to the next item, and looks for all items after it that are equal to it. There are two. So far we're at 5, and we haven't even finished yet (we have one more to add), but there are only four items in the whole array.
Clearly we have an issue here. We need to ensure that when we've searched the array for duplicates of a given item that we don't search through it again for that same item. While there are ways of doing that, this fundamental approach is looking to be quite a lot of work.
Of course, there are different approaches entirely that we can take. Rather that going through each item and searching for others like it, we can loop through the array once, and add to a count of number of times we've found that character. The use of a Dictionary makes this easy:
var dictionary = new Dictionary<int, int>();
foreach (int n in array)
{
if (!dictionary.ContainsKey(n))
dictionary[n] = 0;
dictionary[n]++;
}
Now we can just loop through the dictionary and see which values were found more than once:
foreach(var pair in dictionary)
if(pair.Value > 1)
Console.WriteLine(pair.Key);
This makes the code clear to read, obviously correct, and (as a bonus) quite a lot more efficient than your code, as you can avoid looping through the collection multiple times.
Here is an answer that avoids using Dictionaries. Since the OP said he is not familiar with them, this might give him a little insight into what Dictionaries do.
The downside to this answer is you have to enforce a limit on the max number in the array, and you can't have negative numbers. You'd never actually use this version in real code.
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int[] count = new int[13];
foreach(int number in array) {
// using the index of count same way you'd use a key in a dictionary
count[number]++;
}
foreach(int c in count) {
int numberCount = count[c];
if(numberCount > 0) {
Console.WriteLine(c + " occurs " + numberCount + " times");
}
}
int[] arr = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
var result = arr.GroupBy(x => x).Select(x => new { key = x.Key, val = x.Count() });
foreach (var item in result)
{
if(item.val > 1)
{
Console.WriteLine("Duplicate value : {0}", item.key);
Console.WriteLine("MaxCount : {0}", item.val);
}
}
Console.ReadLine();
Ok I have modified your code. This should do the job:
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
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 = count + 1;
}
Console.WriteLine("\t\n " + array[i] + " occurs " + count + " times");
}
Console.ReadKey();
}
}
/This is the answer that helps you to find the duplicate integer values using Forloop and it will return only the repeated values apart from its times of occurences/
public static void Main(string[] args)
{
//Array list to store all the duplicate values
int[] ary = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
ArrayList dup = new ArrayList();
for (int i = 0; i < ary.Length; i++)
{
for (int j = i + 1; j < ary.Length; j++)
{
if (ary[i].Equals(ary[j]))
{
if (!dup.Contains(ary[i]))
{
dup.Add(ary[i]);
}
}
}
}
Console.WriteLine("The numbers which duplicates are");
DisplayArray(dup);
}
public static void DisplayArray(ArrayList ary)
{
//loop through all the elements
for (int i = 0; i < ary.Count; i++)
{
Console.Write(ary[i] + " ");
}
Console.WriteLine();
Console.ReadKey();
}
public static void FindRepeating(int[] input)
{
for (var i = 0; i < input.Length; i++)
{
var abs = Math.Abs(input[i]);
if (input[abs] >= 0)
input[abs] = -input[abs];
else
Console.Write(abs + " ");
}
}
You made a minor mistake of using J instead of i ...
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int count = 1;
for (int i = 0; i < array.Length; i++)
{
for (int j = i; j < array.Length - 1 ; j++)
{
if(array[i] == array[j+1])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + "occurse" + count);
Console.ReadKey();
}
}
}
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 7, 7, 8, 9, 7, 12, 12 };
Dictionary<int, int> duplicateNumbers = new Dictionary<int, int>();
int count=1;
for (int i = 0; i < array.Length; i++)
{
count=1;
if(!duplicateNumbers.ContainsKey(array[i]))
{
for (int j = i; j < array.Length-1; j++)
{
if (array[i] == array[j+1])
{
count++;
}
}
if (count > 1)
{
duplicateNumbers.Add(array[i], count);
}
}
}
foreach (var num in duplicateNumbers)
{
Console.WriteLine("Duplicate numbers, NUMBER-{0}, OCCURRENCE- {1}",num.Key,num.Value);
}
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
/// <summary>
/// How do you find the duplicate number on a given integer array?
/// </summary>
class Program
{
static void Main(string[] args)
{
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
Dictionary<int, int> duplicates = FindDuplicate(array);
Display(duplicates);
Console.ReadLine();
}
private static Dictionary<T, int> FindDuplicate<T>(IEnumerable<T> source)
{
HashSet<T> set = new HashSet<T>();
Dictionary<T, int> duplicates = new Dictionary<T, int>();
foreach (var item in source)
{
if (!set.Add(item))
{
if (duplicates.ContainsKey(item))
{
duplicates[item]++;
}
else
{
duplicates.Add(item, 2);
}
}
}
return duplicates;
}
private static void Display(Dictionary<int, int> duplicates)
{
foreach (var item in duplicates)
{
Console.WriteLine($"{item.Key}:{item.Value}");
}
}
}
}
int[] arr = { 1, 2, 3, 2, 4, 5, 2, 4 };
var duplicates = arr.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Item = y.Key, Count = y.Count() })
.ToList();
Console.WriteLine(String.Join("\n", duplicates));
This approach, fixed up, will give the correct output (it's highly inefficient, but that's not a problem unless you're scaling up dramatically.)
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
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 = count + 1;
}
Console.WriteLine("\t\n " + array[i] + " occurs " + count);
Console.ReadKey();
}
I counted 5 errors in the OP code, noted below.
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
int count = 1; // 1. have to put "count" in the inner loop so it gets reset
// 2. have to start count at 0
for (int i = 0; i < array.Length; i++)
{
for (int j = i; j < array.Length - 1 ; j++) // 3. have to cover the entire loop
// for (int j=0 ; j<array.Length ; j++)
{
if(array[j] == array[j+1]) // 4. compare outer to inner loop values
// if (array[i] == array[j])
count = count + 1;
}
Console.WriteLine("\t\n " + array[i] + "occurse" + count);
// 5. It's spelled "occurs" :)
Console.ReadKey();
}
Edit
For a better approach, use a Dictionary to keep track of the counts. This allows you to loop through the array just once, and doesn't print duplicate counts to the console.
var counts = new Dictionary<int, int>();
int[] array = { 10, 5, 10, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 11, 12, 12 };
for (int i = 0; i < array.Length; i++)
{
int currentVal = array[i];
if (counts.ContainsKey(currentVal))
counts[currentVal]++;
else
counts[currentVal] = 1;
}
foreach (var kvp in counts)
Console.WriteLine("\t\n " + kvp.Key + " occurs " + kvp.Value);
class Program
{
static void Main(string[] args)
{
int[] arr = { 2, 3, 2, 4, 5, 12, 2, 3, 3, 3, 12 };
List<int> nums = new List<int>();
List<int> count = new List<int>();
nums.Add(arr[0]);
count.Add(1);
for (int i = 1; i < arr.Length; i++)
{
if(nums.Contains(arr[i]))
{
count[nums.IndexOf(arr[i])] += 1;
}
else
{
nums.Add(arr[i]);
count.Add(1);
}
}
for(int x =0; x<nums.Count;x++)
{
Console.WriteLine("number:"+nums[x] +"Count :"+ count[x]);
}
Console.Read();
}
}

Categories