Exemplo n.º 1
0
        /// <summary>
        /// ReverseLinkedListInGroupsOfGivenSizeV2 (Using Stack), TC: O(n*groupsize), SC: O(groupSize)
        /// This is done via Stack and that's why takes more space.
        /// https://www.geeksforgeeks.org/reverse-linked-list-groups-given-size-set-2/
        ///
        /// It's previous attempt for better SC is in the file below.
        /// Method: ReverseLinkedListInGroupsOfGivenSize, TC: O(n*groupsize), SC: O(1)
        /// https://www.geeksforgeeks.org/reverse-a-list-in-groups-of-given-size/
        /// </summary>
        public void ReverseLinkedListInGroupsOfGivenSizeV2()
        {
            var list = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 2, 4, 5, 6, 7, 8 });

            var head     = list.Head;
            var flag     = true;
            var tempNode = head;
            var size     = 4;
            var stack    = new Stack <ISinglyNode <int> >();
            ISinglyNode <int> tempNode2 = null;

            // iterate while your first moving temp node is valid
            while (tempNode != null)
            {
                // push elements in stack based on group size.
                for (int i = 0; i < size; i++)
                {
                    if (tempNode != null)
                    {
                        stack.Push(tempNode);
                        tempNode = tempNode.Next;
                    }
                    // if elements perish before group iteration completes, then come out.
                    else
                    {
                        break;
                    }
                }

                // We'll now pull out elements from stack to point to Head to begin
                // and then iterate through another temp node till we connect all stack
                // elements in reverse order. Post that, connect reversed list's END
                // to remaining "initial" list that still needs to be reversed.
                while (stack.Any())
                {
                    // Realign HEAD only once.
                    if (flag)
                    {
                        head      = stack.Pop();
                        tempNode2 = head;
                        flag      = false;

                        // Realigned HEAD now should point to the list.
                        list.Head = head;
                    }
                    else
                    {
                        tempNode2.Next = stack.Pop();
                        tempNode2      = tempNode2.Next;
                    }
                }

                // Now, connect reversed list's END
                // to remaining "initial" list that still needs to be reversed.
                tempNode2.Next = tempNode;

                list.Print();
            }
        }
        /// <summary>
        /// ReverseLinkedList, TC: O(n), SC: O(1)
        /// </summary>
        public static void ReverseLinkedList()
        {
            var list = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 3 }.Cast <int>());

            list.Print();

            // Take 3 elements for this process.
            ISinglyNode <int> previous, current, next;

            /* start with previous set to head, current to second element
             * 0. Iterate till C is not NULL.
             * 1. We backup NEXT series from C and reverse ties with P and C.
             * 2. If NEXT series is not null, then shift element by 1, C = Next of C and P = C.
             * else, SET Next of HEAD of list to NULL and HEAD = C
             * 3. Set C = Backed up series i.e. N
             *
             * INCREASE POINTERS ONE BY ONE
             */

            /* Previous = 1st node, Current = 2nd node
             */
            previous = list.Head;
            current  = list.Head.Next;

            while (current != null)
            {
                /* Save the chain ahead of Current.
                 * Reverse the flow. Current -> Previous
                 * Shift the previous ahead to current now
                 */
                next         = current.Next;
                current.Next = previous;
                previous     = current;

                /* If we reach the end of the list, then we have 1st node (which is the Head of the list)
                 * at the end of the list. Set it's _Next_ as NULL and reset list's Head as current
                 * (which is the current element - so called last element of the original list).
                 */
                if (next == null)
                {
                    list.Head.Next = null;
                    list.Head      = current;
                }

                // Shift the current ahead to Next (i.e. shift ahead by 1 node)
                current = next;
            }

            Console.WriteLine();
            list.Print();
        }
        /// <summary>
        /// ReverseLinkedListPostNnodes, TC: O(n), SC: O(1)
        /// </summary>
        public static void ReverseLinkedListPostNnodes()
        {
            var list = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 3, 4, 5, 6 }.Cast <int>());
            int counter = 2, index = 0; // reverse after 2 nodes

            list.Print();

            var node = list.Head;
            ISinglyNode <int> intervalLinkNode = null, previous = null, current = null;

            // Save the node after which you will reverse your list.
            // and mark the next two nodes as previous and current
            // for reversal process
            while (node != null)
            {
                if (index == counter - 1)
                {
                    intervalLinkNode = node;
                    previous         = intervalLinkNode.Next;
                    current          = previous.Next;
                    break;
                }

                node = node.Next;
                index++;
            }

            ISinglyNode <int> next = null;

            while (current != null)
            {
                next         = current.Next;
                current.Next = previous;

                if (next == null)
                {
                    // Reset the interval node's NEXT element to NULL AS END
                    // set the interval's NEXT as the current element which is actually last
                    intervalLinkNode.Next.Next = null;
                    intervalLinkNode.Next      = current;
                    break;
                }

                previous = current;
                current  = next;
            }

            list.Print();
        }
        /// <summary>
        /// ReverseLinkedListInPairs, TC: O(n), SC: O(1)
        /// </summary>
        public static void ReverseLinkedListInPairs()
        {
            var list = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }.Cast <int>());

            list.Print();

            int counter = 0;
            ISinglyNode <int> previous, current, next, intervalLinkNode;

            previous = current = next = intervalLinkNode = null;

            // Everytime for reversal take 3 elements
            // first element - previous, 2nd - current
            // till you reverse both of them...save the NEXT of 2nd element in "next"
            previous = list.Head;
            current  = previous.Next;

            while (current != null)
            {
                next          = current.Next;
                previous.Next = next;
                current.Next  = previous;

                if (counter == 0)
                {
                    list.Head = current;
                }
                else
                {
                    // save the interval last node to point to so-called
                    // current node which will become First element in the pair
                    intervalLinkNode.Next = current;
                }

                // shift the interval node to Last of the Pair.
                intervalLinkNode = previous;
                previous         = next;

                // check do we even have new previous element
                // if yes, do we have NEXT of previous to reverse.
                // if no, then break out from the loop.
                current = previous != null && previous.Next != null ? previous.Next : null;
                counter++;
            }

            list.Print();
        }
Exemplo n.º 5
0
        /// <summary>
        /// AddTwoNumbersContainedInLinkedLists
        ///
        /// Question: You are given two non-empty linked lists representing
        /// two non-negative integers. The digits are stored in reverse order
        /// and each of their nodes contain a single digit. Add the two
        /// numbers and return it as a linked list.
        /// You may assume the two numbers do not contain any leading zero, except the number 0 itself.
        ///
        /// LeetCode Question
        /// https://leetcode.com/problems/add-two-numbers/
        /// Type: LinkedList
        /// Difficulty: Medium
        /// </summary>
        public void AddTwoNumbersContainedInLinkedLists()
        {
            var l1 = LLUtility.CreateSinglyLinkedList(new int[] { 2, 4, 3 }).Head;
            var l2 = LLUtility.CreateSinglyLinkedList(new int[] { 5, 6, 4 }).Head;

            // Initialise it with 0 so we don't have to make flags for checking and iteration.
            // We'll just provide the output with next node instead.
            var sum = new SinglyNode <int>(0);

            int temp, q;

            temp = q = 0;
            ISinglyNode <int> sumPointer = sum;

            // checking the pointer with current digits. If both of them are null means numbers are finished.
            while (l1 != null || l2 != null)
            {
                // scan for nullables because numbers may not be of same length. If they aren't,
                // and one number finishes early then just replace it with 0 and don't hamper the addition
                temp = (l1?.Value ?? 0) + (l2?.Value ?? 0) + q;
                q    = temp / 10;                                  // carry

                sumPointer.Next = new SinglyNode <int>(temp % 10); // remainder goes as new node (actually sum of the nums)
                sumPointer      = sumPointer.Next;                 // move it ahead to store the next remainder in the next iteration

                // move the pointer to next digits. Nullable is used since both the numbers may not be of same length.
                l1 = l1?.Next;
                l2 = l2?.Next;
            }

            // accomodate quotient/carry if it spills over. E.g. 11 > 1  1
            if (q > 0)
            {
                sumPointer.Next = new SinglyNode <int>(q);
            }

            //Return or Print the sum now..
            var list = new SinglyLinkedList <int>();

            list.Head = sum.Next;
            list.Print();
        }
        /// <summary>
        /// FindMiddleElement, TC: O(n), SC: O(1)
        /// </summary>
        public static void FindMiddleElement()
        {
            var linkedList = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 3, 4, 5, 6, 7 }.Cast <int>());

            // look for middle element now
            var node = linkedList.Head;
            ISinglyNode <int> middleNode = null;
            var flag = true;

            while (node != null)
            {
                if (flag)
                {
                    middleNode = middleNode == null ? linkedList.Head : middleNode.Next;
                }

                flag = !flag;
                node = node.Next;
            }

            Console.WriteLine(middleNode.Value);
        }
        /// <summary>
        /// RotateLinkedList, TC: O(n), SC: O(1)
        /// </summary>
        public static void RotateLinkedList()
        {
            var list = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }.Cast <int>());

            Console.WriteLine("Original Linked List");
            list.Print();
            int toBeRotated = 3, counter = 0;

            Console.WriteLine($"Rotation count: {toBeRotated}\n");

            ISinglyNode <int> newLastNode = null, node = list.Head;

            // Iterate till we reach last node
            while (node.Next != null)
            {
                // Save the node which is to be made LAST
                if (counter == toBeRotated - 1)
                {
                    newLastNode = node;
                }

                node = node.Next;
                counter++;
            }

            // Last node is the new linking node.
            var linkingNode = node;

            // 1. Link the last node to old HEAD now.
            // 2. Reset the HEAD to new node.
            // 3. Set NEW LAST NODE's next to NULL
            linkingNode.Next = list.Head;
            list.Head        = newLastNode.Next;
            newLastNode.Next = null;

            list.Print();
        }
        /// <summary>
        /// ReverseLinkedListInGroupsOfGivenSize, TC: O(n*groupsize), SC: O(1)
        /// https://www.geeksforgeeks.org/reverse-a-list-in-groups-of-given-size/
        /// </summary>
        public static void ReverseLinkedListInGroupsOfGivenSize()
        {
            var list = LLUtility.CreateSinglyLinkedList(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }.Cast <int>());

            list.Print();

            // counter for iteration tracking. Groupsize as given!
            int groupSize = 4, counter;

            // Keep 5 variables. For reversal, usual concept of 3 vars: previous, current and next.
            //
            // intervalLinkNode is for keeping it the first node (which will become last of the group)
            // and will point to (LAST element of the upcoming group - which will become FIRST of that upcoming group)
            //
            // changerNode is for shifting the intervalLinkNode to "NEW" Last node of the reversed group
            // to point to (LAST element of the upcoming group - which will become FIRST of that upcoming group)
            ISinglyNode <int> previous, current, next, intervalLinkNode, changerNode;

            previous = current = next = intervalLinkNode = changerNode = null;

            // this is just to RESET the Head to last element of the first group.
            // After it is false, it will be useless.
            var flag = true;

            // Everytime for reversal take 3 elements. Previous as 1st element, Current as 2nd element
            previous = list.Head;
            current  = previous.Next;

            while (current != null)
            {
                counter = 1;

                /* On start, we have interval node as NULL but in next iterations we will have it as
                 * FIRST node of the group which will become LAST after reversal. This will then point
                 * to FIRST node of the upcoming group (which will actually be the LAST element of the
                 * upcoming group before reversal)
                 */
                if (intervalLinkNode != null)
                {
                    intervalLinkNode.Next = previous;
                }

                // Taking this to shift the intervalLinkNode as to Last node of the group.
                // Just for shifting after each iteration.
                changerNode = previous;

                // Iterate till entire group is reversed and you have no more left. i.e. multiple of group size
                // OR you have an incomplete group at the end, so we will break from the loop.
                while (current != null && counter < groupSize)
                {
                    /* Save the chain ahead of Current.
                     * Reverse the flow. Current -> Previous
                     * Shift the previous ahead to current now
                     */
                    next         = current.Next;
                    current.Next = previous;

                    // shift counters by one node
                    previous = current;
                    current  = next;
                    counter++;
                }

                if (flag)
                {
                    /* set the intervalnode to Head because this will point to new node now
                     * as it has become last element of the first group.
                     * Set Head to the last element of the first group (this is now first element)
                     *
                     * Disable flag.
                     */
                    intervalLinkNode = list.Head;
                    list.Head        = previous;
                    flag             = !flag;
                }
                else
                {
                    /* Connect the intervalNode (which is of the last group) to New _reversed_ first
                     * node of current group.
                     * Shift the interval node to First element (previous) of the current group
                     * which has now become the last element after reversal.
                     */
                    intervalLinkNode.Next = previous;
                    intervalLinkNode      = changerNode;
                }


                // shift counters to first element of next node
                // just like we started inside the inner while loop
                previous = current;

                /* reached the end of the list? then set the intervalNode Next to null
                 * mark the end of the list. Come out now!
                 */
                if (current == null)
                {
                    intervalLinkNode.Next = null;
                    break;
                }

                /* If we have completed the group reversal (no of elements are multiple of group size).
                 * Then link the interval node to first element of reversed group. and it will
                 * automatically come out since current has become NULL.
                 */
                current = previous.Next;
                if (current == null)
                {
                    intervalLinkNode.Next = previous;
                }
            }

            list.Print();
        }