<file_sep>﻿using System;
using System.Collections.Generic;
using System.IO;

namespace array_manipulation
{
    public class ArrayManipulationFixture
    {
        public ArrayManipulationFixture()
        {
            TestCases = new Dictionary<string, TestData>();

            LoadTestCase("testCase1");
            LoadTestCase("testCase4");
            LoadTestCase("testCase7");
        }

        internal IDictionary<string, TestData> TestCases { get; }

        void LoadTestCase(string testCaseName)
        {
            if (TestCases.ContainsKey(testCaseName)) return;

            var testCaseData = new TestData();
            var filename = $"{testCaseName}.txt";

            using (var file = File.OpenText(filename))
            {
                string[] nm = file.ReadLine().Split(' ');
                int n = Convert.ToInt32(nm[0]);
                int m = Convert.ToInt32(nm[1]);

                int[][] queries = new int[m][];

                for (int i = 0; i < m; i++)
                {
                    queries[i] = Array.ConvertAll(file.ReadLine().Split(' '), queriesTemp => Convert.ToInt32(queriesTemp));
                }

                testCaseData.ArraySize = n;
                testCaseData.Queries = queries;
            }

            TestCases.Add(testCaseName, testCaseData);
        }

    }
}<file_sep>﻿using System;

namespace Problems.MergeLists
{
    public class MyQueue
    {
        private const string ERR_QUEUE_EMPTY = "Queue is empty.";
        private readonly SinglyLinkedList innerList = new SinglyLinkedList();

        public bool IsEmpty => innerList.Count == 0;

        public void Enqueue(int data)
        {
            innerList.Append(data);
        }

        public int Dequeue()
        {
            var item = innerList.RemoveFirst();

            if (item is null)
                throw new InvalidOperationException(ERR_QUEUE_EMPTY);

            return item.Data;
        }

        public int Peek()
        {
            var item = innerList.Head;

            if (item is null)
                throw new InvalidOperationException(ERR_QUEUE_EMPTY);

            return item.Data;
        }
    }
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using FluentAssertions;
using System.IO;

namespace Problems.MergeLists
{
    public class SingleLinkedListTests
    {
        private readonly SinglyLinkedList linkedList;

        public SingleLinkedListTests()
        {
            linkedList = new SinglyLinkedList();
        }

        [Fact(DisplayName = "New_Linked_List_Is_Empty")]
        public void New_Linked_List_Is_Empty()
        {
            linkedList.Head.Should().BeNull();
            linkedList.Tail.Should().BeNull(); 
            linkedList.Count.Should().Be(0);
        }

        [Fact(DisplayName = "FromArray_Returns_New_Linked_List_From_Array")]
        public void FromArray_Returns_New_Linked_List_From_Array()
        {
            int[] array = { 1, 2, 3, 4 };

            var actual = SinglyLinkedList.FromArray(array);

            actual.Should().NotBeNull();
            actual.Count.Should().Be(4);
            actual.Head.Data.Should().Be(1);
            actual.Tail.Data.Should().Be(4);
        }

        [Fact(DisplayName = "FromArray_Returns_New_Empty_Linked_List_From_Empty_Array")]
        public void FromArray_Returns_New_Empty_Linked_List_From_Empty_Array()
        {
            int[] array = { };

            var actual = SinglyLinkedList.FromArray(array);

            actual.Should().NotBeNull();
            actual.Count.Should().Be(0);
            actual.Head.Should().BeNull();
            actual.Tail.Should().BeNull();
        }

        [Fact(DisplayName = "FromArray_Throws_ArgumentNullException_When_Array_Is_Null")]
        public void FromArray_Throws_ArgumentNullException_When_Array_Is_Null()
        {
            Assert.Throws<ArgumentNullException>(() =>
            {
                SinglyLinkedList.FromArray(null);
            });
        }

        [Theory(DisplayName = "Print_Prints_List_To_Writer")]
        [InlineData(new int[] { }, " ", "[]")]
        [InlineData(new int[] { }, ",", "[]")]
        [InlineData(new int[] { 1, 2, 3 }, " ", "[1 2 3]")]
        [InlineData(new int[] { 1, 2, 3 }, ",", "[1,2,3]")]
        [InlineData(new int[] { 1 }, " ", "[1]")]
        [InlineData(new int[] { 1 }, ",", "[1]")]
        public void Print_Prints_List_To_Writer(int[] initArray, string sep, string expected)
        {
            var list = SinglyLinkedList.FromArray(initArray);

            using (var sw = new StringWriter())
            {
                list.Print(sw, sep);
                sw.ToString().Should().Be(expected);
            }
        }

        [Fact(DisplayName = "Append_Should_Insert_New_Node_At_End")]
        public void Append_Should_Insert_New_Node_At_End()
        {
            linkedList.Append(1);

            linkedList.Head.Should().NotBeNull();
            linkedList.Tail.Should().NotBeNull();
            linkedList.PreviousTail.Should().BeNull();
            linkedList.Head.Data.Should().Be(1);
            linkedList.Tail.Data.Should().Be(1);

            linkedList.Append(10);
            linkedList.Head.Data.Should().Be(1);
            linkedList.Tail.Data.Should().Be(10);
            linkedList.PreviousTail.Should().BeSameAs(linkedList.Head);
        }

        [Fact(DisplayName = "Append_Should_Increment_Count_By_One")]
        public void Append_Should_Increment_Count_By_One()
        {
            linkedList.Append(1);
            linkedList.Count.Should().Be(1);
            linkedList.Append(10);
            linkedList.Count.Should().Be(2);
        }

        [Fact(DisplayName = "Prepend_Should_Insert_New_Node_At_Beginning")]
        public void Prepend_Should_Insert_New_Node_At_Beginning()
        {
            linkedList.Prepend(1);

            linkedList.Head.Should().NotBeNull();
            linkedList.Tail.Should().NotBeNull();
            linkedList.PreviousTail.Should().BeNull();
            linkedList.Head.Data.Should().Be(1);
            linkedList.Tail.Data.Should().Be(1);

            linkedList.Prepend(10);
            linkedList.Head.Data.Should().Be(10);
            linkedList.Tail.Data.Should().Be(1);
            linkedList.PreviousTail.Should().BeSameAs(linkedList.Head);

            linkedList.Prepend(29);
            linkedList.Head.Data.Should().Be(29);
            linkedList.Tail.Data.Should().Be(1);
            linkedList.PreviousTail.Data.Should().Be(10);
        }

        [Fact(DisplayName = "Prepend_Should_Increment_Count_By_One")]
        public void Prepend_Should_Increment_Count_By_One()
        {
            linkedList.Prepend(1);
            linkedList.Count.Should().Be(1);
            linkedList.Prepend(10);
            linkedList.Count.Should().Be(2);
        }

        [Fact(DisplayName = "RemoveLast_Should_Return_And_Remove_The_Last_Node")]
        public void RemoveLast_Should_Return_And_Remove_The_Last_Node()
        {
            linkedList.Append(1);
            linkedList.Append(2);
            linkedList.Append(3);

            var actual = linkedList.RemoveLast();

            actual.Should().NotBeNull();
            actual.Data.Should().Be(3);
            linkedList.Count.Should().Be(2);
            linkedList.Head.Data.Should().Be(1);
            linkedList.Tail.Data.Should().Be(2);
            linkedList.Tail.Next.Should().BeNull();
        }

        [Fact(DisplayName = "RemoveLast_Should_Set_Head_And_Tail_The_Same_When_List_Has_Two_Nodes")]
        public void RemoveLast_Should_Set_Head_And_Tail_The_Same_When_List_Has_Two_Nodes()
        {
            linkedList.Append(1);
            linkedList.Append(2);

            var removedNode = linkedList.RemoveLast();

            removedNode.Should().NotBeNull();
            removedNode.Data.Should().Be(2);
            linkedList.Head.Should().BeSameAs(linkedList.Tail);
            linkedList.Head.Next.Should().BeNull();
        }

        [Fact(DisplayName = "RemoveLast_Should_Set_Head_And_Tail_Null_When_List_Has_Only_One_Node" )]
        public void RemoveLast_Should_Set_Head_And_Tail_Null_When_List_Has_Only_One_Node()
        {
            linkedList.Append(1);

            var removedNode = linkedList.RemoveLast();

            removedNode.Should().NotBeNull();
            removedNode.Data.Should().Be(1);
            linkedList.Head.Should().BeNull();
            linkedList.Tail.Should().BeSameAs(linkedList.Head);
        }

        [Fact(DisplayName = "RemoveLast_Should_Return_Null_When_List_Is_Empty")]
        public void RemoveLast_Should_Return_Null_When_List_Is_Empty()
        {
            var removedNode = linkedList.RemoveLast();

            removedNode.Should().BeNull();
            linkedList.Head.Should().BeNull();
            linkedList.Tail.Should().BeNull();
        }

        [Fact(DisplayName = "RemoveLast_Should_Decrement_Count_By_One")]
        public void RemoveLast_Should_Decrement_Count_By_One()
        {
            linkedList.Append(1);
            linkedList.Append(2);

            var removedNode = linkedList.RemoveLast();

            linkedList.Count.Should().Be(1);
        }

        [Fact(DisplayName = "RemoveFirst_Should_Return_And_Remove_The_First_Node")]
        public void RemoveFirst_Should_Return_And_Remove_The_First_Node()
        {
            linkedList.Append(1);
            linkedList.Append(2);
            linkedList.Append(3);

            var removedNode = linkedList.RemoveFirst();

            removedNode.Should().NotBeNull();
            removedNode.Data.Should().Be(1);
            linkedList.Head.Should().NotBeNull();
            linkedList.Head.Data.Should().Be(2);
            linkedList.Head.Should().NotBeSameAs(linkedList.Tail);
        }

        [Fact(DisplayName = "RemoveFirst_Should_Set_Head_And_Tail_The_Same_When_List_Has_Two_Nodes")]
        public void RemoveFirst_Should_Set_Head_And_Tail_The_Same_When_List_Has_Two_Nodes()
        {
            linkedList.Append(1);
            linkedList.Append(2);

            var removedNode = linkedList.RemoveFirst();

            removedNode.Should().NotBeNull();
            removedNode.Data.Should().Be(1);
            linkedList.Head.Should().BeSameAs(linkedList.Tail);
            linkedList.Head.Next.Should().BeNull();
        }

        [Fact(DisplayName = "RemoveFirst_Should_Set_Head_And_Tail_Null_When_List_Has_Only_One_Node")]
        public void RemoveFirst_Should_Set_Head_And_Tail_Null_When_List_Has_Only_One_Node()
        {
            linkedList.Append(1);

            var removedNode = linkedList.RemoveFirst();

            removedNode.Should().NotBeNull();
            removedNode.Data.Should().Be(1);
            linkedList.Head.Should().BeNull();
            linkedList.Tail.Should().BeSameAs(linkedList.Head);
        }

        [Fact(DisplayName = "RemoveFirst_Should_Return_Null_When_List_Is_Empty")]
        public void RemoveFirst_Should_Return_Null_When_List_Is_Empty()
        {
            var removedNode = linkedList.RemoveFirst();

            removedNode.Should().BeNull();
            linkedList.Head.Should().BeNull();
            linkedList.Tail.Should().BeNull();
        }

        [Fact(DisplayName = "RemoveFirst_Should_Decrement_Count_By_One")]
        public void RemoveFirst_Should_Decrement_Count_By_One()
        {
            linkedList.Append(1);
            linkedList.Append(2);

            var removedNode = linkedList.RemoveFirst();

            linkedList.Count.Should().Be(1);
        }

        [Fact(DisplayName = "Append_And_RemoveLast_Should_Set_Count_To_Zero")]
        public void Append_And_RemoveLast_Should_Set_Count_To_Zero()
        {
            linkedList.Append(1);
            linkedList.RemoveLast();

            linkedList.Count.Should().Be(0);
        }
    }
}
<file_sep>using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Arrays.SwapSum
{
    public class SwapSum
    {
        public static bool AreElegible(long[] arrayA, long[] arrayB)
        {
            var sumA = arrayA.Sum();
            var sumB = arrayB.Sum();

            // if the sum of the arrays are already equal then return true as
            // we can swap elements without altering the results.
            if(sumA == sumB) return true;
            // if the difference of the sums is odd, then no elements can be 
            // swapped to get an equal sum of both arrays.
            // The detailed explanation:
            //  The effect of swapping elements from A to B on the sum is:
            //   sumA = sumA - a + b
            //   sumB = sumB - b + a
            //  As sumA == sumB then
            //   sumA - a + b = sumB - b + a => (sumA - sumB) = 2(a - b) => (a - b) = (sumA - sumB) / 2
            //  This tells that:
            //   1. The difference between the sums of A and B must be even.
            //   2. The difference between the swapping elements is equal to the difference of the sums of A and B divided by 2.
            if((sumA - sumB) % 2 != 0) return false;

            var diff = (sumA - sumB) / 2;
            var hashSet = new HashSet<long>();
            long expectedB = 0;

            // Given that: (a - b) = (sumA - sumB) / 2
            // Solving for b: b = a - ((sumA - sumB) / 2)
            // That means we can determine the value of the element on arrayB based on the sum difference and arrayA elements.
            // Here we calculate the value of the expected B value and then store it on a hashSet (this will allow a O(1) lookup)
            for(int i = 0; i < arrayA.Length; i++) 
            {
                expectedB = arrayA[i] - diff;
                hashSet.Add(expectedB);
            }

            // For each element on arrayB, check if element exists on hashSet. If true, return true; false otherwise.
            for (int i = 0; i < arrayB.Length; i++)
            {
                if(hashSet.Contains(arrayB[i]))
                    return true;
            }

            return false;
        }
    }
}<file_sep>using System;
using Xunit;

namespace Problems.Atoi
{
    public class AtoiTests
    {
        [Theory]
        [InlineData("42", 42)]
        [InlineData("-42", -42)]
        [InlineData("+42", 42)]
        [InlineData("    42", 42)]
        [InlineData("    42 word", 42)]
        [InlineData("  00042", 42)]
        [InlineData("xx 23", 0)]
        [InlineData("00042", 42)]
        [InlineData("-00042", -42)]
        [InlineData("12345689912", Int32.MaxValue)]
        [InlineData("-12345689912", Int32.MinValue)]
        [InlineData("", 0)]
        [InlineData("  ", 0)]
        [InlineData("2147483646", 2147483646)]
        [InlineData("-2147483646", -2147483646)]
        [InlineData("2147483648", Int32.MaxValue)]
        public void MyAtoiTests(string input, int expected)
        {
            var solution = new Solution();

            int actual = solution.MyAtoi(input);

            Assert.Equal(expected, actual);
        }
    }
}<file_sep>﻿using System;
using Xunit;

namespace Problems.MyCalendar
{
    public class MyCalendarTests
    {
        private readonly MyCalendar myCalendar;

        public MyCalendarTests()
        {
            myCalendar = new MyCalendar();
        }

        [Fact]
        public void CanBookEvent_WhenFirstEvent()
        {
            var result = myCalendar.Book(10, 20);

            Assert.True(result);
        }

        [Fact]
        public void CanBookEvent_WhenEventIsPriorToExistingOne()
        {
            myCalendar.Book(10, 20);

            var result = myCalendar.Book(5, 10);

            Assert.True(result);
        }

        [Fact]
        public void CanBookEvent_WhenEventIsAfterToExistingOne()
        {
            myCalendar.Book(10, 20);

            var result = myCalendar.Book(30, 40);

            Assert.True(result);
        }

        [Fact]
        public void CannotBookEvent_WhenEventOverlapsExistingEvent()
        {
            myCalendar.Book(10, 20);
            myCalendar.Book(5, 10);
            myCalendar.Book(30, 40);

            var result = myCalendar.Book(15, 30);

            Assert.False(result);
        }
    }
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Problems.MergeLists
{
    public class MyStack
    {
        private readonly SinglyLinkedList innerList = new SinglyLinkedList();

        public void Push(int data)
        {
            innerList.Append(data);
        }

        public int Pop()
        {
            var item = innerList.RemoveLast();

            if (item is null)
            {
                throw new InvalidOperationException();
            }

            return item.Data;
        }

        public int Peek()
        {
            var item = innerList.Tail;

            if (item is null)
            {
                throw new InvalidOperationException();
            }

            return item.Data;
        }

        public bool IsEmpty => innerList.Count == 0;
    }
}
<file_sep>﻿using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace Problems.MergeLists
{
    public class SinglyLinkedListComparer : IEqualityComparer<SinglyLinkedList>
    {
        public bool Equals([AllowNull] SinglyLinkedList x, [AllowNull] SinglyLinkedList y)
        {
            return x.Equals(y);
        }

        public int GetHashCode([DisallowNull] SinglyLinkedList obj)
        {
            return obj.GetHashCode();
        }
    }
}
<file_sep>using System.Diagnostics;
using Xunit;

namespace array_manipulation
{
	public class ArrayManipulationTests : IClassFixture<ArrayManipulationFixture>
    {
        private readonly ArrayManipulationFixture _fixture;
        private readonly ArrayManipulator _target;

        public ArrayManipulationTests(ArrayManipulationFixture fixture)
        {
            _fixture = fixture;
            _target = new ArrayManipulator();
        }

        [Fact]
        public void TestCase1()
        {
            var testData = _fixture.TestCases["testCase1"];
            const int expectedMax = 200;

            var max = _target.GetMaxInArray(testData);

            Assert.Equal(expectedMax, max);
        }

        [Fact]
        public void TestCase4()
        {
            const long expectedMax = 7542539201;
            var testData = _fixture.TestCases["testCase4"];

            var max = _target.GetMaxInArray(testData);

            Assert.Equal(expectedMax, max);
        }

        [Fact]
        public void TestCase7()
        {
            const long expectedMax = 2497169732;
            var testData = _fixture.TestCases["testCase7"];

            var stopwatch = Stopwatch.StartNew();
            var max = _target.GetMaxInArray(testData);

            stopwatch.Stop();

            Assert.Equal(expectedMax, max);

        }
    }
}
<file_sep>using System;
using System.IO;
using System.Linq;
using Xunit;

namespace MigratoryBirds
{
    public class MigratoryBirdsTests
    {
        private readonly MigratoryBirds _migratoryBirds;

        public MigratoryBirdsTests() 
        {
            _migratoryBirds = new MigratoryBirds();
        }

        [Fact]
        public void TestCase4()
        {
            //Arrange
            const int expectedBirdId = 3;
            var inputArray = LoadTestCaseData("testcase4.txt");

            //Act
            var birdId = _migratoryBirds.Solve(inputArray);

            //Assert
            Assert.Equal(expectedBirdId, birdId);
        }

        private static int[] LoadTestCaseData(string filename) 
        {
            // throw new NotImplementedException();
            
            using(var file = File.OpenText(filename)) 
            {
                int arrayCount = Convert.ToInt32(file.ReadLine().Trim());

                var array = file.ReadLine().TrimEnd().Split(' ').ToList().Select(arrTemp => Convert.ToInt32(arrTemp)).ToArray();

                return array;
            }
        }
    }
}
<file_sep>﻿namespace array_manipulation
{
    class TestData
    {
        public int ArraySize { get; set; }
        public int[][] Queries { get; set; }
    }
}
<file_sep>using System;
using trees;
using Xunit;

namespace Trees
{
    public class TreeExtensionsTests
    {
        public class CheckBstTests
        {
            private Tree<int> _tree;

            public CheckBstTests()
            {
                _tree = new Tree<int>();

            }

            [Fact]
            public void ShouldReturnTrue_ForABinarySearchTree()
            {
                _tree.Insert(10);
                _tree.Insert(5);
                _tree.Insert(20);
                _tree.Insert(15);
                _tree.Insert(25);
                _tree.Insert(3);
                _tree.Insert(9);

                var isBst = _tree.CheckBst();

                Assert.True(isBst);
            }

            [Fact]
            public void ShouldReturnFalse_ForANonBinarySearchTree()
            {
                _tree.Insert(10);

                var root = _tree.Root;
                root.Left = new Node<int>(5);
                root.Left.Left = new Node<int>(30);

                _tree.Insert(20);

                var isBst = _tree.CheckBst();

                Assert.False(isBst);
            }
        }

        public class HeightTests
        {
            private readonly Tree<int> _tree;

            public HeightTests()
            {
                _tree = new Tree<int>();
            }

            [Fact]
            public void ShouldReturnZero_ForAnEmptyBst()
            {
                Assert.Equal(0, _tree.Height());
            }

            [Fact]
            public void ShouldReturnOne_ForATreeWithOnlyOneNode()
            {
                _tree.Insert(1);

                Assert.Equal(1, _tree.Height());
            }

            [Fact]
            public void ShouldReturnX_ForABstTree()
            {
                /*
                 *    (1)          10
                 *               /    \
                 *    (2)       5      20 
                 *             / \    /   \
                 *    (3)     3   9  15    25
                 */

                _tree.Insert(10);
                _tree.Insert(5);
                _tree.Insert(20);
                _tree.Insert(15);
                _tree.Insert(25);
                _tree.Insert(3);
                _tree.Insert(9);

                Assert.Equal(3, _tree.Height());
            }
        }

        public class PrintTests
        {
            private readonly Tree<int> _tree = new Tree<int>();

            [Fact]
            public void PrintTest()
            {
                _tree.Insert(10);
                _tree.Insert(5);
                _tree.Insert(20);
                _tree.Insert(15);
                _tree.Insert(25);
                _tree.Insert(3);
                _tree.Insert(9);

                _tree.Print();
            }
        }
    }
}<file_sep>﻿using System;
using System.Diagnostics.CodeAnalysis;

namespace Problems.MyCalendar
{
    public class MyCalendar
    {
        private readonly Tree tree;

        public MyCalendar()
        {
            tree = new Tree();
        }

        public bool Book(int start, int end)
        {
            var interval = new Interval(start, end);

            return tree.Add(interval);
        }

        private class Tree
        {
            private IntervalNode rootNode;

            public bool Add(Interval interval)
            {
                if (rootNode == null)
                {
                    rootNode = new IntervalNode(interval);
                    return true;
                }

                return rootNode.Add(interval);
            }

            private class IntervalNode
            {
                public IntervalNode(Interval interval)
                {
                    Data = interval ?? throw new ArgumentNullException(nameof(interval));
                }

                public Interval Data { get; }
                public IntervalNode Left { get; set; }
                public IntervalNode Right { get; set; }

                public bool Add(Interval interval)
                {
                    int comparision = Compare(Data, interval);

                    if (comparision == 0)
                    {
                        return false; // the interval overlaps this node's interval
                    } else if (comparision < 0)
                    {
                        // the interval does not overlap but happens before current event
                        // if no node at the left, then add the interval node and return true
                        // to indicate the booking was successful
                        if (Left == null)
                        {
                            Left = new IntervalNode(interval);
                            return true;
                        }

                        // otherwise keep digging on the tree to insert on the left side.
                        return Left.Add(interval);
                    } else
                    {
                        // the interval does not overlap but happens after current event
                        // if no node at the right, then add the interval node and return true
                        // to indicate the booking was successful
                        if (Right == null)
                        {
                            Right = new IntervalNode(interval);
                            return true;
                        }

                        // otherwise keep digging on the tree to insert on the right side
                        return Right.Add(interval);
                    }

                }

                private int Compare(Interval interval1, Interval interval2)
                {
                    if (interval1 is null)
                    {
                        throw new ArgumentNullException(nameof(interval1));
                    }

                    if (interval2 is null)
                    {
                        throw new ArgumentNullException(nameof(interval2));
                    }

                    if (Math.Max(interval1.Start, interval2.Start) < Math.Min(interval1.End, interval2.End))
                    {
                        return 0; // these intervals overlap each other
                    }

                    if (interval2.Start >= interval1.End)
                    {
                        return -1;
                    }

                    if (interval1.Start >= interval2.End)
                    {
                        return 1;
                    }

                    throw new InvalidOperationException();
                }
            }
        }

        private class Interval 
        {
            public Interval(int start, int end)
            {
                if (start < 0)
                    throw new ArgumentOutOfRangeException(nameof(start));
                if (end < 0)
                    throw new ArgumentOutOfRangeException(nameof(end));
                if (end < start)
                    throw new ArgumentException($"End is expected to be greater than start.");

                Start = start;
                End = end;
            }

            public int Start { get; }
            public int End { get; }
        }
    }
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace Problems.MergeLists
{
    public class MergeListsTests
    {
        [Theory]
        [InlineData(new int[] { }, new int[] { 2, 3, 4, 5, 6 }, new int[] { 2, 3, 4, 5, 6 })]
        [InlineData(new int[] { 2, 3, 4, 5, 6 }, new int[] { }, new int[] { 2, 3, 4, 5, 6 })]
        [InlineData(new int[] { }, new int[] { }, new int[] { })]
        public void Merge_Should_Handle_Empty_Lists(int[] listArray1, int[] listArray2, int[] expectedArray)
        {
            DoTest(listArray1, listArray2, expectedArray);
        }

        [Theory]
        [InlineData(new int[] { 1, 3, 5, 7 }, new int[] { 2, 4, 6, 8, 10, 12 }, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 10, 12 })]
        [InlineData(new int[] { 1, 3, 5, 7, 9, 11, 13 }, new int[] { 2, 4, 6 }, new int[] { 1, 2, 3, 4, 5, 6, 7, 9, 11, 13 })]
        public void Merge_Should_Handle_Different_List_Sizes(int[] listArray1, int[] listArray2, int[] expectedArray)
        {
            DoTest(listArray1, listArray2, expectedArray);
        }

        [Theory]
        [InlineData(new int[] { 1, 2, 3, 4, 6, 8 }, new int[] { 5, 7, 9, 10, 11, 12 }, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 })]
        public void Merge_Should_Handle_Equal_List_Sizes(int[] listArray1, int[] listArray2, int[] expectedArray)
        {
            DoTest(listArray1, listArray2, expectedArray);
        }

        private static void DoTest(int[] listArray1, int[] listArray2, int[] expectedArray)
        {
            var list1 = SinglyLinkedList.FromArray(listArray1);
            var list2 = SinglyLinkedList.FromArray(listArray2);
            var expected = SinglyLinkedList.FromArray(expectedArray);

            var actual = Solution.MergeLists(list1.Head, list2.Head);

            Assert.Equal(expected, actual, new SinglyLinkedListComparer());
        }
    }
}
<file_sep>using System;
using System.Collections;

namespace Problems.Atoi
{
    public class Solution
    {
        /* Main Questions:
        1. Can the input string contain whitespaces at both beginning or end?
            A: Yes. Ignore all whitespaces at the beginning only. Only ' ' is considered a whitespace.
        2. Can the input string contain any other non-numerical characters?
            A: Yes, you can expect non-numerical characters. But for conversion to be valid, the first sequence of chars has to be a valid integer value (ie. no words or any other char except '+' or '-')
        3. What do we expect from the function if we encounter such characters?
            A: Just ignore them. They will not affect the result.
        4. It needs to return an int. So I assume we're dealing with 32-bit integers. right?
            A: Yes.
        5. Will it always include the sign at the beginning? If not, do we assume the result will be a positive number?
            A: Yes. The sign is optional. Default will be +.
        6. What about if the number is out-of-range?
            A: You will either return INT_MAX (2^31 - 1) for positive values or INT_MIN (-2^31) for negative ones.
        7. What if the input string has no valid number (ie. string is empty or has no numbers)?
            A: No conversion is performed. Return Zero.
        */
        public int MyAtoi(string str)
        {
            // let's define INT_MAX and INT_MIN
            const int INT_MAX = Int32.MaxValue;
            const int INT_MIN = Int32.MinValue;

            if (str.Length == 0)
            {
                return 0;
            }

            int sign = 1;
            int i = 0;
            int result = 0;

            // discard as many whitespaces are found.
            while (i < str.Length && str[i] == ' ') i++;

            if (i < str.Length && (str[i] == '-' || str[i] == '+'))
            {
                sign = str[i] == '-' ? -1 : 1;
                i++;
            }
            // discard as many leading zeroes are found
            while (i < str.Length && str[i] == '0') i++;

            while (i < str.Length)
            {
                if (str[i] >= '0' && str[i] <= '9')
                {
                    if (result > (INT_MAX / 10) || (result == INT_MAX / 10 && str[i] - '0' > 7))
                    {
                        return sign == -1 ? INT_MIN : INT_MAX;
                    }
                    result = (result * 10) + str[i] - '0';
                }
                else
                {
                    break;
                }

                i++;
            }

            return result * sign;
        }

        public int MyAtoi2(string str)
        {
            return MyAtoiRecursive(str, str.Length - 1);
        }

        private int MyAtoiRecursive(string str, int i)
        {
            int sign = 0;
            
            if (str[i] == '+' || str[i] == '-')
            {
                sign = str[i] == '-' ? -1 : 1;
                return (str[i + 1] - '0');
            }
            if (i == 0)
                return 0;

            if (IsDigit(str[i]))
            {
                int result = (10 * MyAtoiRecursive(str, i - 1) + str[i] - '0');
                return result * sign;
            }
            
            return MyAtoiRecursive(str, i - 1);
            

            //int result = (10 * MyAtoiRecursive(str, i - 1) + str[i] - '0');
            //return result;
            //return result * sign;
        }

        private bool IsDigit(char chr) => chr >= '0' && chr <= '9';
    }
}<file_sep>﻿using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace Problems.MergeLists
{
    public class MyQueueTests
    {
        private readonly MyQueue myQueue;

        public MyQueueTests()
        {
            myQueue = new MyQueue();
        }

        [Fact(DisplayName = "New_MyQueue_Should_Be_Empty")]
        public void New_MyQueue_Should_Be_Empty()
        {
            myQueue.IsEmpty.Should().BeTrue();
        }

        [Fact(DisplayName = "Enqueue_Should_Put_Item_At_End_Of_Queue")]
        public void Enqueue_Should_Put_Item_At_End_Of_Queue()
        {
            myQueue.Enqueue(1);
            myQueue.Peek().Should().Be(1);

            myQueue.Enqueue(2);
            myQueue.Peek().Should().Be(1);
        }

        [Fact(DisplayName = "Dequeue_Should_Return_Item_At_The_Head_Of_Queue_And_Remove_It")]
        public void Dequeue_Should_Return_Item_At_The_Head_Of_Queue_And_Remove_It()
        {
            myQueue.Enqueue(1);
            myQueue.Enqueue(2);

            myQueue.Dequeue().Should().Be(1);
            myQueue.Peek().Should().Be(2);
        }

        [Fact(DisplayName = "Dequeue_Should_Throw_InvalidOperationException_When_Queue_Is_Empty")]
        public void Dequeue_Should_Throw_InvalidOperationException_When_Queue_Is_Empty()
        {
            Assert.Throws<InvalidOperationException>(() => myQueue.Dequeue());
        }

        [Fact(DisplayName = "Peek_Should_Return_Item_At_The_Head_Of_Queue_But_Keeps_It_On_Queue")]
        public void Peek_Should_Return_Item_At_The_Head_Of_Queue_But_Keeps_It_On_Queue()
        {
            myQueue.Enqueue(1);

            myQueue.Peek().Should().Be(1);
            myQueue.Peek().Should().Be(1);

            myQueue.Enqueue(2);
            myQueue.Peek().Should().Be(1);
        }

        [Fact(DisplayName = "Peek_Should_Throw_InvalidOperationException_When_Queue_Is_Empty")]
        public void Peek_Should_Throw_InvalidOperationException_When_Queue_Is_Empty()
        {
            Assert.Throws<InvalidOperationException>(() => myQueue.Peek());
        }

        [Fact(DisplayName = "IsEmpty_Should_Return_False_After_Item_Has_Been_Enqueued")]
        public void IsEmpty_Should_Return_False_After_Item_Has_Been_Enqueued()
        {
            myQueue.Enqueue(1);

            myQueue.IsEmpty.Should().BeFalse();

            myQueue.Dequeue();
            myQueue.Enqueue(2);

            myQueue.IsEmpty.Should().BeFalse();
        }

        [Fact(DisplayName = "IsEmpty_ShouldReturn_True_After_All_Items_Had_Been_DeQueued")]
        public void IsEmpty_ShouldReturn_True_After_All_Items_Had_Been_DeQueued()
        {
            myQueue.Enqueue(1);
            myQueue.Enqueue(2);

            myQueue.Dequeue();
            myQueue.Dequeue();

            myQueue.IsEmpty.Should().BeTrue();
        }
    }
}
<file_sep>using System;

namespace Arrays.Sorting
{
    class QuickSortC : QuickSortBase
    {
        protected override void Sort(int[] array, int start, int end)
        {
            Console.WriteLine($"Sort: start = {start}; end = {end}");

            if(start < end) {
                int pivotIndex = Partition(array, start, end);
                Sort(array, start, pivotIndex - 1);
                Sort(array, pivotIndex + 1, end);
            }
        }

        protected override int Partition(int[] array, int start, int end)
        {
            int pivot = array[start];
            int pivotIndex = start;
            int current = 0;
            int[] helper = new int[(end - start + 1)];

            for(int i = start + 1; i <= end; i++) {
                if(array[i] < pivot) {
                    helper[current++] = array[i];
                }
            }
            pivotIndex = current + start;
            helper[current++] = pivot;
            for(int i = start + 1; i <= end; i++) {
                if(array[i] >= pivot) {
                    helper[current++] = array[i];
                }
            }

            helper.CopyTo(array, start);
            return pivotIndex;
        }
    }
}<file_sep>﻿using System;
using Trees;

namespace trees
{
    public static class TreeExtensions
    {
        public static int Height<T>(this Tree<T> tree)
            where T : IComparable<T>
        {
            return Height(tree.Root);
        }

        private static int Height<T>(Node<T> root)
            where T : IComparable<T>
        {
            if (root == null) return 0;

            var leftHeight = Height(root.Left);
            var rightHeight = Height(root.Right);

            return Math.Max(leftHeight, rightHeight) + 1;
        }

        public static void Print<T>(this Tree<T> tree)
            where T : IComparable<T>
        {
            PrintNode(tree.Root);
        }

        private static void PrintNode<T>(Node<T> node, int direction = 0)
            where T : IComparable<T>
        {
            if(node == null) return;

            var directionStr = direction < 0 ? "  /  " : "   \\   ";
            if(direction == 0) directionStr = "";

            Console.WriteLine(directionStr);
            Console.WriteLine($"{node.Data}");

            PrintNode(node.Left, -1);
            PrintNode(node.Right, 1);
        }
    }
}
<file_sep>using Xunit;

namespace Arrays.Search
{
    public class BinarySearchTests
    {
        [Theory]
        [InlineData(new long[] {1, 2, 3, 4, 5}, 3)]
        [InlineData(new long[] {1, 2, 3, 4, 5}, 1)]
        [InlineData(new long[] {1, 2, 3, 4, 5}, 5)]
        public void BinarySearch_ShouldReturnTrue_WhenLookupValueIsFound(long[] array, long lookupValue)
        {
            const bool expectedResult = true;

            DoTest(array, lookupValue, expectedResult);
        }

        [Fact]
        public void BinarySearch_ShouldReturnFalse_WhenLookupValueIsNotFound()
        {
            const long lookupValue = 0;
            const bool expectedResult = false;
            long[] array = {1, 2, 3, 4, 5};

            DoTest(array, lookupValue, expectedResult);
        }

        [Fact]
        public void BinarySearch_ShouldHandleUnsortedArrays()
        {
            const long lookupValue = 5;
            const bool expectedResult = true;
            long[] array = {9, 3, 1, 4, -5, 5};

            DoTest(array, lookupValue, expectedResult);
        }
        
        private void DoTest(long[] array, long lookupValue, bool expectedResult)
        {
            var result = BinarySearch.Search(array, lookupValue);

            Assert.Equal(expectedResult, result);
        }
    }
}<file_sep>﻿namespace Problems.MergeLists
{
    public static class Solution
    {
        public static SinglyLinkedList MergeLists (SinglyLinkedListNode head1, SinglyLinkedListNode head2)
        {
            SinglyLinkedList resultList = new SinglyLinkedList();

            while(head1 != null && head2 != null)
            {
                if (head1 != null && head1.Data <= head2.Data)
                {
                    resultList.Append(head1.Data);
                    head1 = head1.Next;
                } 
                else if (head2 != null)
                {
                    resultList.Append(head2.Data);
                    head2 = head2.Next;
                }
            }

            while (head1 != null)
            {
                resultList.Append(head1.Data);
                head1 = head1.Next;
            }

            while (head2 != null)
            {
                resultList.Append(head2.Data);
                head2 = head2.Next;
            }

            return resultList;
        }
    }
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text;

namespace Problems.MergeLists
{
    public class SinglyLinkedListNode
    {
        public SinglyLinkedListNode(int data)
        {
            this.Data = data;
        }

        public int Data { get; set; }
        public SinglyLinkedListNode Next { get; set; }

        public override bool Equals(object obj)
        {
            if (obj is SinglyLinkedListNode)
            {
                return this.Data == this.Data;
            }

            return false;
        }

        public override int GetHashCode()
        {
            return 7 ^ Data.GetHashCode();
        }
    }
}
<file_sep>﻿using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using FluentAssertions;

namespace Problems.MergeLists
{
    public class MyStackTests
    {
        private readonly MyStack stack = new MyStack();

        [Fact (DisplayName = "IsEmpty_Should_Return_True_When_Stack_Is_New")]
        public void IsEmpty_Should_Return_True_When_Stack_Is_New()
        {
            stack.IsEmpty.Should().BeTrue();
        }

        [Fact(DisplayName = "IsEmpty_Should_Return_True_When_Item_Is_Pushed")]
        public void IsEmpty_Should_Return_True_When_Item_Is_Pushed()
        {
            stack.Push(1);
            stack.IsEmpty.Should().BeFalse();

            stack.Push(2);
            stack.IsEmpty.Should().BeFalse();
        }

        [Fact(DisplayName = "IsEmpty_Should_Return_False_When_All_Items_Are_Popped")]
        public void IsEmpty_Should_Return_False_When_All_Items_Are_Popped()
        {
            stack.Push(1);
            stack.Push(2);

            stack.Pop();
            stack.Pop();

            stack.IsEmpty.Should().BeTrue();
        }

        [Fact(DisplayName = "Push_Should_Put_Item_At_The_Top_Of_Stack")]
        public void Push_Should_Put_Item_At_The_Top_Of_Stack()
        {
            stack.Push(1);
            stack.Peek().Should().Be(1);

            stack.Push(2);
            stack.Peek().Should().Be(2);
        }

        [Fact(DisplayName = "Pop_Should_Remove_And_Return_Item_At_The_Top_Of_Stack")]
        public void Pop_Should_Remove_And_Return_Item_At_The_Top_Of_Stack()
        {
            stack.Push(1);
            stack.Push(2);

            stack.Pop().Should().Be(2);
            stack.Pop().Should().Be(1);
        }

        [Fact(DisplayName = "Pop_Should_Throw_InvalidOperationException_When_Stack_Is_Empty")]
        public void Pop_Should_Throw_InvalidOperationException_When_Stack_Is_Empty()
        {
            Assert.Throws<InvalidOperationException>(() => stack.Pop());
        }

        [Fact(DisplayName = "Peek_Should_Return_Item_At_The_Top_Of_Stack_And_Keep_It")]
        public void Peek_Should_Return_Item_At_The_Top_Of_Stack_And_Keep_It()
        {
            stack.Push(1);
            stack.Peek().Should().Be(1);

            stack.Push(2);
            stack.Peek().Should().Be(2);
        }

        [Fact(DisplayName = "Peek_Should_Throw_InvalidOperationException_When_Stack_Is_Empty")]
        public void Peek_Should_Throw_InvalidOperationException_When_Stack_Is_Empty()
        {
            Assert.Throws<InvalidOperationException>(() => stack.Peek());
        }
    }
}
<file_sep>using System;

namespace Arrays.Sorting
{
    abstract class QuickSortBase : ISorter
    {
        public void Sort(int[] array)
        {
            Sort(array, 0, array.Length - 1);
        }

        protected abstract void Sort(int[] array, int start, int end);

        protected abstract int Partition(int[] array, int start, int end);
    }
}<file_sep>using System;
using Xunit;

namespace Arrays
{
    public class ArrayExtensionsTests
    {
        public class CopyTests
        {

            [Fact]
            public void ShouldCopyArrayFromStartToFinish()
            {
                int[] array = new int[] { 1, 2, 3, 4, 5 };

                var copy = ArrayExtensions.Copy(array);

                // Assert.
                Assert.NotSame(copy, array);
                Assert.Equal(array, copy);
            }

            [Fact]
            public void ShouldCopyArrayFromSpecifiedStartAndEnd()
            {
                int[] array = new int[] { 1, 2, 3, 4, 5 };
                int[] expected = new int[] { 1, 2, 3 };

                var copy = ArrayExtensions.Copy(array, 0, 2);

                // Assert.
                Assert.Equal(expected, copy);
            }
        }

        public class CopyToTests
        {
            [Theory]
            [InlineData(new int[] { 1, 3, 2 }, new int[] { 0, 0, 0, 5, 8, 7, 9 }, 0, new int[] { 1, 3, 2, 5, 8, 7, 9 })]
            [InlineData(new int[] { 3, 2 }, new int[] { 1, 0, 0, 5, 8, 7, 9}, 1, new int[] { 1, 3, 2, 5, 8, 7, 9 })]
            [InlineData(new int[] { 1, 3, 2, 5, 8, 7, 9 }, new int[] { 0, 0, 0, 0, 0, 0, 0}, 0, new int[] { 1, 3, 2, 5, 8, 7, 9 })]
            [InlineData(new int[] { 8, 7, 9 }, new int[] { 1, 3, 2, 5, 0, 0, 0 }, 4, new int[] { 1, 3, 2, 5, 8, 7, 9 })]
            public void ShouldCopySourceIntoDestinationArrayFromSpecifiedStartAndEndIndexes(int[] sourceArray, int[] destArray, int start, int[] expectedArray)
            {
                //Arrange
                //Act
                ArrayExtensions.CopyTo(sourceArray, destArray, start);

                //Assert
                Assert.Equal(destArray, expectedArray);
            }
        }

        public class SwapTests
        {
            [Fact]
            public void ShouldSwapValuesInArray()
            {
                //Arrange
                int[] array = new int[] { 1, 2, 3, 4 };
                int left = 1, right = 3;
                int originalLeft = array[left];
                int originalRight = array[right];

                //Act
                ArrayExtensions.Swap(array, left, right);

                //Assert
                Assert.Equal(originalLeft, array[right]);
                Assert.Equal(originalRight, array[left]);
            }
        }
    }
}
<file_sep>using System;
using System.Linq;
using Xunit;

namespace Trees
{
    public class TreeTests
    {
        public class InsertTests 
        {
            [Fact]
            public void ShouldSetRootNode_WhenTreeIsEmpty()
            {
                const int data = 5;
                var tree = new Tree<int>();

                tree.Insert(data);

                Assert.False(tree.IsEmpty);
                Assert.NotNull(tree.Root);
                Assert.Equal(data, tree.Root.Data);
            }

            [Fact]
            public void ShouldSetRootLeftNode_WhenDataIsLessThanRootData()
            {
                const int data = 5;
                var tree = new Tree<int>(10);

                tree.Insert(data);

                Assert.False(tree.IsEmpty);
                Assert.NotNull(tree.Root.Left);
                Assert.Equal(data, tree.Root.Left.Data);
            }

            [Fact]
            public void ShouldSetRootRightNode_WhenDataIsGreaterThanRootData()
            {
                const int data = 15;
                var tree = new Tree<int>(10);

                tree.Insert(data);

                Assert.False(tree.IsEmpty);
                Assert.NotNull(tree.Root.Right);
                Assert.Equal(data, tree.Root.Right.Data);
            }
        }

        public class TraverseTests
        {
            private Tree<int> _tree;

            public TraverseTests()
            {
                _tree = new Tree<int>(10);
                _tree.Insert(5);
                _tree.Insert(3);
                _tree.Insert(9);
                _tree.Insert(20);
                _tree.Insert(25);
                // _tree.Insert(15);
            }

            [Fact]
            public void ShouldTraverseTreeInOrder_WhenTraverseOrderIsInOrder()
            {
                //When
                var items = _tree.Traverse(TraverseOrder.InOrder);
                
                //Then
                Assert.Collection(items,
                    i => Assert.Equal(3, i),
                    i => Assert.Equal(5, i),
                    i => Assert.Equal(9, i),
                    i => Assert.Equal(10, i),
                    i => Assert.Equal(20, i),
                    i => Assert.Equal(25, i)
                );
            }

            [Fact]
            public void ShouldTraverseTreePostOrder_WhenTraverseOrderIsPostOrder()
            {
                //when
                var items = _tree.Traverse(TraverseOrder.PostOrder);

                //Then
                Assert.Collection(items,
                    i => Assert.Equal(3, i),
                    i => Assert.Equal(9, i),
                    i => Assert.Equal(5, i),
                    i => Assert.Equal(25, i),
                    i => Assert.Equal(20, i),
                    i => Assert.Equal(10, i)
                );
            }

            [Fact]
            public void ShouldTraverseTreePreOrder_WhenTraverseOrderIsPreOrder()
            {
                //When
                var items = _tree.Traverse(TraverseOrder.PreOrder);

                //Then
                Assert.Collection(items,
                    i => Assert.Equal(10, i),
                    i => Assert.Equal(5, i),
                    i => Assert.Equal(3, i),
                    i => Assert.Equal(9, i),
                    i => Assert.Equal(20, i),
                    i => Assert.Equal(25, i)
                );
            }

            [Fact]
            public void ShouldTraverseTreeInLevelOrder_WhenTraverseOrderIsInLevelOrder()
            {
                //When
                var items = _tree.Traverse(TraverseOrder.LevelOrder);
                
                //Then
                Assert.Collection(items,
                    i => Assert.Equal(10, i),
                    i => Assert.Equal(5, i),
                    i => Assert.Equal(20, i),
                    i => Assert.Equal(3, i),
                    i => Assert.Equal(9, i),
                    i => Assert.Equal(25, i)
                );
            }
        }
    }
}
<file_sep>using System;
using Xunit;

namespace Arrays.Sorting
{
    public class SortingTests
    {   
        [Fact]
        public void MergeSort_ShouldReturnSortedArray()
        {
            var sorter = new MergeSort();
            DoTest(sorter);
        }

        [Fact]
        public void QuickSortA_ShouldReturnSortedArray()
        {
            var sorter = new QuickSortA();
            DoTest(sorter);
        }
        
        [Fact]
        public void QuickSortB_ShouldReturnSortedArray()
        {
            var sorter = new QuickSortB();
            DoTest(sorter);
        }

        [Fact]
        public void QuickSortC_ShouldReturnSortedArray()
        {
            var sorter = new QuickSortC();
            DoTest(sorter);
        }

        private void DoTest(ISorter sorter) 
        {
            int[] array = { 38, 27, 43, 3, 9, 82, 10 };
            int[] expectedSortedArray = { 3, 9, 10, 27, 38, 43, 82 };

            sorter.Sort(array);

            Assert.Equal(expectedSortedArray, array);
        }
    }
}
<file_sep>namespace Arrays.Sorting
{
    class QuickSortB : QuickSortBase
    {
        protected override void Sort(int[] array, int start, int end)
        {
            if(start < end) {
                int pivotIndex = Partition(array, start, end);
                Sort(array, start, pivotIndex - 1);
                Sort(array, pivotIndex + 1, end);
            }
        }

        ///
        /// This partition algorithm takes the last item on the array as pivot
        /// Then it starts traversing the array until an item less than the pivot appears
        /// swapping the values. It then returns the pivot index.
        protected override int Partition(int[] array, int start, int end)
        {
            int pivot = array[end];
            int pivotIndex = start;

            for(int i = start; i < end; i++) 
            {
                if(array[i] <= pivot)
                {
                    array.Swap(pivotIndex, i);
                    pivotIndex++;
                }
            }
            array.Swap(pivotIndex, end);

            return pivotIndex;
        }

    }
}<file_sep>﻿using System.Linq;

namespace array_manipulation
{
    internal class ArrayManipulator
    {
        public long GetMaxInArray(TestData testData)
        {
            var array = Enumerable.Repeat((long)0, testData.ArraySize + 1)
                              .ToArray();
            DoInsert(testData.Queries, array);

            return Max(array);
        }

        void DoInsert(int[][] queries, long[] array)
        {
            int a, b, k;
            for (int queryLine = 0; queryLine < queries.Length; queryLine++)
            {
                a = queries[queryLine][0];
                b = queries[queryLine][1];
                k = queries[queryLine][2];

                array[a] += k;

                if ((b + 1) < array.Length) 
                    array[(b + 1)] -= k;
                /*
                for (int index = a; index <= b; index++)
                {
                    array[index] += k;
                }*/
            }
        }

        long Max(long[] array) {
            long max = 0, temp = 0;

            for (int i = 1; i < array.Length; i++) {
                temp += array[i];
                if (max < temp)
                    max = temp;
            }

            return max;
        }
    }
}<file_sep>using System;
using System.Diagnostics;

namespace Arrays.TwoSortedArraysMedian
{
    public class Solution
    {
        public static double FindMedianSortedArrays(int[] nums1, int[] nums2) 
        {
            // first determine the number of items each of the arrays will contribute
            // to the left half of the merged array
            int[] A = nums1;
            int[] B = nums2;

            if (nums1.Length > nums2.Length)
            {
                A = nums2;
                B = nums1;
            }

            return FindMedianSortedArrays(A, B, 0, A.Length);
        }

        private static double FindMedianSortedArrays(int[] A, int[] B, int start, int end)
        {
            Console.WriteLine($"start = {start}; end = {end}");
            
            int halfLength = (A.Length + B.Length + 1) / 2;
            int partitionA = (end + start) / 2;
            int partitionB = halfLength - partitionA;

            Debug.WriteLine($"partitionA = {partitionA}; partitionB = {partitionB}");

            int x = partitionA > 0 ? A[partitionA - 1] : int.MinValue;
            int xP = partitionA >= A.Length ? int.MaxValue : A[partitionA];
            int y = partitionB > 0 ? B[partitionB - 1] : int.MinValue;
            int yP = partitionB >= B.Length ? int.MaxValue : B[partitionB];

            Debug.WriteLine($"x = {x}; xP = {xP}");
            Debug.WriteLine($"y = {y}; yP = {yP}");

            if (x <= yP && y <= xP)
            {
                if ((A.Length + B.Length) % 2 == 0)
                {
                    return (Math.Max(x, y) + Math.Min(xP, yP)) / 2.0d;
                }

                return Math.Max(x, y);
            }
            else if (x > yP)
            {
                return FindMedianSortedArrays(A, B, start, partitionA);
            }
            else
            {
                return FindMedianSortedArrays(A, B, partitionA + 1, end);
            }
        }
    }
}<file_sep>using System;
using System.Collections.Generic;

namespace Trees
{
    internal class Node<T> where T: IComparable<T>
    {
        public T Data { get; set; }
        public Node<T> Left { get; set; }
        public Node<T> Right { get; set; }

        internal Node(T data)
        {
            Data = data;
        }

        public void Insert(T data) 
        {
            var comparision = data.CompareTo(this.Data);

            if(comparision <= 0) 
            {
                if(Left == null)
                    Left = new Node<T>(data);
                else 
                    Left.Insert(data);
            } else 
            {
                if(Right == null)
                    Right = new Node<T>(data);
                else
                    Right.Insert(data);
            }
        }

        internal IEnumerable<T> TraverseInOrder()
        {
            var list = new List<T>();

            if(Left != null)
                list.AddRange(Left.TraverseInOrder());

            list.Add(this.Data);

            if(Right != null)
                list.AddRange(Right.TraverseInOrder());

            return list;
        }

        internal IEnumerable<T> TraversePostOrder()
        {
            var list = new List<T>();

            if(Left != null)
                list.AddRange(Left.TraversePostOrder());

            if(Right != null)
                list.AddRange(Right.TraversePostOrder());

            list.Add(this.Data);
            
            return list;
        }

        internal IEnumerable<T> TraversePreOrder()
        {
            var list = new List<T>();

            list.Add(this.Data);
            
            if(Left != null)
                list.AddRange(Left.TraversePreOrder());

            if(Right != null)
                list.AddRange(Right.TraversePreOrder());

            return list;
        }

        internal IEnumerable<T> TraverseLevelOrder()
        {
            var queue = new Queue<Node<T>>();
            var list = new List<T>();

            queue.Enqueue(this);

            while(queue.Count > 0) 
            {
                var currentNode = queue.Dequeue();
                list.Add(currentNode.Data);

                if(currentNode.Left != null) queue.Enqueue(currentNode.Left);
                if(currentNode.Right != null) queue.Enqueue(currentNode.Right);
            }

            return list;
        }
    }
}<file_sep>using System;
using System.Diagnostics;

namespace Arrays.Sorting
{
    class MergeSort : ISorter
    {
        public void Sort(int[] array)
        {
            int n = array.Length;

            if(n < 2) {
                return;
            }

            int mid = n / 2;
            int[] left = ArrayExtensions.Copy(array, 0, mid - 1);
            int[] right = ArrayExtensions.Copy(array, mid, n - 1);
            Sort(left);
            Sort(right);
            Merge(left, right, array);
            left = right = null;
        }

        void Merge(int[] left, int[] right, int[] array)
        {
            if((left.Length + right.Length) > array.Length)
                throw new ArgumentOutOfRangeException();

            int k = 0, i = 0, j = 0;
            // Iterate both left and right arrays
            // Using i as an index for left and j for right arrays
            while(i < left.Length && j < right.Length) {
                //Compare elements from left and right arrays, if left array is greater or equal to right array element,
                // copy left item into destination array. Otherwise, copy the right item into destination array.
                if(left[i] <= right[j]) {
                    array[k++] = left[i++];
                } else {
                    array[k++] = right[j++];
                }
            }
            //Are there any remaining items on left array, copy all of them into array
            while(i < left.Length) {
                array[k++] = left[i++];
            }
            //Do the same for righ array.
            while(j < right.Length) {
                array[k++] = right[j++];
            }
        }

        void PrintArray(int[] array) 
        {
            
        }
    }
}<file_sep>using System;

namespace Heaps
{
    public abstract class Heap
    {
        private int _capacity;
        private int _size;
        private int[] _items;

        public Heap() : this(10) {}

        public Heap(int initialCapacity) 
        {
            _capacity = initialCapacity;
            _size = 0;
            _items = new int[_capacity];
        }

        protected int Capacity => _capacity;
        protected int Size => _size;
        protected int[] Items => _items;

        protected bool IsEmpty => _size == 0;
        
        protected abstract bool Compare(int a, int b);

        private int GetLeftChildIndex(int parentIndex) => 2 * parentIndex + 1;
        private int GetRightChildIndex(int parentIndex) => 2 * (parentIndex + 1);
        private int GetParentIndex(int childIndex) => (childIndex - 1) / 2;

        private bool HasLeftChild(int index) => GetLeftChildIndex(index) < _size;
        private bool HasRightChild(int index) => GetRightChildIndex(index) < _size;
        private bool HasParent(int index) => GetParentIndex(index) >= 0;

        private int GetLeftChild(int index) => _items[GetLeftChildIndex(index)];
        private int GetRightChild(int index) => _items[GetRightChildIndex(index)];
        private int GetParent(int index) => _items[GetParentIndex(index)];
        
        private void Swap(int indexA, int indexB) 
        {
            int temp = _items[indexA];
            _items[indexA] = _items[indexB];
            _items[indexB] = temp;
        }

        private void EnsureCapacity()
        {
            if(_size == _capacity) 
            {
                _capacity *= 2;
                Array.Resize(ref _items, _capacity);
            }
        }

        private void HeapifyUp()
        {
            int index = _size - 1;
            // while(HasParent(index) && GetParent(index) > _items[index]) 
            while(HasParent(index) && !Compare(GetParent(index), _items[index]))
            {
                Swap(index, GetParentIndex(index));
                index = GetParentIndex(index);
            }
        }

        private void HeapifyDown(int index = 0)
        {
            while(HasLeftChild(index)) 
            {
                int childIndex = GetLeftChildIndex(index);
                // if(HasRightChild(index) && GetRightChild(index) < GetLeftChild(index)) 
                if(HasRightChild(index) && Compare(GetRightChild(index), GetLeftChild(index))) 
                {
                    childIndex = GetRightChildIndex(index);
                }

                // if(_items[index] < _items[childIndex]) 
                if(Compare(_items[index], _items[childIndex])) 
                {
                    break;
                } 
                else 
                {
                    Swap(index, childIndex);
                }
                index = childIndex;
            }
        }
    }
}<file_sep>using System;

namespace Arrays
{
    public static class ArrayExtensions
    {
        public static int[] Copy(this int[] source) 
        {
            return Copy(source, 0, source.Length - 1);
        }

        public static int[] Copy(this int[] source, int start, int end) 
        {
            int n = end - start + 1;

            if(n < 1)
                throw new ArgumentOutOfRangeException();

            var temp = new int[n];

            for(int i = 0, j = start; i < n; i++, j++) 
            {
                temp[i] = source[j];
            }

            return temp;
        }

        public static void CopyTo(this int[] source, int[] dest, int start) 
        {
            if(source.Length + start > dest.Length)
                throw new ArgumentOutOfRangeException(nameof(start));

            int current = start;
            for(int i = 0; i < source.Length; i++) 
            {
                dest[current++] = source[i];
            }
        }

        public static void Swap(this int[] array, int index1, int index2)
        {
            if(index1 < 0 && index1 >= array.Length)
                throw new ArgumentOutOfRangeException(nameof(index1));
            if(index2 < 0 && index2 >= array.Length)
                throw new ArgumentOutOfRangeException(nameof(index2));

            int temp = array[index2];
            array[index2] = array[index1];
            array[index1] = temp;
        }
    }
}<file_sep>﻿using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Xunit.Abstractions;

namespace Problems
{
    public class DictionaryTests
    {
        private readonly ITestOutputHelper output;

        public DictionaryTests(ITestOutputHelper output)
        {
            this.output = output ?? throw new ArgumentNullException(nameof(output));
        }

        [Fact(DisplayName = "Dictionary_Keeps_Keys_In_Order")]
        public void Dictionary_Keeps_Keys_In_Order_Of_Insertion()
        {
            var dict = new Dictionary<int, int>();
            dict.Add(1, 1);
            dict.Add(4, 1);
            dict.Add(2, 1);
            dict.Add(3, 1);

            int[] orderedKeys = { 1, 4, 2, 3 };
            int index = 0;
            foreach(var key in dict.Keys)
            {
                output.WriteLine($"{key} = {dict[key]}");
                key.Should().Be(orderedKeys[index++]);
            }
        }
    }
}
<file_sep>namespace Arrays.Sorting
{
    class QuickSortA : QuickSortBase
    {
        protected override void Sort(int[] array, int start, int end)
        {
            if(start < end) {
                int pivotIndex = Partition(array, start, end);
                Sort(array, start, pivotIndex - 1);
                Sort(array, pivotIndex, end);
            }
        }

        // This partition algorithm takes a pivot as parameter (usually the mid point in the array)
        // Then it takes two pointers, left and right. Left pointer will traverse the array from left to right.
        // Whereas right pointer will do so from right to left. 
        // It will swap the left and right items once: left item is greater or equal to pivot and right item is
        // less or equal to pivot.
        protected override int Partition(int[] array, int start, int end)
        {
            int mid = (start + end) / 2;
            int pivot = array[mid];

            int left = start;
            int right = end;
            while(left <= right)
            {
                while(array[left] < pivot) left++;
                while(array[right] > pivot) right--;

                if(left <= right) {
                    array.Swap(left, right);
                    left++; right--;
                }
            }

            return left;
        }
    }
}<file_sep>using System;
using System.Collections;
using System.Collections.Generic;

namespace Trees
{
    public enum TraverseOrder
    {
        InOrder,
        PreOrder,
        PostOrder,
        LevelOrder
    }

    public class Tree<T> 
        where T: IComparable<T>
    {
        private Node<T> _root;

        public Tree() : this(null) {}

        public Tree(T rootData) : this(new Node<T>(rootData)) {}

        internal Tree(Node<T> root)
        {
            _root = root;
        }

        public bool IsEmpty => _root == null;

        public void Insert(T data)
        {
            if (_root == null)
            {
                _root = new Node<T>(data);
                return;
            }

            _root.Insert(data);
        }

        public IEnumerable<T> Traverse()
        {
            return Traverse(TraverseOrder.InOrder);
        }

        public IEnumerable<T> Traverse(TraverseOrder order)
        {
            if(_root == null)
                throw new InvalidOperationException(); 

            var traversal = default(IEnumerable<T>);

            switch(order) 
            {
                case TraverseOrder.InOrder:
                    traversal = _root.TraverseInOrder();
                    break;
                case TraverseOrder.PostOrder:
                    traversal = _root.TraversePostOrder();
                    break;
                case TraverseOrder.PreOrder:
                    traversal = _root.TraversePreOrder();
                    break;
                case TraverseOrder.LevelOrder:
                    traversal = _root.TraverseLevelOrder();
                    break;
            }

            return traversal;
        }

        internal Node<T> Root => _root;
    }
}<file_sep>using System;
using System.Collections;
using System.Linq;

namespace Arrays.Search
{
    public static class BinarySearch
    {
        public static bool Search(long[] array, long lookupValue)
        {
            Array.Sort(array);
            // int index =  SearchInternal(array, lookupValue, 0, array.Length - 1);
            int index = BinarySearchLoop(array, lookupValue);
            
            return index >= 0;
        }

        private static int SearchInternal(long[] array, long lookupValue, int startIndex, int endIndex)
        {
            if(startIndex > endIndex)
            {
                return -1; //Value not found.
            }

            int midIndex = (endIndex + startIndex) / 2;
            if(lookupValue > array[midIndex]) 
            {
                return SearchInternal(array, lookupValue, midIndex + 1, endIndex);
            } 
            else if(lookupValue < array[midIndex])
            {
                return SearchInternal(array, lookupValue, startIndex, midIndex - 1);
            }

            return midIndex;
        }

        private static int BinarySearchLoop(long[] array, long lookupValue)
        {
            int startIndex = 0;
            int endIndex = array.Length - 1;
            int midIndex = 0;

            while(startIndex <= endIndex) 
            {
                midIndex = (endIndex + startIndex) / 2;

                if(lookupValue > array[midIndex])
                {
                    startIndex = midIndex + 1;
                } 
                else if(lookupValue < array[midIndex])
                {
                    endIndex = midIndex - 1;
                }
                else if(lookupValue == array[midIndex])
                {
                    return midIndex;
                }
            }

            return -1;
        }
    }
}<file_sep>using Xunit;

namespace Arrays.SwapSum
{
    public class SwapSumTests
    {
        
            [Theory]
            [InlineData(new long[] {0, 1, 2, 3, 4, 5}, new long[] {5, 4, 6, 0, 0}, true)]
            [InlineData(new long[] {0, 3, 5, 7, 9, 1}, new long[] {5, 4, 1, 9}, true)]
            [InlineData(new long[] {0, 3, 5, 7, 9, 1}, new long[] {2, 4, 8, 9, 1}, false)]
            public void AreElegibleTests(long[] arrayA, long[] arrayB, bool expectedResult)
            {
                var areElegible = SwapSum.AreElegible(arrayA, arrayB);

                Assert.Equal(expectedResult, areElegible);
            }
        
    }
}<file_sep>using System;
using Xunit;

namespace Arrays.TwoSortedArraysMedian 
{
    public class TwoSortedArraysMedianTests
    {
        [Theory(DisplayName = "FindMedianSortedArrays")]
        [InlineData(new int[] {1, 2}, new int[] {3}, 2.0)]
        [InlineData(new int[] {1, 2}, new int[] {3, 4}, 2.5)]
        [InlineData(new int[] {4, 20, 32, 50, 55, 61}, new int[] {1, 15, 22, 30, 70}, 30.0)]
        [InlineData(new int[] {23, 26, 31, 35}, new int[] {3, 5, 7, 9, 11, 16}, 13.5)]
        [InlineData(new int[] {23, 26, 31, 35, 36}, new int[] {3, 5, 7, 11}, 23.0)]
        public void FindMedianSortedArraysTests(int[] nums1, int[] nums2, double expectedMedian)
        {
            double actual = Solution.FindMedianSortedArrays(nums1, nums2);

            Assert.Equal(expectedMedian, actual);
        }
    }
}<file_sep>using System;

namespace Heaps
{
    public class MinHeap
    {
        private int _capacity;
        private int _size;
        private int[] _items;

        public MinHeap()
            : this(10)
        {}

        public MinHeap(int capacity) 
        {
            _capacity = capacity;
            _size = 0;

            _items = new int[_capacity];
        }

        public int Peek() 
        {
            if(IsEmpty) 
            {
                throw new InvalidOperationException();
            }

            return _items[0];
        }

        public int Poll() 
        {
            if(IsEmpty) 
            {
                throw new InvalidOperationException();
            }
            
            int item = _items[0];
            _items[0] = _items[_size - 1];
            _size--;
            HeapifyDown();
            
            return item;
        }

        public void Add(int item)
        {
            EnsureCapacity();

            _items[_size] = item;
            _size++;
            HeapifyUp();
        }

        private int GetLeftChildIndex(int parentIndex) => 2 * parentIndex + 1;
        private int GetRightChildIndex(int parentIndex) => 2 * (parentIndex + 1);
        private int GetParentIndex(int childIndex) => (childIndex - 1) / 2;

        private bool IsEmpty => _size == 0;
        private bool HasLeftChild(int index) => GetLeftChildIndex(index) < _size;
        private bool HasRightChild(int index) => GetRightChildIndex(index) < _size;
        private bool HasParent(int index) => GetParentIndex(index) >= 0;

        private int GetLeftChild(int index) => _items[GetLeftChildIndex(index)];
        private int GetRightChild(int index) => _items[GetRightChildIndex(index)];
        private int GetParent(int index) => _items[GetParentIndex(index)];
        
        private void Swap(int indexA, int indexB) 
        {
            int temp = _items[indexA];
            _items[indexA] = _items[indexB];
            _items[indexB] = temp;
        }

        private void EnsureCapacity()
        {
            if(_size == _capacity) 
            {
                _capacity *= 2;
                int[] temp = new int[_capacity];
                _items.CopyTo(temp, 0);
                _items = temp;
            }
        
        }

        private void HeapifyUp()
        {
            int index = _size - 1;
            while(HasParent(index) && GetParent(index) > _items[index]) 
            {
                Swap(index, GetParentIndex(index));
                index = GetParentIndex(index);
            }
        }

        private void HeapifyDown(int index = 0)
        {
            while(HasLeftChild(index)) 
            {
                int childIndex = GetLeftChildIndex(index);
                if(HasRightChild(index) && GetRightChild(index) < GetLeftChild(index)) 
                {
                    childIndex = GetRightChildIndex(index);
                }

                if(_items[index] < _items[childIndex]) 
                {
                    break;
                } 
                else 
                {
                    Swap(index, childIndex);
                }
                index = childIndex;
            }
        }
    }
}<file_sep>
using System;
using System.Collections.Generic;

namespace MigratoryBirds
{
    public class MigratoryBirds
    {
        public int Solve(int[] inputArray) 
        {
            var birdSights = new Dictionary<int, int> {
                { 1, 0 },
                { 2, 0 },
                { 3, 0 },
                { 4, 0 },
                { 5, 0 }
            };
        
            foreach(var birdId in inputArray) {
                if(!birdSights.ContainsKey(birdId)) {
                    birdSights.Add(birdId, 0);
                }
                
                birdSights[birdId] = birdSights[birdId] + 1;
            }
            /*foreach(var item in birdSights) {
                Console.WriteLine("{0}: {1}", item.Key, item.Value);
            }*/
            //birdSight.s
            int maxCountBirdId = 0, maxCount = 0;
            foreach(var birdId in birdSights.Keys) {
                if(birdSights[birdId] > maxCount) {
                    maxCount = birdSights[birdId];
                    maxCountBirdId = birdId;
                    /*Console.WriteLine("maxCount = {0}", maxCount);
                    Console.WriteLine("birdId = {0}", birdId);
                    Console.WriteLine("maxCountBirdId = {0}", maxCountBirdId);*/
                    /*if(maxCountBirdId == 0 || maxCountBirdId > birdId) {
                        maxCountBirdId = birdId;
                    }*/
                    
                }
            }
            
            return maxCountBirdId;
        }
    }
}<file_sep>using System;
using System.Collections;

namespace Trees
{
    public static class CheckBstTreeExtensions
    {
        public static bool CheckBst(this Tree<int> tree)
        {
            if(tree == null || tree.IsEmpty) {
                return true;
            }

            return tree.Root.CheckBst();
        }

        private static bool CheckBst(this Node<int> node)
        {
            return CheckBst(node, Int32.MinValue, Int32.MaxValue);
        }

        private static bool CheckBst(Node<int> node, int min, int max)
        {
            if(node == null) return true;
            if(node.Data < min || node.Data > max)
                return false;
            
            return CheckBst(node.Left, min, node.Data) && CheckBst(node.Right, node.Data, max);
        }
    }
}<file_sep>namespace Arrays.Sorting
{
    public interface ISorter
    {
        void Sort(int[] array);
    }
}<file_sep>﻿using System;
using System.IO;
using System.Text;

namespace Problems.MergeLists
{
    public class SinglyLinkedList
    {
        public SinglyLinkedListNode Head { get; private set; } = null;
        public SinglyLinkedListNode Tail { get; private set; } = null;
        public SinglyLinkedListNode PreviousTail { get; set; } = null;

        public int Count { get; private set; } = 0;

        public void Append(int nodeData)
        {
            var newNode = new SinglyLinkedListNode(nodeData);

            if (Head == null)
            {
                Head = newNode;
            } else
            {
                PreviousTail = Tail;
                Tail.Next = newNode;
            }

            Tail = newNode;
            Count++;
        }

        public void Prepend(int nodeData)
        {
            var newNode = new SinglyLinkedListNode(nodeData)
            {
                Next = Head
            };

            if (Tail == null)
            {
                Tail = newNode;
            }
            else if (newNode.Next == Tail)
            {
                PreviousTail = newNode;
            }
            Head = newNode;
            Count++;
        }

        public SinglyLinkedListNode RemoveFirst()
        {
            var currentHead = Head;
            if (Tail == currentHead)
            {
                Tail = null;
            }
            Head = Head?.Next;
            Count--;

            return currentHead;
        }

        public SinglyLinkedListNode RemoveLast()
        {
            SinglyLinkedListNode lastNode;

            if (Head == Tail)
            {
                lastNode = Tail;
                Head = Tail = null;
            }
            else
            {
                var currentNode = Head;

                while (currentNode?.Next?.Next != null) currentNode = currentNode.Next;

                lastNode = Tail;
                Tail = currentNode;
                Tail.Next = null;
            }

            Count--;

            return lastNode;
        }

        public override bool Equals(object other)
        {
            if (!(other is SinglyLinkedList))
            {
                return false;
            }

            var ptr1 = this.Head;
            var ptr2 = (other as SinglyLinkedList).Head;

            while (ptr1 != null && ptr2 != null)
            {
                if (ptr1.Data != ptr2.Data)
                {
                    return false;
                }
                ptr1 = ptr1.Next;
                ptr2 = ptr2.Next;
            }

            if (ptr1 != null || ptr2 != null)
            {
                return false;
            }

            return true;
        }

        public override int GetHashCode()
        {
            return 7 ^ Count ^ Head.GetHashCode() ^ Tail.GetHashCode();
        }

        public static SinglyLinkedList FromArray(int[] array)
        {
            if (array is null)
            {
                throw new ArgumentNullException(nameof(array));
            }

            var newList = new SinglyLinkedList();

            foreach (int item in array)
            {
                newList.Append(item);
            }

            return newList;
        }

        public void Print(TextWriter textWriter, string sep = " ")
        {
            Print(Head, sep, textWriter);
        }

        public static void Print(SinglyLinkedListNode head, string sep, TextWriter textWriter)
        {
            var node = head;
            textWriter.Write("[");

            while (node != null)
            {
                textWriter.Write("{0}", node.Data);

                if (node.Next != null)
                {
                    textWriter.Write(sep);
                }

                node = node.Next;
            }

            textWriter.Write("]");
        }
    }
}
