It is a leet code contest question which I am trying to attempt after contest is over but my code always exceeds time limit.
Question is
Given four lists A, B, C, D of integer values, compute how many tuples
(i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.
To make problem a bit easier, all A, B, C, D
have same length of N where 0 ≤ N ≤ 500.
All integers are in the range of -228 to 228 - 1
and the result is guaranteed to be at most 231 - 1.
Example:
Input:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
Output:
2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
My code is
public static int FourSumCount(int[] A, int[] B, int[] C, int[] D)
{
int count = 0;
List<int> map1 = new List<int>();
List<int> map2 = new List<int>();
for (int i = 0; i < A.Length; i++)
for (int y = 0; y < B.Length; y++)
{
map1.Add(A[i] + B[y]);
map2.Add(C[i] + D[y]);
}
for (int i = 0; i < map2.Count(); i++)
{
for (int j = 0; j < map2.Count(); j++)
//if (map1.Contains(map2[i]*-1))
//{
// var newList = map1.FindAll(s => s.Equals(map2[i] * -1));
// count = count + newList.Count();
//}
if (map1[i] + map2[j] == 0)
{
count++;
}
}
return count;
}
is there any better way? Thanks in anticipation.
I suggest kind of meet in the middle algorithm:
A[i] + B[j] + C[k] + D[l] = 0
actually means to find out A[i] + B[j] and C[k] + D[l] such that
(A[i] + B[j]) == (-C[k] - D[l])
We can put all possible A[i] + B[j] sums into a dictionary and then, in the loop over -C[k] - D[l], try to look up in this dictionary. You can implement it like this:
private static int FourSumCount(int[] A, int[] B, int[] C, int[] D) {
// left part: all A[i] + B[j] combinations
Dictionary<int, int> left = new Dictionary<int, int>();
// loop over A[i] + B[j] combinations
foreach (var a in A)
foreach (var b in B) {
int k = a + b;
int v;
if (left.TryGetValue(k, out v))
left[k] = v + 1; // we have such a combination (v of them)
else
left.Add(k, 1); // we don't have such a combination
}
int result = 0;
// loop over -C[k] - D[l] combinations
foreach (var c in C)
foreach (var d in D) {
int v;
if (left.TryGetValue(-c - d, out v))
result += v;
}
return result;
}
As you can see, we have O(|A| * |B| + |C| * |D|) complexity; in case A, B, C and D arrays have the approximately equal sizes N the complexity is O(N**2).
Your first step is okay. But use Dictionary instead of List which will ensure constant time lookup and reduce the complexity of second part.
This was my C++ O(n^2) solution:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
int n = A.size();
int result = 0;
unordered_map<int,int> sumMap1;
unordered_map<int,int> sumMap2;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
int sum1 = A[i] + B[j];
int sum2 = C[i] + D[j];
sumMap1[sum1]++;
sumMap2[sum2]++;
}
}
for(auto num1 : sumMap1) {
int number = num1.first;
if(sumMap2.find(-1 * number) != sumMap2.end()) {
result += num1.second * sumMap2[-1 * number];
}
}
return result;
}
The core observation is - if W + X + Y + Z = 0 then W + X = -(Y + Z).
Here I used two hash-tables for each of possible sums in both (A, B) and (C, D) find number of occurrences of this sum.
Then, for each sum(A, B) we can find if sum(C, D) contains complimentary sum which will ensure sum(A, B) + sum(C, D) = 0. Add (the number of occurrences of sum(a, b)) * (number of occurrences of complimentary sum(c,d)) to the result.
Creating sum(A, B) and sum(C, D) will take O(n^2) time. And counting the number of tuples is O(n^2) as there are n^2 sum for each pairs(A-B, C-D). Other operation like insertion and search on hashtable is amortized O(1). So, the overall time complexity is O(n^2).
Related
I've got a programing problem.
I've been trying to do something like a probability calculator in c#, for that I need a certain type of factorial. I know how to program factorial, but I need
sum of all the factorials from zero to some given number.
Suppose the input number is some constant r, what I want is:
0! + 1! +2! + ... + (r-1)! + r!
This is what I've got so far, but still does not work:
double a, j, k = 1, sum = 1, l = 1;
for (a = 1; a <= f; a ++)
{
for (j = 1; j <= a; j++)
{
l = k * j;
}
sum = sum + l;
}
Console.WriteLine(sum);
One simple for loop is enough. Since factorial grows fast, let's use BigInteger type;
however, if you want, you can change all BigInteger into double:
using System.Numerics;
...
// 0! + 1! + 2! + ... + value!
public static BigInteger MyFunc(int value) {
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value));
BigInteger result = 1;
BigInteger factorial = 1;
for (int i = 1; i <= value; ++i)
result += (factorial *= i);
return result;
}
Demo:
using System.Linq;
...
int[] tests = new int[] {
0, 1, 2, 3, 4, 5, 6, 7
};
string report = string.Join(Environment.NewLine,
tests.Select(x => $"{x} => {MyFunc(x),4}"));
Console.WriteLine(report);
Outcome:
0 => 1
1 => 2
2 => 4
3 => 10
4 => 34
5 => 154
6 => 874
7 => 5914
My codes are like below.
I just want to try to convert number to binary and summarize binary numbers as if they are decimal ones, e.g. the desired outcome for 3 is 22:
1 -> 1
2 -> 10
3 -> 11
-------
22 == 1 + 10 + 11
But number array is growing and the code blowing :)
static void Main(string[] args)
{
long deger = 1;
for (int i = 0; i < 1000000; i++)
{
deger *= (deger + 1);
int result = solve(deger);
Console.WriteLine(result);
}
}
public static int solve(long a)
{
ulong[] lastValue = new ulong[a];
for (int i = 1; i < a; i++)
{
var binary = Convert.ToString(i, 2);
lastValue[i] = Convert.ToUInt64(binary);// this part gives an error
}
var result = lastValue.Aggregate((t, c) => t + c);
return (int)result;
}
Well, UInt64 is not large enough; you can try either BigInteger or you may sum up strings:
private string MyBinarySum(string left, string right) {
var x = left
.PadLeft(Math.Max(left.Length, right.Length) + 1, '0')
.Reverse()
.Select(c => c - '0')
.ToArray();
var y = right
.PadLeft(Math.Max(left.Length, right.Length) + 1, '0')
.Reverse().Select(c => c - '0')
.ToArray();
StringBuilder sb = new StringBuilder(left.Length);
int shift = 0;
for (int i = 0; i < x.Length; ++i) {
int v = x[i] + y[i] + shift;
shift = v / 2;
v = v % 2;
sb.Append((char)('0' + v));
}
return String.Concat(sb.ToString().TrimEnd('0').Reverse());
}
Then, with a help of Linq
var result = Enumerable
.Range(0, 1000000)
.Select(item => Convert.ToString(item, 2))
.Aggregate((sum, item) => MyBinarySum(sum, item));
Console.Write(result);
Outcome:
111010001101010010010101110011011100000
which is beyond UInt64.MaxValue == 18446744073709551615
Look at UInt64.MaxValue and UInt64.MinValue.
They defined as 18446744073709551615 and 0 corresponding.
I have some MATLAB code that filters an input signal using filter:
CUTOFF = 0.05;
FS = 5000;
[b, a] = butter(1, CUTOFF / (FS / 2), 'high');
% b = [0.99996859, -0.99996859]
% a = [1.0, -0.99993717]
dataAfter = filter(b, a, dataBefore);
I'm trying to convert this code to C#. I have already got the butter function to work pretty fast, but now I'm stuck converting the filter function.
I have read the MATLAB filter documentation and Python Scipy.signal filter documentation, but there is a term present in the transfer function definition that I don't understand.
Here is the "rational transfer function" definition from the linked documentation:
b[0] + b[1]z^(-1) + ... + b[M]z^(-M)
Y(z) = _______________________________________ X(z)
a[0] + a[1]z^(-1) + ... + a[N]z^(-N)
Correct me if i'm wrong, but z is the current element of input data, and Y(z) is the output?
If the above this is true, what is X(z) in this equation?
I want to understand this to implement it in C#, if there is an equivalent option then please enlighten me.
In the More About section of the matlab docs as you pointed out, they describe:
The input-output description of the filter operation on a vector in the Z-transform domain is a rational transfer function. A rational transfer function is of the form,
b[0] + b[1]z^(-1) + ... + b[M]z^(-M)
Y(z) = _______________________________________ X(z)
a[0] + a[1]z^(-1) + ... + a[N]z^(-N)
Rearranging:
Y(z) b[0] + b[1]z^(-1) + ... + b[M]z^(-M)
H(z) = ____ = _______________________________________
X(z) a[0] + a[1]z^(-1) + ... + a[N]z^(-N)
Thus, X(z) is the z-domain transform of the input vector x (seeDigital Filter). It is important to mention that, also in the docs they give an alternate representation of the transfer function as a difference equation
Which lends itself better to be ported into code. One possible implementation in C#, could be (using this answer as reference)
public static double[] Filter(double[] b, double[] a, double[] x)
{
// normalize if a[0] != 1.0. TODO: check if a[0] == 0
if(a[0] != 1.0)
{
a = a.Select(el => el / a[0]).ToArray();
b = b.Select(el => el / a[0]).ToArray();
}
double[] result = new double[x.Length];
result[0] = b[0] * x[0];
for (int i = 1; i < x.Length; i++)
{
result[i] = 0.0;
int j = 0;
if ((i < b.Length) && (j < x.Length))
{
result[i] += (b[i] * x[j]);
}
while(++j <= i)
{
int k = i - j;
if ((k < b.Length) && (j < x.Length))
{
result[i] += b[k] * x[j];
}
if ((k < x.Length) && (j < a.Length))
{
result[i] -= a[j] * result[k];
}
}
}
return result;
}
Driver:
static void Main(string[] args)
{
double[] dataBefore = { 1, 2, 3, 4 };
double[] b = { 0.99996859, -0.99996859 };
double[] a = { 1.0, -0.99993717 };
var dataAfter = Filter(b1, a, dataBefore);
}
Output
Matlab dataAfter = [0.99996859 1.999874351973491 2.999717289867956 3.999497407630634]
CSharp dataAfter = [0.99996859 1.9998743519734905 2.9997172898679563 3.999497407630634]
UPDATE
If the coefficient vectors a and b have a fixed length of 2 the filtering function can be simplified to:
public static double[] Filter(double[] b, double[] a, double[] x)
{
// normalize if a[0] != 1.0. TODO: check if a[0] == 0
if (a[0] != 1.0)
{
a = a.Select(el => el / a[0]).ToArray();
b = b.Select(el => el / a[0]).ToArray();
}
int length = x.Length;
double z = 0.0;
double[] y = new double[length]; // output filtered signal
double b0 = b[0];
double b1 = b[1];
double a1 = a[1];
for (int i = 0; i < length; i++)
{
y[i] = b0 * x[i] + z;
z = b1 * x[i] - a1 * y[i];
}
return y;
}
Given a large list of integers (more than 1 000 000 values) find how many ways there are of selecting two of them that add up to 0.... Is the question
What I have done is create a positive random integer list:
Random pos = new Random();
int POSNO = pos.Next(1, 1000000);
lstPOS.Items.Add(POSNO);
lblPLus.Text = lstPOS.Items.Count.ToString();
POSCount++;
And created a negative list:
Random neg = new Random();
int NEGNO = neg.Next(100000, 1000000);
lstNEG.Items.Add("-" + NEGNO);
lblNegative.Text = lstNEG.Items.Count.ToString();
NegCount++;
To do the sum checking I am using:
foreach (var item in lstPOS.Items)
{
int POSItem = Convert.ToInt32(item.ToString());
foreach (var negItem in lstNEG.Items)
{
int NEGItem = Convert.ToInt32(negItem.ToString());
int Total = POSItem - NEGItem;
if (Total == 0)
{
lstADD.Items.Add(POSItem + "-" + NEGItem + "=" + Total);
lblAddition.Text = lstADD.Items.Count.ToString();
}
}
}
I know this is not the fastest route. I have considered using an array. Do you have any suggestions?
Let's see; your array is something like this:
int[] data = new int[] {
6, -2, 3, 2, 0, 0, 5, 7, 0, -2
};
you can add up to zero in two different ways:
a + (-a) // positive + negative
0 + 0 // any two zeros
in the sample above there're five pairs:
-2 + 2 (two pairs): [1] + [3] and [3] + [9]
0 + 0 (three pairs): [4] + [5], [4] + [8] and [5] + [8]
So you have to track positive/negative pairs and zeros. The implementation
Dictionary<int, int> positives = new Dictionary<int, int>();
Dictionary<int, int> negatives = new Dictionary<int, int>();
int zeros = 0;
foreach(var item in data) {
int v;
if (item < 0)
if (negatives.TryGetValue(item, out v))
negatives[item] = negatives[item] + 1;
else
negatives[item] = 1;
else if (item > 0)
if (positives.TryGetValue(item, out v))
positives[item] = positives[item] + 1;
else
positives[item] = 1;
else
zeros += 1;
}
// zeros: binomal coefficent: (2, zeros)
int result = zeros * (zeros - 1) / 2;
// positive/negative pairs
foreach (var p in positives) {
int n;
if (negatives.TryGetValue(-p.Key, out n))
result += n * p.Value;
}
// Test (5)
Console.Write(result);
Note, that there's no sorting, and dictionaries (i.e. hash tables) are used for positives and negatives so the execution time will be linear, O(n); the dark side of the implementation is that two additional structures (i.e. additional memory) required. In your case (millions integers only - Megabytes) you have that memory.
Edit: terser, but less readable Linq solution:
var dict = data
.GroupBy(item => item)
.ToDictionary(chunk => chunk.Key, chunk => chunk.Count());
int result = dict.ContainsKey(0) ? dict[0] * (dict[0] - 1) / 2 : 0;
result += dict
.Sum(pair => pair.Key > 0 && dict.ContainsKey(-pair.Key) ? pair.Value * dict[-pair.Key] : 0);
Fastest way without sorting!.
First of all you know that the sum of two integers are only 0 when they have equal absolute value but one is negative and the other is positive. So you dont need to sort. what you need is to Intersect positive list with negative list (by comparing absolute value). the result is numbers that ended up 0 sum.
Intersect has time complexity of O(n+m) where n is size of first list and m is size of second one.
private static void Main(string[] args)
{
Random random = new Random();
int[] positive = Enumerable.Range(0, 1000000).Select(n => random.Next(1, 1000000)).ToArray();
int[] negative = Enumerable.Range(0, 1000000).Select(n => random.Next(-1000000, -1)).ToArray();
var zeroSum = positive.Intersect(negative, new AbsoluteEqual());
foreach (var i in zeroSum)
{
Console.WriteLine("{0} - {1} = 0", i, i);
}
}
You also need to use this IEqualityComparer.
public class AbsoluteEqual : IEqualityComparer<int>
{
public bool Equals(int x, int y)
{
return (x < 0 ? -x : x) == (y < 0 ? -y : y);
}
public int GetHashCode(int obj)
{
return obj < 0 ? (-obj).GetHashCode() : obj.GetHashCode();
}
}
You tried to avoid check two numbers that are close (1, 2 are close, 3, 4 are close), but you didn't avoid check like (-100000, 1), (-1, 100000). Time complexity is O(n^2).
To avoid that you need to sort them first, then search from two direction.
var random = new Random();
var input = Enumerable.Range(1, 100).Select(_ => random.Next(200) - 100).ToArray();
Array.Sort(input); // This causes most computation. Time Complexity is O(n*log(n));
var expectedSum = 0;
var i = 0;
var j = input.Length - 1;
while (i < j) // This has liner time complexity O(n);
{
var result = input[i] + input[j];
if(expectedSum == result)
{
var anchori = i;
while (i < input.Length && input[i] == input[anchori] )
{
i++;
}
var anchorj = j;
while (j >= 0 && input[j] == input[anchorj])
{
j--;
}
// Exclude (self, self) combination
Func<int, int, int> combination = (n, k) =>
{
var mink = k * 2 < n ? k : n - k;
return mink == 0 ? 1
: Enumerable.Range(0, mink).Aggregate(1, (x, y) => x * (n - y))
/ Enumerable.Range(1, mink).Aggregate((x, y) => x * y);
};
var c = i < j ? (i - anchori) * (anchorj - j) : combination(i - anchori, 2);
for (int _ = 0; _ < c; _++)
{
// C# 6.0 String.Format
Console.WriteLine($"{input[anchori]}, {input[anchorj]}");
}
}
else if(result < expectedSum) {
i++;
}
else if(result > expectedSum) {
j--;
}
}
Here is another solution using (huh) LINQ. Hope the code is self explanatory
First some data
var random = new Random();
var data = new int[1000000];
for (int i = 0; i < data.Length; i++) data[i] = random.Next(-100000, 100000);
And now the solution
var result = data
.Where(value => value != int.MinValue)
.GroupBy(value => Math.Abs(value), (key, values) =>
{
if (key == 0)
{
var zeroCount = values.Count();
return zeroCount * (zeroCount - 1) / 2;
}
else
{
int positiveCount = 0, negativeCount = 0;
foreach (var value in values)
if (value > 0) positiveCount++; else negativeCount++;
return positiveCount * negativeCount;
}
})
.Sum();
Theoretically the above should have O(N) time and O(M) space complexity, where M is the count of the unique absolute values in the list.
How do I exclude and count values which are bigger than 4095 from this array:
EDIT: so this is the final code I have, it basically works on some mousepoints, however there are some exceptions where the difference between depth and neighbouring values are too big (see green marked box on http://s7.directupload.net/images/131007/uitb86ho.jpg). In the screenshot there is a red box, which contains 441 Pixels, and the average value of those 441 Pixels is 1198 mm, where the depth on x;y 15;463 is only about 614 mm. Have no idea where the bigger average values come from, since it should have been excluded with the if-condition (d < 4095).
protected void imageIR_MouseClick(object sender, System.Windows.Input.MouseEventArgs e)
{
// Get the x and y coordinates of the mouse pointer.
System.Windows.Point mousePoint = e.GetPosition(imageIR);
double xpos_IR = mousePoint.X;
double ypos_IR = mousePoint.Y;
int x = (int)xpos_IR;
int y = (int)ypos_IR;
lbCoord.Content = "x- & y- Koordinate [pixel]: " + x + " ; " + y;
int d = (ushort)pixelData[x + y * this.depthFrame.Width];
d = d >> 3;
int xpos_Content = (int)((x - 320) * 0.03501 / 2 * d/10);
int ypos_Content = (int)((240 - y) * 0.03501 / 2 * d/10);
xpos.Content = "x- Koordinate [mm]: " + xpos_Content;
ypos.Content = "y- Koordinate [mm]: " + ypos_Content;
zpos.Content = "z- Koordinate [mm]: " + (d);
// Calculate the average value of array element
int sum = 0;
int i;
i = Convert.ToInt32(gr_ordnung.Text);
i = int.Parse(gr_ordnung.Text);
int m;
int n;
int d_mw = 0;
int count = 0;
for (m = x - i; m <= x + i; m++)
{
for (n = y - i; n <= y + i; n++)
{
int d_array = (ushort)pixelData[m + n * this.depthFrame.Width];
d_array = d_array >> 3;
// With condition that if one of those values is more than 4095:
if (d_array <= 4095)
{
sum += d_array;
count++;
d_mw = sum / count;
}
tiefen_mw.Content = "Tiefen-MW [mm]: " + d_mw;
}
}
}
So, the 'if' condition means if I have d_array (in my case 100 Pixels) from m = x-i to m = x+i and n = y-i to n = y+i which is less than 4095 then just do the 'normal' calculation where the average is the sum of all values divided by the number of total elements.
Now the 'else' condition means: if I have d_array value which is more than 4095, then it should be declared as 0 and it doesn't count in the average. Did I write the Syntax correctly?
You could use LinQ to do this quite easily:
using System.Linq;
...
int[] values = new int[10];
// Fill array
...
int[] usefulValues = values.Where(i => i <= 4095).ToArray();
int numberOfUselessValues = values.Length - usefulValues.Length;
UPDATE >>>
Try this instead:
int count_useful = 0; // <<< Important to initialise this here
for (m = x - i; m <= x + i; m++)
{
for (n = y - i; n <= y + i; n++)
{
int d_array = (ushort)pixelData[m + n * this.depthFrame.Width];
d_array = d_array >> 3;
if (d_array <= 4095)
{
sum += d_array;
count_useful++;
}
}
}
d_mw = sum / count_useful; // <<< Perform these sums outside of the loop
tiefen_mw.Content = "Tiefen-MW [mm]: " + d_mw;
Just check before you do anything:
int d_array = (ushort)pixelData[m + n * this.depthFrame.Width];
d_array = d_array >> 3;
if (d_array > 4095) continue; // <-- this
Without knowing more.. its hard to give you a nicer answer.