Skip to content

Instantly share code, notes, and snippets.

@kunitsyn
Last active April 26, 2020 15:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kunitsyn/07df2be1c4da8e2a2b6d08fc151d02c3 to your computer and use it in GitHub Desktop.
Save kunitsyn/07df2be1c4da8e2a2b6d08fc151d02c3 to your computer and use it in GitHub Desktop.
Calculating "What is the value on the given index of array which is a sorted result of merging two given sorted arrays?" in O(log n) with O(1) memory
using System;
using System.Diagnostics;
using System.Linq;
namespace BinarySearchOlymp
{
class Program
{
private static int? FindValueByIndex(int[] array1, int[] array2, int index)
{
if (index < 0 || index >= array1.Length + array2.Length)
{
return null;
}
int minCount1 = Math.Max(0, index - array2.Length);
int maxCount1 = Math.Min(index, array1.Length);
while (minCount1 <= maxCount1)
{
int testIndex1 = (minCount1 + maxCount1) / 2;
int testIndex2 = index - testIndex1;
if (e(array1, testIndex1) > e(array2, testIndex2))
{
if (e(array1, testIndex1 - 1) <= e(array2, testIndex2))
{
return e(array2, testIndex2);
}
else
{
maxCount1 = testIndex1 - 1;
}
}
else
{
if (e(array1, testIndex1) >= e(array2, testIndex2 - 1))
{
return e(array1, testIndex1);
}
else
{
minCount1 = testIndex1 + 1;
}
}
}
return Math.Min(e(array1, minCount1), e(array2, index - minCount1));
}
private static int e(int[] array, int index)
{
return index < 0 ? int.MinValue : (index >= array.Length ? int.MaxValue : array[index]);
}
static void Main(string[] args)
{
Test(
new int[] { 0, 0, 1, 3, 4, 4, 7, 7, 10, 10, 11, 11, 11, 12, 13, 16, 16 },
new int[] { 2, 2, 2, 4, 5, 5, 6, 7, 8, 9, 9, 10, 10, 10, 11, 13, 13, 15, 16, 16, 17, 17, 18, 18, 18, 18, 20, 20, 20, 21, 21, 22, 24, 26, 26, 27, 29, 32, 33, 35, 36, 42, 42 },
35);
Test(
new int[] { 1, 3, 4, 5, 5, 6, 8, 9, 9, 10, 11, 11 },
new int[] { 1, 1 },
4);
Test(
new int[] { 0, 1, 1, 1, 1, 3, 3, 7 },
new int[] { 0, 0, 1, 1, 1, 4, 4, 7, 9, 10, 10, 12, 13, 16, 16, 16, 17, 19, 19, 20, 20, 20, 23, 23, 25, 25, 25, 26, 28, 28, 28, 29, 29, 30, 33, 33, 35, 35, 35, 37, 38 },
13);
Test(
new int[] { 1, 1 },
new int[] { 2, 2, 3, 4, 6, 6, 7, 7, 8 },
0);
Test(
new int[] { 0 },
new int[] { 0, 0, 1, 2, 2, 5 },
6);
Test(
new int[] { 0, 1, 3, 3, 4, 5, 6 },
new int[] { 1, 1, 2, 2, 3, 3, 4, 6 },
12);
Test(
new int[] { 18, 19, 19, 19, 19, 20 },
new int[] { 15, 16, 17, 19, 19, 19 },
3);
Test(
new int[] { 0, 0, 1, 1, 1, 1, 3, 3, 5, 10, 10, 11, 16, 16, 17, 18, 19, 19, 19, 19, 20 },
new int[] { 3, 3, 3, 5, 5, 5, 5, 7, 7, 8, 8, 10, 11, 13, 13, 15, 16, 17, 19, 19, 19 },
33);
Test(
new int[] { 0, 2, 2, 2, 3, 4 },
new int[] { 0, 1, 2, 2, 3, 4, 5, 6, 6, 8 },
2);
Test(
new int[] { 0, 0, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 12, 12, 13, 15, 15, 16, 16, 18, 18, 18, 21, 21, 24, 25 },
new int[] { 0, 2, 2, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 13, 14, 14, 14, 14, 19, 20, 20 },
34);
var r = new Random();
for (int i = 0; i < 200; i++)
{
int length1 = r.Next(5);
int length2 = r.Next(5);
if (length1 == 0 && length2 == 0)
{
length1 = 1;
}
int[] array1 = Enumerable.Range(1, length1 * 10).Select(x => r.Next(100)).OrderBy(x => x).ToArray();
int[] array2 = Enumerable.Range(1, length2 * 10).Select(x => r.Next(100)).OrderBy(x => x).ToArray();
int index = r.Next(length1 + length2);
Test(array1, array2, index);
}
}
private static void Test(int[] array1, int[] array2, int index)
{
int truth = FindValueByIndexGroundTruth(array1, array2, index);
int test = (int)FindValueByIndex(array1, array2, index);
int minTruthIndex1 = array1.Where(x => x < truth).Count();
int maxTruthIndex1 = (array1.Where(x => x <= truth).Count() - (array2.Where(x => x == truth).Count() > 0 ? 0 : 1));
bool truthIn1 = array1.Where(x => x == truth).Count() > 0;
bool truthIn2 = array2.Where(x => x == truth).Count() > 0;
if (truth != test)
{
Debug.WriteLine("incorrect");
Debug.WriteLine("array1 = " + p(array1) + " array2 = " + p(array2) + " index = " + index + " truth = " + truth + " test = " + test +
" index1 min = " + minTruthIndex1 + " index1 max = " + maxTruthIndex1 + (truthIn1 ? ", in 1" : "") + (truthIn2 ? ", in 2" : ""));
}
}
private static int FindValueByIndexGroundTruth(int[] array1, int[] array2, int index)
{
return array1.Concat(array2).OrderBy(x => x).ElementAt(index);
}
private static string p(int[] array)
{
return string.Join(", ", array);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment