Last active
April 26, 2020 15:41
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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