Skip to content

Commit

Permalink
Day-61 One DP problem and finished chap 2 of CTCI2
Browse files Browse the repository at this point in the history
  • Loading branch information
mandliya committed Oct 16, 2015
1 parent d002cf2 commit e389c7b
Show file tree
Hide file tree
Showing 5 changed files with 503 additions and 4 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

| Current Status| Stats |
| :------------: | :----------: |
| Total Problems | 87 |
| Current Streak | 60 days |
| Longest Streak | 60 ( August 17, 2015 - October 15, 2015 ) |
| Total Problems | 90 |
| Current Streak | 61 days |
| Longest Streak | 61 ( August 17, 2015 - October 16, 2015 ) |

</center>

Expand Down Expand Up @@ -88,12 +88,17 @@ Include contains single header implementation of data structures and some algori
| Problem 2-3: Implement an algorithm to delete a node in the middle of a singly linked list | [2-3-delete-middle-node.cpp](cracking_the_coding_interview_problems/2-3-delete-middle-node.cpp)|
| Problem 2-4: Partition a linked list around a value x, all the nodes smaller than x come before all the nodes greater than equal to x | [2-4-partition.cpp](cracking_the_coding_interview_problems/2-4-partition.cpp)|
| Problem 2-5: You have two numberse represented by a linked list where each node contains a single digit. The digits are stored in reversed order, such that 1's digits are at the head of the list. Write a function that adds the two numbers and returns the sum as a linked list.Example:<ul><li>Input: ( 7 --> 1 --> 6 ) + ( 5 --> 9 --> 2 ) that is 617 + 295</li></ul><ul><li>Output: ( 2 --> 1 --> 9 ) i.e. 912.</li></ul><ul><li> FOLLOW UP : Suppose the lists are stored in forward order, Repeat the above problem.</ul></li><ul><li>Input: ( 6 --> 1 --> 7 ) + ( 2 --> 9 --> 5 ) i.e. 617 + 295</li></ul><ul><li> Output: ( 9 --> 1 --> 2 ) i.e. 912.</li></ul><ul><li>Implement it recursively and iteratively.</li></ul> | [2-5-add-lists.cpp](cracking_the_coding_interview_problems/2-5-add-lists.cpp) |
| Problem 2-6: Determine if linked list is palindrome( 2 iterative and one recursive approach | [2-6-palindrome.cpp](cracking_the_coding_interview_problems/2-6-palindrome.cpp) |
| Problem 2-7: Determine if two singly linked list intersect, if yes, return the intersecting node| The intersection is defined based on reference not on values| [2-7-intersection.cpp](cracking_the_coding_interview_problems/2-7-intersection.cpp)|
| Problem 2-8: Detect if the linked list have a loop, Find the start node of the loop and remove the loop| [2-8-loop-detection.cpp](cracking_the_coding_interview_problems/2-8-loop-detection.cpp)

###Dynamic Programming Problems
| Problem | Solution |
| :------------ | :----------: |
| N<sup>th</sup> Fibonacci term using different memoization techniques | [fibonacci.cpp](dynamic_programming_problems/fibonacci.cpp)|
| Longest Common Subsequence Problem | [lcs.cpp](dynamic_programming_problems/lcs.cpp) |
| Longest Common Subsequence Problem | [lcs.cpp](dynamic_programming_problems/lcs.cpp) |
| Maximum Value Contigous Subsequence Problem [wiki](https://en.wikipedia.org/wiki/Maximum_subarray_problem)| [max_subsequence.cpp](dynamic_programming_problems/max_subsequence.cpp)|
| Catalan number - Count the number of possible Binary Search Trees with n keys | [catalan_number.cpp](dynamic_programming_problems/catalan_number.cpp)|

### Tree Problems
| Problem | Solution |
Expand Down
253 changes: 253 additions & 0 deletions cracking_the_coding_interview_problems/2-6-palindrome.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/**
* Cracking the coding interview edition 6
* Implement a function to check if a list is a palindrome.
*
* Approach 1: Reverse the half the list and compare with other half.
* Approach 2: Iterative Approach
* - Push half the list in stack,
* - Compare the rest of the list by popping off from the stack
* Approach 3: Recursive Approach
*/

#include <iostream>
#include <stack>

struct Node {
char data;
Node * next;
Node ( char c ) : data{ c }, next{ nullptr } { }
};

/**
* [insert helper routine to insert new node at head]
* @param head [current head of the list]
* @param c [new node's data]
*/
void insert( Node * & head, char c ) {
Node * newNode = new Node(c);
newNode->next = head;
head = newNode;
}

/**
* [printList = helper routine to print the list]
* @param head [head of the list]
*/
void printList( Node * head ) {
while( head ) {
std::cout << head->data << "-->";
head = head->next;
}
std::cout << "nullptr" << std::endl;
}


/**
* [reversedList helper routine to reverse a list]
* @param head [head of current list]
* @return [reversed list's head]
*/
void reverse( Node * & head ) {
if ( head == nullptr || (head && (head->next == nullptr))){
return;
}
Node * newHead = nullptr;
Node * nextNode = nullptr;
while ( head ) {
nextNode = head->next;
head->next = newHead;
newHead = head;
head = nextNode;
}
head = newHead;
}


/**
* [isPallindromeIter1 - Iteratively determine if list is palindrome using reversing the list]
* @param head [Head node of the list]
* @return [True if list is palindrome, false if not]
*/
bool isPalindromeIter1( Node * head ) {

// if list is empty or just contains one node.
if ( head == nullptr || head->next == nullptr ) {
return true;
}

//step1 figure out middle node.
Node * ptr1 = head;
Node * ptr2 = head;
Node * middleNode = nullptr;

while( ptr2 && ptr1 && ptr1->next) {
ptr1 = ptr1->next->next;
ptr2 = ptr2->next;
}

//in case of odd number of nodes, skip the middle one
if ( ptr1 && ptr1->next == nullptr ) {
ptr2 = ptr2->next;
}


//reverse the second half of the list
reverse(ptr2);

middleNode = ptr2;
// now compare the two halves
ptr1 = head;

while( ptr1 && ptr2 && ptr1->data == ptr2->data ) {
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}

//reverse the list again.
reverse(middleNode);

if ( ptr2 == nullptr ) {
return true;
} else {
return false;
}
}

/**
* [isPalindromeIter2 - Iteratively determine if list is palindrome using a stack]
* @param head [Head node of the list]
* @return [True if list is palindrome, false if not]
*/
bool isPalindromeIter2( Node * head ) {
// if list is empty or just contains one node.
if ( head == nullptr || head->next == nullptr ) {
return true;
}

Node * ptr1 = head;
Node * ptr2 = head;

//pushing the first half of list to stack.
std::stack<Node*> nodeStack;

while( ptr2 && ptr1 && ptr1->next ) {
ptr1 = ptr1->next->next;
nodeStack.push(ptr2);
ptr2 = ptr2->next;
}

//in case of odd number of nodes, skip the middle one
if ( ptr1 && ptr1->next == nullptr ) {
ptr2 = ptr2->next;
}

// Now compare the other half of the list with nodes
// we just pushed in stack

while(!nodeStack.empty() && ptr2) {
Node * curr = nodeStack.top();
nodeStack.pop();
if (curr->data != ptr2->data) {
return false;
}
ptr2 = ptr2->next;
}

return true;
}


/**
* [isPalindromeRecurHelper - Recursive approach to determine if list is palindrome]
* Idea is to use two pointers left and right, we move left and right to reduce
* problem size in each recursive call, for a list to be palindrome, we need these two
* conditions to be true in each recursive call.
* a. Data of left and right should match.
* b. Remaining Sub-list is palindrome.
* We are using function call stack for right to reach at last node and then compare
* it with first node (which is left).
* @param left [left pointer of sublist]
* @param right [right pointer of sublist]
* @return [true if sublist is palindrome, false if not]
*/
bool isPalindromeRecurHelper( Node * & left, Node * right ) {
//base case Stop when right becomes nullptr
if ( right == nullptr ) {
return true;
}

//rest of the list should be palindrome
bool isPalindrome = isPalindromeRecurHelper(left, right->next);
if (!isPalindrome) {
return false;
}

// check values at current node.
isPalindrome = ( left->data == right->data );

// move left to next for next call.
left = left->next;

return isPalindrome;
}

bool isPalindromeRecur( Node * head ) {
return isPalindromeRecurHelper(head, head);
}


int main()
{
Node * head1 = nullptr;
insert( head1, 'a' );
insert( head1, 'b' );
insert( head1, 'c' );
insert( head1, 'c' );
insert( head1, 'b' );
insert( head1, 'a' );
std::cout << "List 1: ";
printList( head1 );
if ( isPalindromeRecur( head1 ) ) {
std::cout << "List 1 is pallindrome list\n";
} else {
std::cout << "List 1 is not a pallindrome list\n";
}
std::cout << "List 1: ";
printList( head1 );

Node * head2 = nullptr;
insert( head2, 'r');
insert( head2, 'a');
insert( head2, 'd');
insert( head2, 'a');
insert( head2, 'r');
std::cout << "List 2: ";
printList( head2 );

if ( isPalindromeRecur( head2 ) ) {
std::cout << "List 2 is pallindrome list\n";
} else {
std::cout << "List 2 is not a pallindrome list\n";
}

std::cout << "List 2: ";
printList( head2 );

Node * head = nullptr;
insert( head, 'a' );
insert( head, 'b' );
insert( head, 'c' );
insert( head, 'b' );
insert( head, 'd' );
std::cout << "List 3: ";
printList( head );

if ( isPalindromeRecur( head ) ) {
std::cout << "List 3 is pallindrome list\n";
} else {
std::cout << "List 3 is not a pallindrome list\n";
}
std::cout << "List 3: ";
printList( head );
return 0;
}
98 changes: 98 additions & 0 deletions cracking_the_coding_interview_problems/2-7-intersection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* Cracking the coding interview edition 6
* Problem 2.7 Intersection
* Given two linked lists, if they both intersect at some point.
* Find out the intersecting point else return nullptr.
* Intersection is defined based on reference not value.
*/

#include <iostream>
#include <cmath>

struct Node {
int data;
Node * next;
Node( int d ) : data{ d }, next{ nullptr } { }
};

/**
* [printList Helper routine to print list]
* @param head [head of the list]
*/
void printList( Node * head )
{
while( head ) {
std::cout << head->data << "-->";
head = head->next;
}
std::cout << "NULL" << std::endl;
}

int listLen( Node * head )
{
int count = 0;
while( head ) {
head = head->next;
count++;
}
return count;
}

/**
* [intersectionPoint Returns the point of intersection of two lists]
* @param head1 [ head of list 1 ]
* @param head2 [ head of list 2 ]
* @return [ Intersecting node, if lists intersect, else nullptr]
*/
Node * intersectionPoint( Node * head1, Node * head2 )
{
int len1 = listLen(head1);
int len2 = listLen(head2);
//figure out the bigger list ( and smaller )
//ptr points to bigger list, let us move the difference
//between the two.
Node * ptr1 = ( len1 > len2 ) ? head1 : head2;
Node * ptr2 = ( len1 > len2 ) ? head2 : head1;
int i = 0;
while ( i < std::abs(len1 - len2) && ptr1 ) {
ptr1 = ptr1->next;
++i;
}
//Now we have equal nodes to travel on both the nodes
// traversing and comparing the pointers.

while( ptr1 && ptr2 ) {
if ( ptr1 == ptr2 ) {
return ptr1;
}
ptr1 = ptr1->next;
ptr2 = ptr2->next;
}
return nullptr;
}


int main()
{
Node * list1 = new Node(3);
list1->next = new Node(6);
list1->next->next = new Node(9);
list1->next->next->next = new Node(12);
list1->next->next->next->next = new Node(15);
list1->next->next->next->next->next = new Node(18);

Node * list2 = new Node(7);
list2->next = new Node(10);
list2->next->next = list1->next->next->next;

printList(list1);
printList(list2);

Node * intersectingNode = intersectionPoint( list1 , list2 );
if (intersectingNode) {
std::cout << "Intersecting Node of lists is :" << intersectingNode->data << std::endl;
} else {
std::cout << "Lists do not interset" << std::endl;
}
return 0;
}
Loading

0 comments on commit e389c7b

Please sign in to comment.