using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace FindNumbers
{
class Program
{
static void Main(string[] args)
{
var input = new List<int>();
for (int i = 0; i < 7000; ++i )
{
input.
Add(rand.
Next(100)); }
Console.WriteLine("====== Standard =============================================================");
var sw = new Stopwatch();
sw.Start();
List<int> r1 = null;
for (int i = 0; i < 10; ++i)
{
r1 = NumberFinder.FindNumbersStandard(input);
}
sw.Stop();
Console.WriteLine("Elapsed: {0}ms", sw.ElapsedMilliseconds);
Console.WriteLine("====== Fast =================================================================");
var sw2 = new Stopwatch();
sw2.Start();
List<int> r2 = null;
for (int i = 0; i < 10; ++i)
{
r2 = NumberFinder.FindNumbersFast(input);
}
sw2.Stop();
Console.WriteLine("Elapsed: {0}ms", sw2.ElapsedMilliseconds);
if (r1.Count != r2.Count)
{
Console.WriteLine("BUG - different number of results");
}
for (int i = 0; i < r1.Count; ++i)
{
if (r1[i] != r2[i])
{
Console.WriteLine("BUG - count mismatch");
break;
}
}
}
}
public class NumberFinder
{
public static List<int> FindNumbersStandard(List<int> input)
{
var res = new List<int>(input.Count * 2);
for (int i = 0; i < input.Count; ++i)
{
int current = input[i];
int numElementsLargerToTheRight = 0;
int numElementsSmallerToTheLeft = 0;
for (int j = i + 1; j < input.Count; ++j)
{
if (input[j] > current) numElementsLargerToTheRight++;
}
for (int j = i - 1; j >= 0; --j)
{
if (input[j] < current) numElementsSmallerToTheLeft++;
}
res.Add(numElementsSmallerToTheLeft);
res.Add(numElementsLargerToTheRight);
//Console.WriteLine("input[{0}] = {1}, {2} smaller elements to the left, {3} larger elements to the right", i, current, numElementsSmallerToTheLeft, numElementsLargerToTheRight);
}
return res;
}
public static List<int> FindNumbersFast(List<int> input)
{
var res = new List<int>(input.Count * 2);
var keyIndexMap = new Dictionary<int, List<int>>();
int maxKey = -1;
// find the list of all indices for each element in the array
for (int i = 0; i < input.Count; ++i)
{
var current = input[i];
maxKey = current > maxKey ? current : maxKey;
List<int> indices;
if (!keyIndexMap.TryGetValue(current, out indices))
{
indices = new List<int>();
keyIndexMap[current] = indices;
}
indices.OrderedInsert(i);
}
for (int i = 0; i < input.Count; ++i)
{
var current = input[i];
int numElementsLargerToTheRight = 0;
int numElementsSmallerToTheLeft = 0;
for (int k = current + 1; k <= maxKey; ++k)
{
List<int> indices;
if (!keyIndexMap.TryGetValue(k, out indices))
continue;
int firstIndexBiggerThanCurrent = indices.FindPosition(i);
numElementsLargerToTheRight += indices.Count - firstIndexBiggerThanCurrent;
}
for (int k = current - 1; k >= 0; --k)
{
List<int> indices;
if (!keyIndexMap.TryGetValue(k, out indices))
continue;
int lastIndexSmallerThanCurrent = indices.FindPosition(i);
numElementsSmallerToTheLeft += lastIndexSmallerThanCurrent;
}
res.Add(numElementsSmallerToTheLeft);
res.Add(numElementsLargerToTheRight);
//Console.WriteLine("input[{0}] = {1}, {2} smaller elements to the left, {3} larger elements to the right", i, current, numElementsSmallerToTheLeft, numElementsLargerToTheRight);
}
return res;
}
}
public static class OrderedExtensions
{
public static void OrderedInsert(this List<int> @this, int item)
{
var index = @this.BinarySearch(item);
if (index < 0) index = ~index;
@this.Insert(index, item);
}
// item should not be in the list as item is the index of current,
// the binary search will return the first index which is bigger than item which is what we are after
public static int FindPosition(this List<int> @this, int item)
{
var index = @this.BinarySearch(item);
System.Diagnostics.Debug.Assert(index < 0, "broken");
return ~index;
}
}
}