├── .gitignore ├── Ch 1.Arrays And Strings ├── 1.Is Unique │ └── 1. Is_unique.cpp ├── 10.Ouicksort.cpp ├── 2.Check Permutation │ └── 1.Check_Permutation.cpp ├── 3.Palindrome Permutation │ └── Palindrome Permutation.cpp ├── 3.URLify │ ├── URLify.cpp │ └── URLify2.cpp ├── 4.Palindrome_Permutation │ └── 4-pallindrome-permutations.cpp ├── 5. One Away │ └── 5.One Away.cpp ├── 5.One_Away │ └── 5-one-edit-away.cpp ├── 6.String_Compression │ └── 6.string_compression.cpp ├── 7.Rotate_matrix │ └── 7.rotate_matrix.cpp ├── 8.Zero_matrix │ └── 8.zero_matrix.cpp └── 9.String_rotation │ └── 9.string_rotation.cpp ├── Ch 10. Sorting and Searching └── 10.1 - sortedMerge.cpp ├── Ch 12. C++ ├── k_strings.txt └── print_k_lines.cpp ├── Ch 17. Hard ├── Q17_01_Add_Without_Plus │ └── addWithoutPlus.cpp └── Q17_21_Volume_of_Histogram │ └── histogramVolume.cpp ├── Ch 4. Trees and Graphs ├── 4-1-Route-Between-Nodes.cpp ├── 4-2-Minimal-Tree.cpp ├── 4.10_Check_Subtree.cpp ├── 4.2_Minimal_Tree.cpp ├── 4.4_Check_Balanced.cpp ├── 4.5_Validate_BST.cpp ├── 4.6_Successor.cpp └── C++14 │ ├── 4.1-RouteBetweenNodes.cpp │ ├── 4.10i-CheckSubtree.cpp │ ├── 4.10r-CheckSubtree.cpp │ ├── 4.11-RandomNode.cpp │ ├── 4.11m-RandomTree.cpp │ ├── 4.12-PathsWithSum.cpp │ ├── 4.2-MinimalTree.cpp │ ├── 4.3-ListOfDepths.cpp │ ├── 4.4-CheckBalanced.cpp │ ├── 4.5-ValidateBST.cpp │ ├── 4.6-Successor.cpp │ ├── 4.7-BuildOrder.cpp │ ├── 4.7d-BuildOrder.cpp │ ├── 4.8-FirstCommonAncestor.cpp │ ├── 4.8p-FirstCommonAncestor.cpp │ ├── 4.9-BSTSequences.cpp │ ├── graph.hpp │ ├── graphtestutils.hpp │ ├── tree.hpp │ ├── treenode.hpp │ ├── treenodeiterator.hpp │ └── treetestutils.hpp ├── Ch 5. Bit Manipulation └── C++14 │ ├── 5.1-Insertion.cpp │ ├── 5.2-BinaryToString.cpp │ ├── 5.3-FlipBitToWin.cpp │ ├── 5.4-NextNumber.cpp │ └── bitutils.hpp ├── Ch 6. Math and Logic Puzzles ├── 7.The Apocalypse │ └── The Apocalypse.cpp └── Intro │ ├── Prime.cpp │ └── SieveOfEratosthenes.cpp ├── Ch 7.OOD └── 1.Deck Of Cards │ ├── BlackJackCard.cpp │ ├── BlackJackHand.cpp │ └── card.cpp ├── Chapter-10-Sorting-and-Searching ├── 10-1-Sorted-Merge │ └── 10-1-Sorted-Merge.cpp └── 10-2-Group-Anagrams │ └── 10-2-Group-Anagrams.cpp ├── Chapter-16-moderate ├── test_word_freq └── word_freq.cpp ├── Chapter-3-Stacks-and-Queues ├── 3.1-Three-in-One │ ├── FixedMultiStack.cpp │ └── FixedMultiStack.h ├── 3.2-Stack-Min │ ├── Stack.cpp │ ├── Stack.h │ ├── StackNode.cpp │ └── StackNode.h ├── 3.2_stack_min.cpp ├── 3.3_stack_of_plastes ├── 3.4_queue_via_stacks ├── 3.5_sort_stack ├── 3.6_animal_shelter └── C++14 │ ├── 3.2-StackMin.cpp │ ├── 3.3-StackOfPlates.cpp │ ├── 3.3-StackOfPlatesFU.cpp │ ├── 3.4-QueueViaStacks.cpp │ ├── 3.5-SortStack.cpp │ ├── 3.6-AnimalShelter.cpp │ ├── queue.hpp │ └── stack.hpp ├── Chapter-4-tree-and-graph ├── 4.10_check_subtree.cpp ├── 4.11_random_node.cpp ├── 4.2_minimal_tree.cpp ├── 4.3_list_of_depths.cpp ├── 4.4_check_balanced.cpp ├── 4.5_validate_BST.cpp ├── 4.6_successor.cpp ├── 4.7_build_order.cpp ├── 4.8_first_common_ancestor.cpp └── 4.9_BST_sequences.cpp ├── README.md ├── chapter-2-Linked-Lists ├── 2-1-remove-dups.cpp ├── 2-2-kthToLast.cpp ├── 2-3-delete-middle-node.cpp ├── 2-4-partition.cpp ├── 2-5-add-lists.cpp ├── 2-6-palindrome.cpp ├── 2-7-intersection.cpp ├── 2-8-loop-detection.cpp └── 2.4cpp_partition └── chapter-8-recursion-and-Dynamic-Programming ├── 8-1-Triple-Step.cpp ├── 8-11-Coins.cpp ├── 8-2-Robot-in-a-Grid.cpp ├── 8-3-Magic-Index.cpp ├── 8-5-Recursive-Multiply.cpp ├── 8-7-Permutations-without-Dups.cpp ├── 8-8-Permutation-with-dups-alt.cpp ├── 8-8-Permutation-with-dups.cpp ├── 8-9-parens-alt.cpp ├── 8-9-parens.cpp ├── 8.10_Paint_Fill.cpp ├── 8.1_Triple_Step.cpp ├── 8.2_Grid_Paths.cpp ├── 8.3_Magic_Index.cpp ├── 8.4_Power_Set.cpp ├── 8.5_Recursive_Multiply.cpp ├── 8.6_Tower_of_Hanoi.cpp ├── 8.7_Permutations_without_Dups.cpp ├── 8.8_Permutations_with_Dups.cpp └── 8.9_Parens.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/1.Is Unique/1. Is_unique.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include // for sort() 6 | 7 | using namespace std; 8 | 9 | bool isUniqueChars(const string &str){ 10 | if (str.length() > 128){ 11 | return false; 12 | } 13 | vector char_set(128); 14 | for (int i = 0; i < str.length(); i++){ 15 | int val = str[i]; 16 | if (char_set[val]){ 17 | return false; 18 | } 19 | char_set[val] = true; 20 | } 21 | return true; 22 | } 23 | 24 | bool isUniqueChars_bitvector(const string &str) { 25 | //Reduce space usage by a factor of 8 using bitvector. 26 | //Each boolean otherwise occupies a size of 8 bits. 27 | bitset<256> bits(0); 28 | for(int i = 0; i < str.length(); i++) { 29 | int val = str[i]; 30 | if(bits.test(val) > 0) { 31 | return false; 32 | } 33 | bits.set(val); 34 | } 35 | return true; 36 | } 37 | bool isUniqueChars_noDS( string str) { 38 | 39 | sort(str.begin(), str.end()); // O(nlogn) sort from 40 | 41 | bool noRepeat = true; 42 | for ( int i = 0 ; i < str.size() - 1; i++){ 43 | if ( str[i] == str[i+1] ){ 44 | noRepeat = false; 45 | break; 46 | } 47 | } 48 | 49 | return noRepeat; 50 | } 51 | 52 | int main(){ 53 | vector words = {"abcde", "hello", "apple", "kite", "padle"}; 54 | for (auto word : words) 55 | { 56 | cout << word << string(": ") << boolalpha << isUniqueChars(word) < 2 | using namespace std; 3 | 4 | int partition(int *arr,int low,int high); 5 | 6 | void quick(int *arr,int low,int high){ 7 | if(high>low){ 8 | int cnst=partition(arr,low,high); 9 | quick(arr,low,cnst-1); 10 | quick(arr,cnst+1,high); 11 | } 12 | } 13 | 14 | int partition(int *arr,int low,int high){ 15 | int pivot=arr[low]; 16 | int i=low,j=high+1; 17 | 18 | while(ipivot); 29 | 30 | if(i>n; 54 | 55 | int arr[n]; 56 | cout<<"Enter array elements "<>arr[i]; 60 | 61 | quick(arr,0,n-1); 62 | for(int i=0;i 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | bool arePermutation(string str1,string str2) 7 | { 8 | // Get lengths of both strings 9 | int n1 = str1.length(); 10 | int n2 = str2.length(); 11 | 12 | // If length of both strings is not same, then they 13 | // cannot be anagram 14 | if (n1 != n2) 15 | return false; 16 | 17 | // Sort both strings 18 | sort(str1.begin(), str1.end()); 19 | sort(str2.begin(), str2.end()); 20 | // Compare sorted strings 21 | for (int i = 0; i < n1; i++) 22 | if (str1[i] != str2[i]) 23 | return false; 24 | 25 | return true; 26 | } 27 | 28 | bool arePermutation_2(const string &str1, const string &str2) { 29 | if(str1.length() != str2.length()) 30 | return false; 31 | int count[256]={0}; 32 | for(int i = 0; i < str1.length(); i++) { 33 | int val = str1[i]; 34 | count[val]++; 35 | } 36 | for(int i = 0; i < str2.length(); i++) { 37 | int val = str2[i]; 38 | count[val]--; 39 | if(count[val]<0) 40 | return false; 41 | } 42 | return true; 43 | } 44 | int main() { 45 | // Test Method 1 - Using sort 46 | cout << "Method 1 - Using sort" << endl; 47 | string str1 = "testest"; 48 | string str2 = "estxest"; 49 | if(arePermutation(str1, str2)) 50 | cout << str1 <<" and " << str2 << " are permutation of each other" << endl; 51 | else 52 | cout << str1 <<" and " << str2 << " are not permutation of each other" << endl; 53 | str1 = "hello"; 54 | str2 = "oellh"; 55 | if(arePermutation(str1, str2)) 56 | cout << str1 <<" and " << str2 << " are permutation of each other" << endl; 57 | else 58 | cout << str1 <<" and " << str2 << " are not permutation of each other" << endl; 59 | 60 | //Test Method 2 - Using character count 61 | cout << "Method 2 - Using character count" << endl; 62 | str1 = "testest"; 63 | str2 = "estxest"; 64 | if(arePermutation_2(str1, str2)) 65 | cout << str1 <<" and " << str2 << " are permutation of each other" << endl; 66 | else 67 | cout << str1 <<" and " << str2 << " are not permutation of each other" << endl; 68 | str1 = "hello"; 69 | str2 = "oellh"; 70 | if(arePermutation_2(str1, str2)) 71 | cout << str1 <<" and " << str2 << " are permutation of each other" << endl; 72 | else 73 | cout << str1 <<" and " << str2 << " are not permutation of each other" << endl; 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/3.Palindrome Permutation/Palindrome Permutation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int getCharNumber(const char & c){ 9 | int a = (int) 'a'; 10 | int z = (int) 'z'; 11 | int A = (int) 'A'; 12 | int Z = (int) 'Z'; 13 | int val = (int) c; 14 | if(a <= val && val <= z){ 15 | return val - 'a'; 16 | } 17 | else if(A <= val && val <= Z){ 18 | return val - 'A'; 19 | } 20 | return -1; 21 | } 22 | 23 | 24 | vector buildCharFrequencyTable(string phrase){ 25 | vector table(getCharNumber('z') - getCharNumber('a') + 1, 0); 26 | for(char &c : phrase){ 27 | int x = getCharNumber(c); 28 | if(x != -1){ 29 | table[x]++; 30 | } 31 | } 32 | return table; 33 | } 34 | 35 | 36 | bool checkMaxOneOdd(vector &table) 37 | { 38 | bool foundOdd = false; 39 | for (auto count : table) 40 | { 41 | if (count % 2 == 1) 42 | { 43 | if (foundOdd) 44 | { 45 | return false; 46 | } 47 | foundOdd = true; 48 | } 49 | } 50 | return true; 51 | } 52 | 53 | bool isPermutationOfPalindrome(const string &phrase) 54 | { 55 | vector table = buildCharFrequencyTable(phrase); 56 | return checkMaxOneOdd(table); 57 | } 58 | 59 | bool isPermutationOfPalindrome_bitwise(const string &phrase) 60 | { 61 | const int numChar = 26; 62 | bitset table(0); 63 | for (const char& c : phrase) 64 | { 65 | const int hash = getCharNumber(c); 66 | if (hash == -1) 67 | {continue;} 68 | table.flip(hash); 69 | } 70 | const int summary = table.to_ulong(); 71 | const bool isPowerOf2 = ((summary) & (summary-1)) == 0; 72 | return isPowerOf2; 73 | } 74 | 75 | #define TEST(pFunc, pattern) \ 76 | do { \ 77 | cout << "[" #pFunc "]" << endl; \ 78 | cout << "- Pattern: " << pattern << endl; \ 79 | cout << "- Result : " << pFunc(pattern) << endl; \ 80 | } while (0) 81 | 82 | int main(int argc, const char *argv[]) 83 | { 84 | vector patterns{ 85 | "", 86 | "a", 87 | "ab", 88 | "Tact Coa", 89 | "Rats live on no evil st", 90 | "Rats live on no evil star" 91 | }; 92 | for (auto& pattern: patterns) 93 | { 94 | TEST(isPermutationOfPalindrome, pattern); 95 | } 96 | for (auto& pattern: patterns) 97 | { 98 | TEST(isPermutationOfPalindrome_bitwise, pattern); 99 | } 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/3.URLify/URLify.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Cracking the coding interview Edition 6 3 | * Problem 1.3 URLify --> Replace all the spaces in a string with '%20'. 4 | * Assumption : We have enough space to accomodate addition chars 5 | * Preferebly in place 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | * Function : urlify 13 | * Args : string long enough to accomodate extra chars + true len 14 | * Return : void (in place transformation of string) 15 | */ 16 | 17 | void urlify(char *str, int len) 18 | { 19 | int numOfSpaces = 0; 20 | int i = 0, j = 0; 21 | for ( i = 0; i < len; ++i ) { 22 | if (str[i] == ' ') { 23 | ++numOfSpaces; 24 | } 25 | } 26 | 27 | int extendedLen = len + 2 * numOfSpaces; 28 | i = extendedLen - 1; 29 | for( j = len - 1; j >= 0; --j ) { 30 | if ( str[j] != ' ' ) { 31 | str[i--] = str[j]; 32 | } else { 33 | str[i--] = '0'; 34 | str[i--] = '2'; 35 | str[i--] = '%'; 36 | } 37 | } 38 | } 39 | 40 | int main() 41 | { 42 | char str[] = "Mr John Smith "; //String with extended length ( true length + 2* spaces) 43 | std::cout << "Actual string : " << str << std::endl; 44 | urlify(str, 13); //Length of "Mr John Smith" = 13 45 | std::cout << "URLified string : " << str << std::endl; 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/3.URLify/URLify2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | using namespace std; 5 | /* in this solution we are using C++ stl/std style */ 6 | string URLify(const string &str) 7 | { 8 | int spacesCnt = 0; 9 | string res; 10 | 11 | for (auto &is : str) { 12 | if (is == ' ') { 13 | ++spacesCnt; 14 | } 15 | } 16 | // cout << "# of spaces: " << spacesCnt << endl; 17 | auto newSize = str.size() + 2*spacesCnt; 18 | res.resize(newSize); 19 | cout << " res new size is: " << res.size() << endl; 20 | int is=0, ir=0; 21 | while (is < str.size()) { 22 | if (str[is] != ' ') { 23 | res[ir] = str[is]; 24 | } 25 | else if (str[is] == ' ') { 26 | res[ir++] = '%'; 27 | res[ir++] = '2'; 28 | res[ir] = '0'; 29 | } 30 | ++is; ++ir; 31 | } 32 | return res; 33 | } 34 | 35 | int main() 36 | { 37 | string s = URLify("This is John Smith"); 38 | cout << " the new string is: " << s << endl; 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/5. One Away/5.One Away.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | bool isOneAway(string s1, string s2){ 6 | string a,b; 7 | a = s1.length() >= s2.length() ? s1 : s2; 8 | b = s1.length() < s2.length() ? s1 : s2; 9 | int len1, len2; 10 | len1 = a.length(); 11 | len2 = b.length(); 12 | if(abs(len1-len2)>1) 13 | return false; 14 | 15 | bool flag = false; 16 | for(int i=0,j=0;i possible edit is replace. 11 | * If there are more than one mismatch, return false 12 | * 13 | * 2. Case when One string is bigger than another 14 | * Smaller string ------------> Bigger String 15 | * insert 16 | * delete 17 | * smaller string <----------- Bigger String 18 | * 19 | * Idea is check if there are more than one mismatch discounting the already 20 | * difference in the string. Therefore for first mismatch we do not move the pointer 21 | * pointing to smaller string, and then expect it to match from next char of bigger 22 | * string. 23 | */ 24 | 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | bool oneEditAway( const std::string & str1, const std::string & str2 ) 33 | { 34 | if ( std::abs( int(str1.length()) - int(str2.length())) > 1 ) { 35 | return false; 36 | } 37 | 38 | int len1 = str1.length(); 39 | int len2 = str2.length(); 40 | std::string smaller = len1 < len2 ? str1 : str2; 41 | std::string bigger = len1 < len2 ? str2 : str1; 42 | 43 | unsigned int i = 0, j = 0; 44 | bool mismatchDone = false; 45 | while ( i < smaller.length() && j < bigger.length() ) 46 | { 47 | if ( smaller[i] != bigger[j] ) { 48 | if (mismatchDone) { 49 | return false; 50 | } 51 | mismatchDone = true; 52 | if ( len1 == len2 ) { 53 | ++i; //case of replace 54 | } 55 | } else { 56 | ++i; //move short pointer if its a match, dont move it in case of first mismatch 57 | } 58 | ++j; //always move long string pointer. 59 | } 60 | return true; 61 | } 62 | 63 | 64 | void translate( bool result, const std::string str1, const std::string str2 ) 65 | { 66 | if (result == true ) { 67 | std::cout << str1 << " and " << str2 << " are one edit away\n"; 68 | } else { 69 | std::cout << str1 << " and " << str2 << " are not one edit away\n"; 70 | } 71 | } 72 | 73 | int main() 74 | { 75 | translate ( oneEditAway("pale", "ple"), "pale", "ple" ); 76 | translate ( oneEditAway("pales", "pale"), "pales", "pale" ); 77 | translate ( oneEditAway("pale", "pales"), "pale", "pales" ); 78 | translate ( oneEditAway("pale", "bale"), "pale", "bale" ); 79 | translate ( oneEditAway("pale", "bake"), "pale", "bake" ); 80 | return 0; 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/6.String_Compression/6.string_compression.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Cracking the coding interview edition 6 3 | * Problem 1-6 Implement a method to perform basic string compression. 4 | * Example string aabcccccaaa should be compressed to a2b1c5a3, 5 | * however if compressed string is bigger than original string, return original string 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | 12 | std::string compress(std::string str) 13 | { 14 | size_t original_length = str.length(); 15 | if (original_length < 2) { 16 | return str; 17 | } 18 | std::string out{""}; 19 | int count = 1; 20 | for( size_t i = 1; i < original_length; ++i ) { 21 | if (str[i-1] == str[i]) { 22 | ++count; 23 | } else { 24 | out += str[i-1]; 25 | out += std::to_string(count); 26 | count = 1; 27 | } 28 | if (out.length() >= original_length) { 29 | return str; 30 | } 31 | } 32 | out += str[original_length-1]; 33 | out += std::to_string(count); 34 | if (out.length() >= original_length) { 35 | return str; 36 | } 37 | return out; 38 | } 39 | 40 | int main() 41 | { 42 | std::string str, out; 43 | std::cout << "Enter a string:\n"; 44 | std::cin >> str; 45 | out = compress(str); 46 | if (str.compare(out)) { 47 | std::cout << str << " can be compressed to " << out << std::endl; 48 | } else { 49 | std::cout << str << " can not be compressed\n"; 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/7.Rotate_matrix/7.rotate_matrix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Cracking the coding interview edition 6 3 | * Problem 1.7 Rotate a matrix by 90' clockwise ( or anticlockwise). 4 | * Solution : I have done it two ways. 5 | * Approach 1: Take transpose of matrix and then reverse the rows for clockwise 90' rotation. 6 | * Obviously if we reverse the columns we will get anticlockwise 90' rotation. 7 | * Approach 2: As mentioned in the book, rotating invididual elements layer by layer. 8 | * I have solved it perform anticlockwise 90' rotation, it can be done similarly for clockwise rotatation. 9 | */ 10 | #include 11 | 12 | void helper_transpose(int **matrix, int N) 13 | { 14 | for( int i = 0; i < N; ++i ) { 15 | for( int j = i+1; j < N; ++j ) { 16 | if ( i != j ) { 17 | std::swap(matrix[i][j], matrix[j][i]); 18 | } 19 | } 20 | } 21 | } 22 | 23 | void helper_reverse( int * row, int N ) { 24 | for ( int i = 0; i < N/2; ++i ) { 25 | std::swap(row[i], row[N-i-1]); 26 | } 27 | } 28 | 29 | void rotate1(int ** matrix, int N) { 30 | //transpose matrix 31 | helper_transpose(matrix, N); 32 | // reverse each row 33 | for ( int i = 0; i < N; ++i ) { 34 | helper_reverse(matrix[i], N); 35 | } 36 | } 37 | 38 | 39 | void rotate2( int ** matrix, int N ) { 40 | for( int i = 0; i < N/2; ++i ) { 41 | for( int j = i; j < N-i-1; ++j ) { 42 | int temp = matrix[i][j]; 43 | matrix[i][j] = matrix[j][N-i-1]; 44 | matrix[j][N-i-1] = matrix[N-i-1][N-j-1]; 45 | matrix[N-i-1][N-j-1]= matrix[N-j-1][i]; 46 | matrix[N-j-1][i] = temp; 47 | } 48 | } 49 | } 50 | 51 | void printMatrix( int ** matrix, int N) { 52 | for ( int i = 0; i < N; ++i ) { 53 | for( int j = 0; j < N; ++j ) { 54 | std::cout << matrix[i][j] << " "; 55 | } 56 | std::cout << std::endl; 57 | } 58 | } 59 | 60 | 61 | int main() { 62 | int N; 63 | std::cout << "Enter N for NxN matrix:"; 64 | std::cin >> N; 65 | int ** matrix = new int*[N]; 66 | for ( int i = 0; i < N; ++i ) { 67 | matrix[i] = new int[N]; 68 | } 69 | 70 | for ( int i = 0; i < N; ++i) { 71 | for ( int j = 0; j < N; ++j ) { 72 | std::cin >> matrix[i][j]; 73 | } 74 | } 75 | 76 | std::cout << "Rotated matrix by 90 (clockwise):\n"; 77 | rotate1(matrix, N); 78 | printMatrix(matrix, N); 79 | 80 | std::cout << "Rotated matrix again by 90(anticlockwise):\n"; 81 | rotate2(matrix, N); 82 | printMatrix(matrix, N); 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/8.Zero_matrix/8.zero_matrix.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview 1.8 3 | * Write a space efficient algorithm, such that if an element in MxN is 0, the entire row and column containing it are 0. 4 | * 5 | * Approach: 6 | * We can use a boolean matrix of MxN or a bit vector to mark row and columns to be nullified in first iteration, but it wont be space efficient. 7 | * More space efficient would be to first check first row and column and if any of them contains zero, mark them to be nullified using two boolearn vars 8 | * let's say firstRow and firstCol, and then iterate through rest of the matrix and store information in first row column elements, only when that row 9 | * and column is to be marked for nullified, this way we will only change values in first row and column which are already going to be 0 in final solution. 10 | */ 11 | 12 | #include 13 | 14 | void nullifyRow( int ** matrix, int N, int row ) { 15 | for ( int j = 0; j < N; ++j ) { 16 | matrix[row][j] = 0; 17 | } 18 | } 19 | 20 | void nullifyCol( int ** matrix, int M, int col ) { 21 | for ( int i = 0; i < M; ++i ) { 22 | matrix[i][col] = 0; 23 | } 24 | } 25 | 26 | 27 | void nullifyMatrix( int ** matrix, int M, int N ) { 28 | bool firstRow = false; 29 | 30 | //first row 31 | for( int i = 0; i < N; ++i ) { 32 | if ( matrix[0][i] == 0 ) { 33 | firstRow = true; 34 | break; 35 | } 36 | } 37 | 38 | //rest of the matrix 39 | for( int i = 1; i < M; ++i ) { 40 | bool nullifyThisRow = false; 41 | for ( int j = 0; j < N; ++j ) { 42 | if ( matrix[i][j] == 0 ) { 43 | matrix[0][j] = 0; 44 | nullifyThisRow = true; 45 | } 46 | } 47 | if (nullifyThisRow) 48 | nullifyRow(matrix, N, i); 49 | } 50 | 51 | //now we know which column to be nullify using information stored in previous step. 52 | //cols first 53 | for ( int j = 0; j < N; ++j ) { 54 | if ( matrix[0][j] == 0 ) { 55 | nullifyCol(matrix, M, j); 56 | } 57 | } 58 | 59 | //now first row 60 | if ( firstRow ) { 61 | nullifyRow(matrix, N, 0); 62 | } 63 | 64 | } 65 | 66 | void printMatrix( int ** matrix, int M, int N ) { 67 | for ( int i = 0; i < M; ++i ) { 68 | for ( int j = 0; j < N; ++j ) { 69 | std::cout << matrix[i][j] << " "; 70 | } 71 | std::cout << std::endl; 72 | } 73 | std::cout << std::endl; 74 | } 75 | 76 | 77 | int main() 78 | { 79 | int M, N; 80 | std::cout << "Enter number of rows:"; 81 | std::cin >> M; 82 | std::cout << "Enter number of cols:"; 83 | std::cin >> N; 84 | int ** matrix = new int*[M]; 85 | for ( int i =0; i < M; ++i ) { 86 | matrix[i] = new int[N]; 87 | } 88 | std::cout << "Provide M x N matrix \n"; 89 | for ( int i = 0; i < M; ++i ) { 90 | for ( int j = 0; j < N; ++j ) { 91 | std::cin >> matrix[i][j]; 92 | } 93 | } 94 | 95 | std::cout << "Matrix Before:\n"; 96 | printMatrix(matrix, M, N); 97 | nullifyMatrix(matrix, M, N); 98 | std::cout << "Matrix After:\n"; 99 | printMatrix(matrix, M, N); 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /Ch 1.Arrays And Strings/9.String_rotation/9.string_rotation.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview 1-9 3 | * You have a function "isSubstring" which checks whether a string is substring of another. 4 | * Given two strings s1 and s2, write code to check if s2 is a rotation of s1 using only one call to "isSubstring". 5 | * 6 | * Approach: 7 | * example s1 = "waterbottle", and s2 = "erbottlewat", clearly s2 is rotation of s1. 8 | * lets say s1 = xy ==> wat + erbottle 9 | * similarly s2 = yx ==> erbottle + wat 10 | * Therefore s1s1 = "waterbottlewaterbottle", clearly s2 is substring of s1s1 11 | * So if a string is formed by rotation of another string, it will always be substring of concatenated original string to itself. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | bool isRotation( std::string s1, std::string s2 ) { 18 | size_t len1 = s1.length(); 19 | size_t len2 = s2.length(); 20 | if ( len1 == 0 || len1 != len2 ) { 21 | return false; 22 | } 23 | std::string concatS1 = s1 + s1; 24 | if ( concatS1.find(s2) != std::string::npos ) { 25 | return true; 26 | } else { 27 | return false; 28 | } 29 | } 30 | 31 | int main() { 32 | std::string s1, s2; 33 | std::cout << "Enter string 1 : "; 34 | std::cin >> s1; 35 | std::cout << "Enter string 2 : "; 36 | std::cin >> s2; 37 | if ( isRotation(s1, s2) ) { 38 | std::cout << "Yes! " << s2 << " is rotation of " << s1 << std::endl; 39 | } else { 40 | std::cout << "No! " << s2 << " is not a rotation of " << s1 << std::endl; 41 | } 42 | return 0; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Ch 10. Sorting and Searching/10.1 - sortedMerge.cpp: -------------------------------------------------------------------------------- 1 | //======================================================================================================================================= 2 | // Name : sortedMerge.cpp 3 | // Author : Larissa Lages de Oliveira 4 | // Version : 5 | // Copyright : 6 | // Description : Given two sorted arrays, A and B, where A has a large enough bufer at the end to hold B, merge B into A in sorted order. 7 | //======================================================================================================================================= 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | vector merge(vector A, vector B, int lastA, int lastB) 14 | { 15 | int indexA = lastA; 16 | int indexB = lastB; 17 | int mergedIndex = lastA + lastB +1; 18 | 19 | while(indexB >= 0) 20 | { 21 | if(indexA >= 0 && A[indexA] > B[indexB]) 22 | { 23 | A[mergedIndex] = A[indexA]; 24 | indexA--; 25 | } 26 | else 27 | { 28 | A[mergedIndex] = B[indexB]; 29 | indexB--; 30 | } 31 | mergedIndex--; 32 | } 33 | return A; 34 | } 35 | 36 | int main() 37 | { 38 | vector b; 39 | b.push_back(5); 40 | b.push_back(7); 41 | b.push_back(11); 42 | b.push_back(20); 43 | b.push_back(25); 44 | 45 | vector a(13); 46 | a[0] = 10; 47 | a[1] = 12; 48 | a[2] = 14; 49 | a[3] = 22; 50 | a[4] = 23; 51 | a[5] = 26; 52 | a[6] = 28; 53 | a[7] = 30; 54 | 55 | a = merge(a,b,7,4); 56 | 57 | for(int i=0;i 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | void printKlines (const string &fn, int k) 10 | { 11 | if (k <= 0){ 12 | cout << "Error invalid K value " << endl; 13 | return; 14 | } 15 | string line; 16 | int cnt=0, first=0; ifstream ifs(fn); 17 | vector output; 18 | while(getline(ifs, line) && !line.empty()) { 19 | if(cnt >= k) { 20 | output[first] = line; 21 | first = (first+1)%k; 22 | } 23 | else { 24 | output.emplace_back(line); 25 | ++cnt; 26 | } 27 | } 28 | 29 | int start = first; 30 | for (int i=0; i< (cnt < k ? cnt : k); ++i, start = (start+1)%k) { 31 | cout << output[start] << endl; 32 | } 33 | 34 | } 35 | 36 | int main() 37 | { 38 | string fn;// = "k_strings.txt"; 39 | cout << "Type in the file name: " << endl; 40 | cin >> fn; 41 | 42 | cout << "Type the number of K last lines to print: " << endl; 43 | int k; 44 | cin >> k; 45 | printKlines(fn, k); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /Ch 17. Hard/Q17_01_Add_Without_Plus/addWithoutPlus.cpp: -------------------------------------------------------------------------------- 1 | //g++ -std=gnu++11 -o addWithoutPlus addWithoutPlus.cpp 2 | #include 3 | 4 | unsigned sum(unsigned x, unsigned y) { 5 | unsigned xor_result = x ^ y; 6 | unsigned carry = (x & y) << 1; 7 | if ( carry == 0 ) return xor_result; 8 | return sum(xor_result, carry); 9 | } 10 | 11 | int main(){ 12 | std::cout << "The sum of 7 + 8 is: " << sum(7,8) << std::endl; 13 | std::cout << "The sum of 33 + 4 is: " << sum(33,4) << std::endl; 14 | std::cout << "The sum of 11 + 5 is: " << sum(5,11) << std::endl; 15 | std::cout << "The sum of 31 + 7 is: " << sum(31,7) << std::endl; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Ch 17. Hard/Q17_21_Volume_of_Histogram/histogramVolume.cpp: -------------------------------------------------------------------------------- 1 | //g++ -std=gnu++11 -o histogramVolume histogramVolume.cpp 2 | #include 3 | #include 4 | 5 | typedef std::vector Histogram; 6 | 7 | double getVolume(Histogram &histogram){ 8 | // Skip 0's 9 | int i = 0; 10 | while ( i < histogram.size() - 1 && histogram[i] == 0 ) i++; 11 | int j = histogram.size() - 1; 12 | while ( j > i && histogram[j] == 0 ) j--; 13 | double volume = 0.0; 14 | while ( i != j ) { 15 | // Choose the smaller bar and advance to the center till we hit a bar 16 | // that is taller 17 | if ( histogram[i] < histogram [j] ){ 18 | double height = histogram[i]; 19 | double barsVolume = 0.0; 20 | int start = i++; 21 | while ( histogram[i] < height ) { 22 | barsVolume += histogram[i]; 23 | i++; 24 | } 25 | volume += (i - start - 1) * height - barsVolume; 26 | } else { 27 | double height = histogram[j]; 28 | double barsVolume = 0.0; 29 | int end = j--; 30 | while ( histogram[j] < height ){ 31 | barsVolume += histogram[j]; 32 | j--; 33 | } 34 | volume += (end - j - 1) * height - barsVolume; 35 | } 36 | } 37 | 38 | return volume; 39 | } 40 | 41 | 42 | int main(){ 43 | Histogram histogram {0, 0, 4, 0, 0, 6, 0, 0, 3, 0, 8, 0, 2, 0, 5, 2, 0, 3, 0, 0}; 44 | 45 | std::cout << "The volume of the histogram is: " << getVolume(histogram) << 46 | std::endl; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/4-1-Route-Between-Nodes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // Graph Class implementing a directed graph in adjacency list representation 7 | class Graph 8 | { 9 | public: 10 | int V; // number of vertices 11 | vector *adj; //adjacency list 12 | 13 | Graph(int V); 14 | void addEdge(int x, int y); 15 | bool isRoute(int x, int y); 16 | }; 17 | 18 | // Constructor 19 | Graph::Graph(int V) 20 | { 21 | this->V=V; 22 | this->adj = new vector[V]; 23 | } 24 | 25 | // add a directed edge from x to y 26 | void Graph::addEdge(int x, int y){ 27 | adj[x].push_back(y); 28 | } 29 | 30 | // isRoute function to determine if there is a route from x to y 31 | bool Graph::isRoute(int x, int y){ 32 | 33 | vector visited(V,false); 34 | queue q; 35 | 36 | q.push(x); 37 | 38 | while(!q.empty()){ 39 | int curr = q.front(); 40 | if (curr == y) 41 | { 42 | return true; 43 | } 44 | q.pop(); 45 | visited[curr]= true; 46 | int n_size =adj[curr].size(); 47 | for (int i = 0; i < n_size; ++i) 48 | { 49 | if (!visited[adj[curr][i]]) 50 | { 51 | q.push(adj[curr][i]); 52 | } 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | int main(){ 59 | 60 | Graph g(6); 61 | g.addEdge(5, 2); 62 | g.addEdge(5, 0); 63 | g.addEdge(4, 0); 64 | g.addEdge(4, 1); 65 | g.addEdge(2, 3); 66 | g.addEdge(3, 1); 67 | 68 | /* 69 | Test graph : 70 | 71 | 0 <---4---->1 72 | ^ ^ 73 | | | 74 | | | 75 | 5---->2---->3 76 | 77 | */ 78 | cout< 2 | using namespace std; 3 | 4 | struct Node { 5 | int data; 6 | Node *left; 7 | Node *right; 8 | Node(int x) : data(x), left(NULL), right(NULL) {} 9 | }; 10 | 11 | void preOrder(Node *node) 12 | { 13 | if (node == NULL) 14 | return; 15 | cout<< node->data <<" "; 16 | preOrder(node->left); 17 | preOrder(node->right); 18 | } 19 | 20 | Node* createMinimalBST(vector arr, int low, int high) 21 | { 22 | if (low > high) { 23 | return NULL; 24 | } 25 | int mid = (low + high) / 2; 26 | Node* node = new Node(arr[mid]); 27 | node->left = createMinimalBST(arr, low, mid - 1); 28 | node->right = createMinimalBST(arr, mid + 1, high); 29 | return node; 30 | } 31 | 32 | Node *createMinimalBST(vector arr) 33 | { 34 | if (arr.size() == 0) 35 | return NULL; 36 | return createMinimalBST( arr, 0, ((int)arr.size()) - 1 ); 37 | } 38 | 39 | int main() 40 | { 41 | int A[] = {1, 2, 3, 4, 5, 6, 7}; 42 | 43 | vector arr (A, A + sizeof(A) / sizeof(A[0]) ); 44 | /* 45 | Convert List to BST {1,2,3,4,5,6,7} 46 | 4 47 | / \ 48 | 2 6 49 | / \ / \ 50 | 1 3 5 7 51 | */ 52 | Node *root = createMinimalBST(arr); 53 | cout<<"\nPreOrder Traversal of constructed BST : "; 54 | preOrder(root); 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/4.10_Check_Subtree.cpp: -------------------------------------------------------------------------------- 1 | bool containTree(TreeNode* T1, TreeNode* T2) { 2 | string s1 = "", s2 = ""; 3 | inOrderString(T1, s1); 4 | inOrderString(T2, s2); 5 | return (s1.find(s2) != string::npos); 6 | } 7 | 8 | void inOrderString(TreeNode* root, string s) { 9 | if (root == nullptr) { 10 | s += "X"; 11 | return; 12 | } 13 | s += root->data; 14 | inOrderString(root->left, s); 15 | inOrderString(root->right, s); 16 | } 17 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/4.2_Minimal_Tree.cpp: -------------------------------------------------------------------------------- 1 | TreeNode* createMinBST(vector arr) { 2 | return createMinBST(arr, 0, arr.length() - 1); 3 | } 4 | 5 | TreeNode* createMinBST(vector arr, int start, int end) { 6 | if (start > end) { 7 | return null; 8 | } 9 | int mid = start + (end - start) / 2; 10 | TreeNode* newNode = new TreeNode(arr[mid]); 11 | newNode.left = createMinBST(arr, start, mid - 1); 12 | newNode.right = createMinBST(arr, mid + 1, end); 13 | return newNode; 14 | } 15 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/4.4_Check_Balanced.cpp: -------------------------------------------------------------------------------- 1 | int checkHeight(TreeNode* root) { 2 | if (root == nullptr) { 3 | return 0; 4 | } 5 | int leftHeight = checkHeight(root->left); 6 | if (leftHeight == -1) { 7 | return -1; 8 | } 9 | int rightHeight = checkHeight(root->right); 10 | if (rightHeight == -1) { 11 | return -1; 12 | } 13 | 14 | if (abs(leftHeight - rightHeight) > 1) { 15 | return -1; 16 | } 17 | else { 18 | return max(leftHeight, rightHeight) + 1; 19 | } 20 | } 21 | 22 | bool isBalanced(TreeNode* root) { 23 | return (checkHeight == -1); 24 | } 25 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/4.5_Validate_BST.cpp: -------------------------------------------------------------------------------- 1 | bool validateBST(TreeNode* root, int min, int max) { 2 | if (root == nullptr) { 3 | return true; 4 | } 5 | if (root->data < min || root->data > max) { 6 | return false; 7 | } 8 | return validateBST(root->left, min, root->data - 1) && validateBST(root->right, root->data + 1, max); 9 | } 10 | 11 | bool validateBST(TreeNode* root) { 12 | return validateBST(root, -2e9, 2e9); 13 | } 14 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/4.6_Successor.cpp: -------------------------------------------------------------------------------- 1 | TreeNode* mostLeft(TreeNode* root) { 2 | while (root->left != nullptr) { 3 | root = root->left; 4 | } 5 | return root; 6 | } 7 | 8 | TreeNode* findSuccessor(TreeNode* root) { 9 | if (root->right != nullptr) { 10 | return mostLeft(root->right); 11 | } 12 | TreeNode* child = root; 13 | TreeNode* ancestor = root->parent; 14 | while(ancestor != nullptr && ancestor->right == child) { 15 | child = ancestor; 16 | ancestor = child->parent; 17 | } 18 | return ancestor; 19 | } 20 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.1-RouteBetweenNodes.cpp: -------------------------------------------------------------------------------- 1 | // Route Between Nodes: Given a directed graph, design an algorithm to find out whether is a 2 | // route between to nodes. 3 | 4 | #include 5 | #include 6 | #include 7 | #include "graph.hpp" 8 | #include "graphtestutils.hpp" 9 | 10 | enum State {Unvisited, Visiting, Visited}; 11 | 12 | // Width visiting 13 | bool routeBetwenNodes(const Graph &graph, const Node &from, const Node &to) 14 | { 15 | if (from == to) 16 | return true; 17 | 18 | for (auto &n : graph.getNodes()) 19 | n->state = Unvisited; 20 | 21 | std::queue> queue; 22 | 23 | from->state = Visiting; 24 | queue.push(from); 25 | 26 | while (!queue.empty()) 27 | { 28 | Node n = queue.front(); 29 | queue.pop(); 30 | for (auto &c : n->getAdjacent()) 31 | { 32 | auto v = c.lock(); 33 | if (v && v->state == Unvisited) 34 | { 35 | if (v == to) 36 | return true; 37 | else 38 | { 39 | v->state = Visiting; 40 | queue.push(v); 41 | } 42 | } 43 | } 44 | n->state = Visited; 45 | } 46 | return false; 47 | } 48 | 49 | // Recursive visiting 50 | 51 | bool routeBetwenNodesWalker(const Graph &graph, const Node &from, const Node &to) 52 | { 53 | if (from == to) 54 | return true; 55 | 56 | from->state = Visited; 57 | 58 | for (auto &c : from->getAdjacent()) 59 | { 60 | auto node = c.lock(); 61 | if (node && node->state != Visited) 62 | { 63 | if (routeBetwenNodesWalker(graph, node, to)) 64 | return true; 65 | } 66 | } 67 | return false; 68 | } 69 | 70 | bool routeBetwenNodesR(const Graph &graph, const Node &from, const Node &to) 71 | { 72 | for (auto &n : graph.getNodes()) 73 | n->state = Unvisited; 74 | 75 | return routeBetwenNodesWalker(graph, from, to); 76 | } 77 | 78 | bool test(const Graph &graph, size_t from, size_t to) 79 | { 80 | auto &fromNode = graph[from], &toNode = graph[to]; 81 | bool result = routeBetwenNodes(graph, fromNode, toNode); 82 | bool resultR = routeBetwenNodesR(graph, fromNode, toNode); 83 | 84 | assert(result == resultR); 85 | std::cout << toNode->Name() << " is " << (result ? "" : "NOT ") << "reachable from " << fromNode->Name() << std::endl; 86 | std::cout << toNode->Name() << " is " << (resultR ? "" : "NOT ") << "reachable from " << fromNode->Name() << std::endl; 87 | return result; 88 | } 89 | 90 | void testGraph(const Graph &graph) 91 | { 92 | auto size = graph.getNodes().size(); 93 | for (decltype(size) i = 0; i < size; ++i) 94 | { 95 | for (decltype(size) j = 0; j < size; ++j) 96 | test(graph, i, j); 97 | std::cout << std::endl; 98 | } 99 | 100 | } 101 | 102 | int main() 103 | { 104 | testGraph(TestUtils::getExampleGraph()); 105 | testGraph(TestUtils::getExampleGraph2()); 106 | testGraph(TestUtils::getExampleGraph3()); 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.10i-CheckSubtree.cpp: -------------------------------------------------------------------------------- 1 | // Check Subtree: Tl and T2 are two very large binary trees, with Tl much bigger than T2. Create an 2 | // algorithm to determine if T2 is a subtree of Tl. 3 | // A tree T2 is a subtree of Tl if there exists a node n in Tl such that the subtree of n is identical to T2. 4 | // That is, if you cut off the tree at node n, the two trees would be identical. 5 | 6 | // Solution with the Tree Node Iterator 7 | 8 | #include "tree.hpp" 9 | #include "treenodeiterator.hpp" 10 | #include "treetestutils.hpp" 11 | 12 | template 13 | bool compareTrees(const NodePtr &left, const NodePtr &right); 14 | 15 | template 16 | bool checkSubtree(const Tree &tree, const Tree &subtree) 17 | { 18 | auto subtreeRoot = subtree.getRoot(); 19 | if (!subtreeRoot) 20 | return true; // empty subtree 21 | auto subtreeRootValue = subtreeRoot->getValue(); 22 | 23 | for (const auto &node : tree) 24 | { 25 | if (node->getValue() == subtreeRootValue) 26 | if (compareTrees(node, subtreeRoot)) 27 | return true; 28 | } 29 | return false; 30 | } 31 | 32 | template 33 | bool compareTrees(const NodePtr &left, const NodePtr &right) 34 | { 35 | if (!left && !right) 36 | return true; 37 | else if (!left || !right) // one tree is not finished, another already finished 38 | return false; 39 | else if (left->getValue() == right->getValue()) 40 | return compareTrees(left->getLeft(), right->getLeft()) && compareTrees(left->getRight(), right->getRight()); 41 | return false; 42 | } 43 | 44 | int main() 45 | { 46 | auto left = TestUtils::getSampleTree(15); 47 | auto right = TestUtils::getSampleTree(7); 48 | TestUtils::printTree(right); 49 | std::cout << (checkSubtree(left, right) ? "is subtree of\n" : "is not subtree of\n"); 50 | TestUtils::printTree(left); 51 | 52 | right = TestUtils::getSampleTree(8); 53 | TestUtils::printTree(right); 54 | std::cout << (checkSubtree(left, right) ? "is subtree of\n" : "is not subtree of\n"); 55 | TestUtils::printTree(left); 56 | } -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.10r-CheckSubtree.cpp: -------------------------------------------------------------------------------- 1 | // Check Subtree: Tl and T2 are two very large binary trees, with Tl much bigger than T2. Create an 2 | // algorithm to determine if T2 is a subtree of Tl. 3 | // A tree T2 is a subtree of Tl if there exists a node n in Tl such that the subtree of n is identical to T2. 4 | // That is, if you cut off the tree at node n, the two trees would be identical. 5 | 6 | // Recursive solution with Tree traversing 7 | 8 | #include "tree.hpp" 9 | #include "treenodeiterator.hpp" 10 | #include "treetestutils.hpp" 11 | 12 | template 13 | bool compareTrees(const NodePtr &left, const NodePtr &right); 14 | 15 | template 16 | bool checkSubtree(const NodePtr &root, const NodePtr &subtreeRoot); 17 | 18 | template 19 | bool checkSubtree(const Tree &tree, const Tree &subtree) 20 | { 21 | if (!subtree.getRoot()) 22 | return true; // empty subtree 23 | return checkSubtree(tree.getRoot(), subtree.getRoot()); 24 | } 25 | 26 | template 27 | bool compareTrees(const NodePtr &left, const NodePtr &right) 28 | { 29 | if (!left && !right) 30 | return true; 31 | else if (!left || !right) // one tree is not finished, another already finished 32 | return false; 33 | else if (left->getValue() == right->getValue()) 34 | return compareTrees(left->getLeft(), right->getLeft()) && compareTrees(left->getRight(), right->getRight()); 35 | return false; 36 | } 37 | 38 | template 39 | bool checkSubtree(const NodePtr &root, const NodePtr &subtreeRoot) 40 | { 41 | if (!root) 42 | return false; 43 | if (root->getValue() == subtreeRoot->getValue() && compareTrees(root, subtreeRoot)) 44 | return true; 45 | return checkSubtree(root->getLeft(), subtreeRoot) || checkSubtree(root->getRight(), subtreeRoot); 46 | } 47 | 48 | int main() 49 | { 50 | auto left = TestUtils::getSampleTree(15); 51 | auto right = TestUtils::getSampleTree(7); 52 | TestUtils::printTree(right); 53 | std::cout << (checkSubtree(left, right) ? "is subtree of\n" : "is not subtree of\n"); 54 | TestUtils::printTree(left); 55 | 56 | std::cout << std::endl; 57 | right = TestUtils::getSampleTree(8); 58 | TestUtils::printTree(right); 59 | std::cout << (checkSubtree(left, right) ? "is subtree of\n" : "is not subtree of\n"); 60 | TestUtils::printTree(left); 61 | } -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.11-RandomNode.cpp: -------------------------------------------------------------------------------- 1 | // Random Node: You are implementing a binary search tree class from scratch, which, in addition 2 | // to insert, find, and delete, has a method getRandomNode() which returns a random node 3 | // from the tree. All nodes should be equally likely to be chosen. Design and implement an algorithm 4 | // for getRandomNode, and explain how you would implement the rest of the methods. 5 | 6 | // Tree contains all nodes in a deque. It needs to handle insert() and delete() methods. 7 | // getRundomNode: O(1) time 8 | // To fill tree with deque additional: + O(N) time + O(N) memory. 9 | // To clean tree with deque additional: + O(N) time 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | template 18 | class Tree 19 | { 20 | public: 21 | Tree() 22 | { 23 | // construct a trivial random generator engine from a time-based seed: 24 | auto seed = std::chrono::system_clock::now().time_since_epoch().count(); 25 | randomEngine = std::default_random_engine(seed); 26 | } 27 | 28 | class RandomNode; 29 | using NodePtr = std::shared_ptr; 30 | 31 | class RandomNode 32 | { 33 | public: 34 | template 35 | explicit RandomNode(U &&value) : v(std::forward(value)) 36 | { 37 | } 38 | 39 | const NodePtr &left() const 40 | { 41 | return childs[0]; 42 | } 43 | const NodePtr &right() const 44 | { 45 | return childs[1]; 46 | } 47 | const T &value() const 48 | { 49 | return v; 50 | } 51 | 52 | private: 53 | std::array childs; 54 | T v; 55 | size_t idx; // index in the Tree::nodes, used for quick deletion from Tree::nodes 56 | friend class Tree; 57 | }; 58 | 59 | template 60 | const NodePtr insert(const NodePtr &parent, U &&value, bool insertRight) 61 | { 62 | NodePtr newNode; 63 | if (!parent) 64 | rootNode = newNode = std::make_shared(std::forward(value)); 65 | else 66 | parent->childs[insertRight ? 1 : 0] = newNode = std::make_shared(std::forward(value)); 67 | newNode->idx = nodes.size(); 68 | nodes.push_back(newNode); 69 | return newNode; 70 | } 71 | 72 | const NodePtr getRundomNode() const 73 | { 74 | if (nodes.size() == 0) 75 | return nullptr; 76 | else if (nodes.size() == 1) 77 | return rootNode; 78 | else 79 | { 80 | if (randomDistribution.max() != nodes.size() - 1) 81 | randomDistribution = std::uniform_int_distribution(0, nodes.size() - 1); 82 | return nodes.at(randomDistribution(randomEngine)); 83 | } 84 | } 85 | 86 | const NodePtr &root() const 87 | { 88 | return this->rootNode; 89 | } 90 | 91 | private: 92 | NodePtr rootNode; 93 | std::deque nodes; 94 | mutable std::default_random_engine randomEngine; 95 | mutable std::uniform_int_distribution randomDistribution; 96 | }; 97 | 98 | int main() 99 | { 100 | Tree tree; 101 | auto node = tree.insert(nullptr, 3, false); // 3 102 | auto left = tree.insert(node, 1, false); // / \ . 103 | tree.insert(left, 0, false); // 1 5 104 | tree.insert(left, 2, true); // / \ / \ . 105 | auto right = tree.insert(node, 5, true); // 0 2 4 6 106 | tree.insert(right, 4, false); 107 | tree.insert(right, 6, true); 108 | 109 | std::string coma; 110 | for (int i = 0; i < 100; ++i) 111 | { 112 | std::cout << coma << tree.getRundomNode()->value(); 113 | if (coma.empty()) 114 | coma = ", "; 115 | } 116 | std::cout << std::endl; 117 | } 118 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.11m-RandomTree.cpp: -------------------------------------------------------------------------------- 1 | // Random Node: You are implementing a binary search tree class from scratch, which, in addition 2 | // to insert, find, and delete, has a method getRandomNode() which returns a random node 3 | // from the tree. All nodes should be equally likely to be chosen. Design and implement an algorithm 4 | // for getRandomNode, and explain how you would implement the rest of the methods. 5 | 6 | // Another solution with custom node implementation for balanced tree. 7 | // getRundomNode: O(log(N)) time 8 | // To fill tree from sorted array: O(N) time and O(N) memory. 9 | 10 | #include 11 | #include 12 | #include 13 | #include "tree.hpp" 14 | #include "treetestutils.hpp" 15 | 16 | template 17 | class RandomNode; 18 | 19 | template 20 | class RandomNode 21 | { 22 | public: 23 | using NodePtr = std::shared_ptr>; 24 | 25 | RandomNode(const T &v): size(1) 26 | { 27 | value = v; 28 | } 29 | 30 | const NodePtr &getLeft() const 31 | { 32 | return childs[0]; 33 | } 34 | 35 | const NodePtr &getRight() const 36 | { 37 | return childs[1]; 38 | } 39 | 40 | const T &getValue() const 41 | { 42 | return value; 43 | } 44 | 45 | private: 46 | void add(const T &v) 47 | { 48 | if (!childs[v > value]) 49 | childs[v > value] = std::make_shared>(v); 50 | else 51 | childs[v > value]->add(v); 52 | ++size; 53 | } 54 | 55 | const T &getRandom() const 56 | { 57 | return get(std::rand() % size + 1); 58 | } 59 | 60 | const T &get(size_t n) const 61 | { 62 | if (n == size) 63 | return value; 64 | else if (childs[0] && n <= childs[0]->size) 65 | return childs[0]->get(n); 66 | else 67 | return childs[1]->get(n - (childs[0] ? childs[0]->size : 0)); 68 | } 69 | 70 | T value; 71 | size_t size; 72 | std::array childs; 73 | 74 | template 75 | friend class RandomTree; 76 | }; 77 | 78 | template 79 | class RandomTree : public Tree 80 | { 81 | using Base = Tree; 82 | 83 | public: 84 | const T &getRandom() const 85 | { 86 | if (!Base::root) 87 | throw typename Base::TreeIsEmptyException(); 88 | return Base::root->getRandom(); 89 | } 90 | 91 | void add(const T &value) 92 | { 93 | if (Base::root) 94 | Base::root->add(value); 95 | else 96 | Base::root = std::make_shared>(value); 97 | } 98 | }; 99 | 100 | 101 | int main() 102 | { 103 | std::srand (unsigned(std::time(0))); 104 | std::vector v(7) ; 105 | std::iota(std::begin(v), std::end(v), 0); // Fill with 0, 1, ..., nodeCount - 1. 106 | std::random_shuffle(std::begin(v), std::end(v), [](int i){return std::rand() % i;}); 107 | 108 | RandomTree tree; 109 | tree.add(v.back()); 110 | v.pop_back(); 111 | for (auto i : v) 112 | tree.add(i); 113 | 114 | TestUtils::printTree(tree); 115 | std::cout << std::endl; 116 | 117 | // Check distribution of rundom tree nodes 118 | v = std::vector(v.size() + 1, 0); 119 | for (auto i = 0U; i < v.size() * 1000; ++i) 120 | ++v[tree.getRandom()]; 121 | 122 | size_t cnt = std::accumulate(v.begin(), v.end(), 0); 123 | std::cout << "Total: " << cnt << " times\n"; 124 | std::cout << std::fixed << std::setprecision(2); 125 | for (auto i = 0U; i < v.size(); ++i) 126 | std::cout << i << ": " << 100.0 * v[i] / cnt << "%\n"; 127 | } 128 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.12-PathsWithSum.cpp: -------------------------------------------------------------------------------- 1 | // Paths with Sum: You are given a binary tree in which each node contains an integer value (which 2 | // might be positive or negative). Design an algorithm to count the number of paths that sum to a 3 | // given value. The path does not need to start or end at the root or a leaf, but it must go downwards 4 | // (traveling only from parent nodes to child nodes). 5 | 6 | #include 7 | 8 | #include "tree.hpp" 9 | #include "treetestutils.hpp" 10 | 11 | int sumsFrom(const NodePtr &node, int requiredSum, int pathSum, std::unordered_map &sums) 12 | { 13 | if (!node) 14 | return 0; 15 | 16 | pathSum += node->getValue(); 17 | 18 | // Count of paths ending here and having required sum 19 | int overflow = pathSum - requiredSum; 20 | int cnt = sums.count(overflow) ? sums.at(overflow) : 0; 21 | 22 | // Starting from root 23 | if (pathSum == requiredSum) 24 | ++cnt; 25 | 26 | sums[pathSum] += 1; 27 | cnt += sumsFrom(node->getLeft(), requiredSum, pathSum, sums); 28 | cnt += sumsFrom(node->getRight(), requiredSum, pathSum, sums); 29 | 30 | // Done with this node, do not use pathSum till this node anymore 31 | if ((sums[pathSum] -= 1) == 0) 32 | sums.erase(pathSum); // less memory 33 | return cnt; 34 | } 35 | 36 | int countPathsWithSum(const Tree &tree, int sum) 37 | { 38 | std::unordered_map tmp; 39 | return sumsFrom(tree.getRoot(), sum, 0, tmp); 40 | } 41 | 42 | int main() 43 | { 44 | auto tree = TestUtils::treeFromArray({1, -2, 3, -5, 7, -11, 13, -1, 2, -3, 5, -7, 11, -1, 2, -3, 1, -2, 3, -7}); 45 | TestUtils::printTree(tree); 46 | 47 | // From sum of negative values till sum of positive values 48 | for (int i = -42; i <= 48; ++i) 49 | std::cout << "Sum " << i << " can be reached in " << countPathsWithSum(tree, i) << " paths\n"; 50 | } 51 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.2-MinimalTree.cpp: -------------------------------------------------------------------------------- 1 | // Minimal Tree: Given a sorted (increasing order) array with unique integer elements, write an 2 | // algorithm to create a binary search tree with minimal height. 3 | 4 | #include 5 | #include 6 | #include "tree.hpp" 7 | #include "treetestutils.hpp" 8 | 9 | template 10 | NodePtr subtreeFromArray(const T *array, int start, int end) 11 | { 12 | if (end < start) 13 | return nullptr; 14 | 15 | int i = (start + end) / 2; 16 | auto node = std::make_shared>(array[i]); 17 | node->setLeftChild(subtreeFromArray(array, start, i - 1)); 18 | node->setRightChild(subtreeFromArray(array, i + 1, end)); 19 | return node; 20 | } 21 | 22 | template 23 | Tree treeFromArray(const T *array, size_t size) 24 | { 25 | Tree tree; 26 | tree.setRoot(subtreeFromArray(array, 0, size - 1)); 27 | 28 | return tree; 29 | } 30 | 31 | int main() 32 | { 33 | std::array array; 34 | std::iota(array.begin(), array.end(), 0); // Fill with 0 .. 62 35 | 36 | for (auto &i : {1, 2, 3, 6, 7, 8, 14, 15, 16, 29, 30, 31}) 37 | { 38 | auto tree = treeFromArray(&array[0], i); 39 | TestUtils::printTree(tree); 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.3-ListOfDepths.cpp: -------------------------------------------------------------------------------- 1 | // List of Depths: Given a binary tree, design an algorithm which creates a linked list of all the nodes 2 | // at each depth (e.g., if you have a tree with depth D, you'll have D linked lists). 3 | 4 | // This task is mostly done in the function printTree :-) 5 | 6 | #include 7 | #include "tree.hpp" 8 | #include "treetestutils.hpp" 9 | 10 | template 11 | using ListOfDepths = std::list>>; 12 | 13 | template 14 | ListOfDepths getListOfDepths(const Tree &tree) 15 | { 16 | ListOfDepths result; 17 | 18 | result.emplace_back(); 19 | auto list = &result.back(); 20 | list->push_back(tree.getRoot()); 21 | 22 | do 23 | { 24 | result.emplace_back(); 25 | auto &childs = result.back(); 26 | for (const auto &n : *list) 27 | { 28 | if (n->getLeft()) 29 | childs.push_back(n->getLeft()); 30 | if (n->getRight()) 31 | childs.push_back(n->getRight()); 32 | } 33 | if (childs.empty()) 34 | { 35 | result.pop_back(); 36 | break; 37 | } 38 | list = &childs; 39 | } while (true); 40 | 41 | return result; 42 | } 43 | 44 | template 45 | void printDepths(const ListOfDepths &depths) 46 | { 47 | std::cout << "Nodes:\n"; 48 | int depth = 0; 49 | for (const auto &line : depths) 50 | { 51 | std::cout << depth << ": "; 52 | auto sep = ""; 53 | for (const auto &n : line) 54 | { 55 | std::cout << sep << n->getValue(); 56 | sep = ", "; 57 | } 58 | std::cout << std::endl; 59 | ++depth; 60 | } 61 | std::cout << std::endl; 62 | } 63 | 64 | int main() 65 | { 66 | auto tree = TestUtils::getSampleTree(15); 67 | TestUtils::printTree(tree); 68 | auto depths = getListOfDepths(tree); 69 | printDepths(depths); 70 | 71 | tree = TestUtils::getSampleTree(20); 72 | TestUtils::printTree(tree); 73 | depths = getListOfDepths(tree); 74 | printDepths(depths); 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.4-CheckBalanced.cpp: -------------------------------------------------------------------------------- 1 | // Check Balanced: Implement a function to check if a binary tree is balanced. For the purposes of 2 | // this question, a balanced tree is defined to be a tree such that the heights of the two subtrees of any 3 | // node never differ by more than one. 4 | 5 | #include 6 | #include "tree.hpp" 7 | #include "treetestutils.hpp" 8 | 9 | template 10 | int getHeight(const NodePtr &node) 11 | { 12 | if (!node) 13 | return 0; 14 | 15 | int leftH = getHeight(node->getLeft()); 16 | if (leftH == -1) 17 | return -1; 18 | 19 | int rightH = getHeight(node->getRight()); 20 | if (rightH == -1) 21 | return -1; 22 | 23 | if (std::abs(leftH - rightH) > 1) 24 | return -1; 25 | return std::max(leftH, rightH) + 1; 26 | } 27 | 28 | template 29 | bool isTreeBalanced(const Tree &tree) 30 | { 31 | return getHeight(tree.getRoot()) != -1; 32 | } 33 | 34 | int main() 35 | { 36 | auto tree = TestUtils::getSampleTree(20); // balanced tree 37 | std::cout << "Tree is " << (isTreeBalanced(tree) ? "" : "NOT ") << "balanced" << std::endl; 38 | 39 | // Disconnect right subtree, the result tree is not balanced 40 | auto r = tree.getRoot()->getRight(); 41 | tree.getRoot()->getRight() = std::make_shared>(100); 42 | std::cout << "Tree is " << (isTreeBalanced(tree) ? "" : "NOT ") << "balanced" << std::endl; 43 | 44 | // Return right subtree and check if the tree is balanced again 45 | tree.getRoot()->getRight() = r; // balanced 46 | std::cout << "Tree is " << (isTreeBalanced(tree) ? "" : "NOT ") << "balanced" << std::endl; 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.5-ValidateBST.cpp: -------------------------------------------------------------------------------- 1 | // Validate BST: Implement a function to check if a binary tree is a binary search tree. 2 | 3 | #include 4 | #include "tree.hpp" 5 | #include "treetestutils.hpp" 6 | 7 | template 8 | bool checkNode(const NodePtr &node, const T *minValue, const T *maxValue) 9 | { 10 | if (!node) 11 | return true; 12 | if (minValue && node->getValue() <= *minValue) 13 | return false; 14 | if (maxValue && node->getValue() > *maxValue) 15 | return false; 16 | 17 | return checkNode(node->getLeft(), minValue, &node->getValue()) && checkNode(node->getRight(), &node->getValue(), maxValue); 18 | } 19 | 20 | template 21 | bool isValidBST(const Tree &tree) 22 | { 23 | return checkNode(tree.getRoot(), nullptr, nullptr); 24 | } 25 | 26 | int main() 27 | { 28 | // valid BST 29 | auto tree = TestUtils::getSampleTree(20); 30 | TestUtils::printTree(tree); 31 | std::cout << "The tree is " << (isValidBST(tree) ? "" : "NOT ") << "binary search tree" << std::endl; 32 | 33 | // invalid BST 34 | tree.getRoot()->getRight()->getRight()->getRight()->setLeftChild(std::make_shared>(19)); 35 | TestUtils::printTree(tree); 36 | std::cout << "The tree is " << (isValidBST(tree) ? "" : "NOT ") << "binary search tree" << std::endl; 37 | 38 | // invalid BST 39 | tree.getRoot()->getRight()->getRight()->getRight()->setLeftChild(std::make_shared>(15)); 40 | TestUtils::printTree(tree); 41 | std::cout << "The tree is " << (isValidBST(tree) ? "" : "NOT ") << "binary search tree" << std::endl; 42 | } 43 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.6-Successor.cpp: -------------------------------------------------------------------------------- 1 | // Successor: Write an algorithm to find the "next" node (i.e., in-order successor) of a given node in a 2 | // binary search tree. You may assume that each node has a link to its parent. 3 | 4 | #include 5 | #include "tree.hpp" 6 | #include "treetestutils.hpp" 7 | 8 | template 9 | NodePtr getMin(NodePtr node) 10 | { 11 | if (!node) 12 | return nullptr; 13 | while (node->getLeft()) 14 | node = node->getLeft(); 15 | return node; 16 | } 17 | 18 | template 19 | NodePtr nextNode(NodePtr node) 20 | { 21 | if (!node) 22 | return nullptr; 23 | if (node->getRight()) 24 | return getMin(node->getRight()); 25 | auto next = node->getParent(); 26 | while (next && node == next->getRight()) 27 | { 28 | // right subtree is traversed -> parent and all its childs were traversed 29 | node = next; 30 | next = next->getParent(); 31 | } 32 | return next; 33 | } 34 | 35 | int main() 36 | { 37 | // valid BST 38 | auto tree = TestUtils::getSampleTree(20); 39 | TestUtils::printTree(tree); 40 | auto node = getMin(tree.getRoot()); 41 | if (node) 42 | { 43 | std::cout << node->getValue(); 44 | for (node = nextNode(node); node; node = nextNode(node)) 45 | std::cout << " --> " << node->getValue(); 46 | std::cout << std::endl; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.7-BuildOrder.cpp: -------------------------------------------------------------------------------- 1 | // Build Order: You are given a list of projects and a list of dependencies (which is a list of pairs of 2 | // projects, where the second project is dependent on the first project). All of a project's dependencies 3 | // must be built before the project is. Find a build order that will allow the projects to be built. If there 4 | // is no valid build order, return an error. 5 | // EXAMPLE 6 | // Input: 7 | // projects: a, b, c, d, e, f 8 | // dependencies: (a, d), (f, b), (b, d), (f, a), (d, c) 9 | // Output: f, e, a, b, d, c 10 | 11 | #include 12 | #include 13 | 14 | #include "graph.hpp" 15 | #include "graphtestutils.hpp" 16 | 17 | std::list> buildOrder(const Graph &graph) 18 | { 19 | std::list> order; 20 | auto &projects = graph.getNodes(); 21 | 22 | for (auto &n : projects) 23 | { 24 | for (auto &c : n->getAdjacent()) 25 | c.lock()->state++; // skip check c.lock() 26 | } 27 | for (auto &n : projects) 28 | if (n->state == 0) 29 | order.push_back(n); 30 | 31 | for (auto &p : order) 32 | { 33 | for (auto &c : p->getAdjacent()) 34 | { 35 | auto n = c.lock(); 36 | if (n && (--n->state) == 0) 37 | order.push_back(n); 38 | } 39 | } 40 | 41 | if (order.size() != projects.size()) 42 | order.clear(); 43 | return order; 44 | } 45 | 46 | 47 | void test(const Graph &graph) 48 | { 49 | auto order = buildOrder(graph); 50 | 51 | const char *sep = ""; 52 | for (auto &n : order) 53 | { 54 | std::cout << sep << n->Name(); 55 | sep = ", "; 56 | } 57 | std::cout << std::endl; 58 | } 59 | 60 | int main() 61 | { 62 | test(TestUtils::createGraph({"a", "b", "c", "d", "e", "f"}, 63 | {{"a", "d"}, {"f", "b"}, {"b", "d"}, {"f", "a"}, {"d", "c"}})); 64 | 65 | test(TestUtils::createGraph({"a", "b", "c", "d", "e", "f", "g"}, 66 | {{"a", "e"}, {"b", "a"}, {"b", "e"}, {"c", "a"}, {"d", "g"}, {"f", "a"}, {"f", "b"}, {"f", "c"}})); 67 | } 68 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.7d-BuildOrder.cpp: -------------------------------------------------------------------------------- 1 | // Build Order: You are given a list of projects and a list of dependencies (which is a list of pairs of 2 | // projects, where the second project is dependent on the first project). All of a project's dependencies 3 | // must be built before the project is. Find a build order that will allow the projects to be built. If there 4 | // is no valid build order, return an error. 5 | // EXAMPLE 6 | // Input: 7 | // projects: a, b, c, d, e, f 8 | // dependencies: (a, d), (f, b), (b, d), (f, a), (d, c) 9 | // Output: f, e, a, b, d, c 10 | 11 | #include 12 | #include 13 | 14 | #include "graph.hpp" 15 | #include "graphtestutils.hpp" 16 | 17 | enum class States 18 | { 19 | NotVisited, 20 | Visiting, 21 | Visited 22 | }; 23 | 24 | bool buildProject(const Node &node, std::list> &order) 25 | { 26 | if (node->state == States::Visited) 27 | return true; // Already pushed in build order 28 | 29 | if (node->state == States::Visiting) 30 | { 31 | // Dependency cycle detected 32 | order.empty(); 33 | return false; 34 | } 35 | 36 | node->state = States::Visiting; 37 | for (auto &a : node->getAdjacent()) 38 | { 39 | auto prj = a.lock(); 40 | if (prj) 41 | if (!buildProject(prj, order)) 42 | return false; 43 | } 44 | node->state = States::Visited; 45 | order.push_front(node); 46 | return true; 47 | } 48 | 49 | std::list> buildOrder(const Graph &graph) 50 | { 51 | std::list> order; 52 | auto &projects = graph.getNodes(); 53 | for (auto &p : projects) 54 | if (!buildProject(p, order)) 55 | break; 56 | return order; 57 | } 58 | 59 | void test(const Graph &graph) 60 | { 61 | auto order = buildOrder(graph); 62 | 63 | const char *sep = ""; 64 | for (auto &n : order) 65 | { 66 | std::cout << sep << n->Name(); 67 | sep = ", "; 68 | } 69 | std::cout << std::endl; 70 | } 71 | 72 | int main() 73 | { 74 | test(TestUtils::createGraph({"a", "b", "c", "d", "e", "f"}, 75 | {{"a", "d"}, {"f", "b"}, {"b", "d"}, {"f", "a"}, {"d", "c"}})); 76 | 77 | test(TestUtils::createGraph({"a", "b", "c", "d", "e", "f", "g"}, 78 | {{"a", "e"}, {"b", "a"}, {"b", "e"}, {"c", "a"}, {"d", "g"}, {"f", "a"}, {"f", "b"}, {"f", "c"}})); 79 | } 80 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.8-FirstCommonAncestor.cpp: -------------------------------------------------------------------------------- 1 | // First Common Ancestor: Design an algorithm and write code to find the first common ancestor 2 | // of two nodes in a binary tree. Avoid storing additional nodes in a data structure. NOTE: This is not 3 | // necessarily a binary search tree. 4 | 5 | // My solution is faster than one from the book. commonAncestor() or commonAncHelper() function from 6 | // the book always recursively traverse subtrees till leafs, but my solutions does it twice rarer. 7 | // In O-notation speeds are the same. 8 | 9 | #include 10 | #include "tree.hpp" 11 | #include "treetestutils.hpp" 12 | #include "treenodeiterator.hpp" 13 | 14 | enum FindResult 15 | { 16 | NotFound, // node not found in subtree 17 | FoundLeft, // node found in left subtree 18 | FoundRight, // node found in right subtree 19 | FoundEqual // node is subtree root 20 | }; 21 | 22 | template 23 | FindResult findNodeFrom(const NodePtr &startNode, const NodePtr &node) 24 | { 25 | if (!startNode) 26 | return NotFound; 27 | if (startNode == node) 28 | return FoundEqual; 29 | if (findNodeFrom(startNode->getLeft(), node) != NotFound) 30 | return FoundLeft; 31 | else if (findNodeFrom(startNode->getRight(), node) != NotFound) 32 | return FoundRight; 33 | return NotFound; 34 | } 35 | 36 | template 37 | NodePtr findCommonAncestor(const Tree &tree, const NodePtr &one, const NodePtr &two) 38 | { 39 | if (one == two) 40 | return one; 41 | 42 | auto startNode = tree.getRoot(); 43 | 44 | auto firstResult = findNodeFrom(startNode, one); 45 | if (firstResult == NotFound) 46 | return nullptr; 47 | auto secondResult = findNodeFrom(startNode, two); 48 | if (secondResult == NotFound) 49 | return nullptr; 50 | 51 | while (firstResult == secondResult) 52 | { 53 | startNode = (firstResult == FoundLeft) ? startNode->getLeft() : startNode->getRight(); 54 | firstResult = findNodeFrom(startNode, one); 55 | secondResult = findNodeFrom(startNode, two); 56 | } 57 | return startNode; 58 | } 59 | 60 | int main() 61 | { 62 | auto tree = TestUtils::treeFromArray({10, 1, 12, 3, 14, 25, 16, 27, 18, 29, 10, 13, 2, 15, 4, 5, 17, 7, 19, 9}); 63 | TestUtils::printTree(tree); 64 | 65 | for (auto one : tree) 66 | { 67 | if (one == tree.getRoot()) 68 | continue; // it is not interesting 69 | for (auto two : tree) 70 | { 71 | if (two == tree.getRoot() || two == one) 72 | continue; // it is not interesting 73 | auto ancestor = findCommonAncestor(tree, one, two); 74 | std::cout << one->getValue() << ", " << two->getValue() << " <-- "; 75 | std::cout << (ancestor ? std::to_string(ancestor->getValue()) : "NOT FOUND") << std::endl; 76 | } 77 | } 78 | 79 | // Test nodes of different trees 80 | auto tree2 = TestUtils::getSampleTree(7); 81 | auto node1 = tree.getRoot()->getLeft()->getRight(); 82 | auto node2 = tree2.getRoot()->getRight()->getLeft(); 83 | auto ancestor = findCommonAncestor(tree, node1, node2); 84 | std::cout << "Nodes below are of diffent trees:\n"; 85 | std::cout << node1->getValue() << ", " << node2->getValue() << " <-- "; 86 | std::cout << (ancestor ? std::to_string(ancestor->getValue()) : "NOT FOUND") << std::endl; 87 | } 88 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.8p-FirstCommonAncestor.cpp: -------------------------------------------------------------------------------- 1 | // First Common Ancestor: Design an algorithm and write code to find the first common ancestor 2 | // of two nodes in a binary tree. Avoid storing additional nodes in a data structure. NOTE: This is not 3 | // necessarily a binary search tree. 4 | // New condition: tree nodes contain links to their parents. 5 | 6 | #include "tree.hpp" 7 | #include "treetestutils.hpp" 8 | #include "treenodeiterator.hpp" 9 | 10 | template 11 | int getDepth(const Tree &tree, NodePtr node) 12 | { 13 | size_t depth = 0; 14 | if (node) 15 | { 16 | while (node->getParent()) 17 | { 18 | node = node->getParent(); 19 | ++depth; 20 | } 21 | } 22 | // Check if the node is in this tree 23 | if (node != tree.getRoot()) 24 | depth = -1; 25 | return depth; 26 | } 27 | 28 | template 29 | NodePtr findCommonAncestor(const Tree &tree, NodePtr one, NodePtr two) 30 | { 31 | if (one == two) 32 | return one; 33 | 34 | auto depthL = getDepth(tree, one); 35 | auto depthR = getDepth(tree, two); 36 | if (depthL == -1 || depthR == -1) 37 | return nullptr; 38 | 39 | if (depthL > depthR) 40 | { 41 | std::swap(depthL, depthR); 42 | std::swap(one, two); // that is why we pass 'one' and 'two' arguments by values 43 | } 44 | 45 | while (depthR != depthL) 46 | { 47 | two = two->getParent(); 48 | --depthR; 49 | } 50 | while (one != two) 51 | { 52 | one = one->getParent(); 53 | two = two->getParent(); 54 | } 55 | return one; 56 | } 57 | 58 | int main() 59 | { 60 | auto tree = TestUtils::treeFromArray({10, 1, 12, 3, 14, 25, 16, 27, 18, 29, 10, 13, 2, 15, 4, 5, 17, 7, 19, 9}); 61 | TestUtils::printTree(tree); 62 | 63 | for (auto one : tree) 64 | { 65 | if (one == tree.getRoot()) 66 | continue; // it is not interesting 67 | for (auto two : tree) 68 | { 69 | if (two == tree.getRoot() || two == one) 70 | continue; // it is not interesting 71 | auto ancestor = findCommonAncestor(tree, one, two); 72 | std::cout << one->getValue() << ", " << two->getValue() << " <-- "; 73 | std::cout << (ancestor ? std::to_string(ancestor->getValue()) : "NOT FOUND") << std::endl; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/4.9-BSTSequences.cpp: -------------------------------------------------------------------------------- 1 | // BST Sequences: A binary search tree was created by traversing through an array from left to right 2 | // and inserting each element. Given a binary search tree with distinct elements, print all possible 3 | // arrays that could have led to this tree. 4 | // EXAMPLE 5 | // Input: 2 6 | // 1 3 7 | // Output: {2, 1, 3}, {2, 3, 1} 8 | 9 | #include 10 | #include 11 | #include 12 | #include "tree.hpp" 13 | #include "treetestutils.hpp" 14 | 15 | template 16 | std::list> possibleStableJoins(std::deque &prefix, std::deque &left, std::deque &right); 17 | 18 | template 19 | std::list> possibleArrays(const NodePtr &root) 20 | { 21 | std::list> result; 22 | if (!root) 23 | { 24 | result.emplace_back(); // empty is required to call cycle body at least once 25 | return result; 26 | } 27 | 28 | auto leftArrays = possibleArrays(root->getLeft()); 29 | auto rightArrays = possibleArrays(root->getRight()); 30 | 31 | std::deque prefix; 32 | prefix.push_back(root->getValue()); 33 | for (auto &left : leftArrays) 34 | for (auto &right : rightArrays) 35 | { 36 | auto joins = possibleStableJoins(prefix, left, right); 37 | result.splice(result.end(), std::move(joins)); 38 | assert(prefix.size() == 1 && prefix[0] == root->getValue()); 39 | } 40 | return result; 41 | } 42 | 43 | template 44 | std::list> possibleStableJoins(std::deque &prefix, std::deque &left, std::deque &right) 45 | { 46 | std::list> result; 47 | 48 | if (left.empty() || right.empty()) 49 | { 50 | std::deque r(prefix); 51 | r.insert(r.end(), left.begin(), left.end()); 52 | r.insert(r.end(), right.begin(), right.end()); 53 | result.push_back(std::move(r)); 54 | return result; 55 | } 56 | 57 | prefix.push_back(left.front()); 58 | left.pop_front(); 59 | result.splice(result.end(), possibleStableJoins(prefix, left, right)); 60 | left.push_front(prefix.back()); 61 | prefix.pop_back(); 62 | 63 | prefix.push_back(right.front()); 64 | right.pop_front(); 65 | result.splice(result.end(), possibleStableJoins(prefix, left, right)); 66 | right.push_front(prefix.back()); 67 | prefix.pop_back(); 68 | 69 | return result; 70 | } 71 | 72 | int main() 73 | { 74 | auto tree = TestUtils::treeFromArray({5, 10, 15, 20, 25, 50, 60, 65, 70, 80}); 75 | TestUtils::printTree(tree); 76 | // auto tree = TestUtils::treeFromArray({2, 3, 1}); 77 | auto result = possibleArrays(tree.getRoot()); 78 | 79 | for (auto &array : result) 80 | { 81 | std::string sep; 82 | std::cout << "{"; 83 | for (auto &n : array) 84 | { 85 | std::cout << sep << n; 86 | if (sep.empty()) 87 | sep = ", "; 88 | } 89 | std::cout << "}" << std::endl; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/graph.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | template 9 | struct WeakPtrHash : public std::unary_function, size_t> 10 | { 11 | size_t operator()(const std::weak_ptr& wp) const 12 | { 13 | auto sp = wp.lock(); 14 | return std::hash()(sp); 15 | } 16 | }; 17 | 18 | template 19 | struct WeakPtrEqual : public std::unary_function, bool> 20 | { 21 | bool operator()(const std::weak_ptr& left, const std::weak_ptr& right) const 22 | { 23 | return !left.owner_before(right) && !right.owner_before(left); 24 | } 25 | }; 26 | 27 | template 28 | class Graph 29 | { 30 | public: 31 | class Node 32 | { 33 | public: 34 | Node(const std::string &n) : name(n) 35 | { 36 | } 37 | virtual ~Node() {} 38 | 39 | bool isAdjacentFor(const std::shared_ptr &other) const 40 | { 41 | return childs.find(other) != childs.end(); 42 | } 43 | 44 | void addChild(const std::shared_ptr &other) 45 | { 46 | childs.insert(other); 47 | } 48 | 49 | const std::unordered_set, WeakPtrHash, WeakPtrEqual> &getAdjacent() const 50 | { 51 | return childs; 52 | } 53 | 54 | const std::string &Name() const 55 | { 56 | return name; 57 | } 58 | 59 | mutable State state; 60 | std::string name; 61 | 62 | private: 63 | std::unordered_set, WeakPtrHash, WeakPtrEqual> childs; 64 | }; 65 | 66 | bool matrix(size_t i, size_t j) const 67 | { 68 | if (i == j) 69 | return false; 70 | 71 | const auto &s = nodes[i]; 72 | const auto &d = nodes[j]; 73 | return s->isAdjacentFor(d); 74 | } 75 | 76 | std::shared_ptr &addNode(const std::string &name = std::string()) 77 | { 78 | nodes.emplace_back(std::make_shared(name)); 79 | if (!name.empty()) 80 | namedNodes[name] = nodes.back(); 81 | return nodes.back(); 82 | } 83 | 84 | const std::shared_ptr &operator[] (size_t i) const 85 | { 86 | return nodes[i]; 87 | } 88 | 89 | const std::shared_ptr &operator[] (const std::string &name) const 90 | { 91 | return namedNodes.at(name); 92 | } 93 | 94 | const std::deque> &getNodes() const 95 | { 96 | return nodes; 97 | } 98 | 99 | private: 100 | std::deque> nodes; 101 | std::unordered_map> namedNodes; 102 | }; 103 | 104 | template 105 | using Node = std::shared_ptr::Node>; 106 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/graphtestutils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "graph.hpp" 4 | 5 | namespace TestUtils 6 | { 7 | template 8 | Graph createGraph(std::initializer_list projects, 9 | std::initializer_list> deps) 10 | { 11 | Graph graph; 12 | for (auto &n : projects) 13 | graph.addNode(n)->state = static_cast(0); 14 | for (auto &d : deps) 15 | graph[d[0]]->addChild(graph[d[1]]); 16 | return graph; 17 | } 18 | 19 | template 20 | Graph getExampleGraph() 21 | { 22 | return createGraph({"0", "1", "2", "3", "4", "5", "6"}, 23 | {{"0", "1"}, {"1", "2"}, {"2", "0"}, {"2", "3"}, {"3", "2"}, {"4", "6"}, {"5", "4"}, {"6", "5"}}); 24 | } 25 | 26 | template 27 | Graph getExampleGraph2() 28 | { 29 | return createGraph({"0", "1", "2", "3"}, 30 | {{"0", "1"}, {"1", "2"}, {"2", "0"}, {"3", "2"}}); 31 | } 32 | 33 | template 34 | Graph getExampleGraph3() 35 | { 36 | return createGraph({"0", "1", "2", "3", "4", "5"}, 37 | {{"0", "1"}, {"0", "4"}, {"0", "5"}, {"1", "3"}, {"1", "4"}, {"2", "1"}, {"3", "2"}, {"3", "4"}}); 38 | } 39 | } -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/tree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "treenode.hpp" 4 | 5 | template class N = Node> 7 | class Tree 8 | { 9 | public: 10 | using NodePtr = typename N::NodePtr; 11 | 12 | const NodePtr &getRoot() const 13 | { 14 | if (isEmpty()) 15 | throw TreeIsEmptyException(); 16 | return root; 17 | } 18 | 19 | template 20 | void setRoot(U &&node) 21 | { 22 | root = std::forward(node); 23 | } 24 | 25 | bool isEmpty() const 26 | { 27 | return !root; 28 | } 29 | 30 | class TreeIsEmptyException {}; 31 | 32 | protected: 33 | NodePtr root; 34 | }; 35 | 36 | template 37 | using NodePtr = typename Tree::NodePtr; 38 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/treenode.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | class NodeBase 7 | { 8 | public: 9 | NodeBase() = default; 10 | 11 | NodeBase(const std::shared_ptr &p) : parent(p) 12 | { 13 | } 14 | 15 | std::shared_ptr getParent() 16 | { 17 | return parent.lock(); 18 | } 19 | private: 20 | std::weak_ptr parent; 21 | }; 22 | 23 | // Specialization for tree node containing no reference to parent 24 | template 25 | class NodeBase 26 | { 27 | public: 28 | NodeBase() = default; 29 | 30 | NodeBase(const std::shared_ptr &) 31 | { 32 | } 33 | 34 | private: 35 | }; 36 | 37 | template 38 | class Node : public NodeBase, WithParent> 39 | { 40 | using Super = NodeBase; 41 | 42 | public: 43 | using NodePtr = std::shared_ptr; 44 | 45 | Node(T &&v) : value(std::move(v)) 46 | { 47 | } 48 | 49 | Node(const T &v) : value(v) 50 | { 51 | } 52 | 53 | Node(T &&v, const NodePtr &parent) : Super(parent), value(std::move(v)) 54 | { 55 | } 56 | 57 | Node(const T &v, const NodePtr &parent) : Super(parent), value(v) 58 | { 59 | } 60 | 61 | const T &getValue() const 62 | { 63 | return value; 64 | } 65 | 66 | const NodePtr &getLeft() const 67 | { 68 | return childs.first; 69 | } 70 | 71 | NodePtr &getLeft() 72 | { 73 | return childs.first; 74 | } 75 | 76 | const NodePtr &getRight() const 77 | { 78 | return childs.second; 79 | } 80 | 81 | NodePtr &getRight() 82 | { 83 | return childs.second; 84 | } 85 | 86 | template 87 | void setLeftChild(U &&node) 88 | { 89 | childs.first = std::forward(node); 90 | } 91 | 92 | template 93 | void setRightChild(U &&node) 94 | { 95 | childs.second = std::forward(node); 96 | } 97 | 98 | protected: 99 | T value; 100 | std::pair childs; 101 | }; 102 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/treenodeiterator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | template class Node> 8 | class IteratorBase 9 | { 10 | using NodePtr = typename Node::NodePtr; 11 | 12 | public: 13 | IteratorBase() = default; 14 | 15 | IteratorBase(const NodePtr &node) : currNode(node) 16 | { 17 | } 18 | 19 | Iterator &operator ++ () 20 | { 21 | auto node = currNode.lock(); 22 | if (!node) 23 | currNode = NodePtr(); 24 | else if (node->getLeft()) 25 | currNode = node->getLeft(); 26 | else if (node->getRight()) 27 | currNode = node->getRight(); 28 | else 29 | { 30 | while (node->getParent() && node == node->getParent()->getRight()) 31 | node = node->getParent(); 32 | currNode = node->getParent() ? node->getParent()->getRight() : node->getParent(); 33 | } 34 | return *static_cast(this); 35 | } 36 | 37 | protected: 38 | std::weak_ptr> currNode; 39 | }; 40 | 41 | template class Node> 42 | class IteratorBase 43 | { 44 | using NodePtr = std::shared_ptr>; 45 | 46 | public: 47 | IteratorBase() = default; 48 | 49 | IteratorBase(const NodePtr &node) : currNode(node) 50 | { 51 | } 52 | 53 | Iterator &operator ++ () 54 | { 55 | auto node = currNode.lock(); 56 | if (!node) 57 | currNode = NodePtr(); 58 | else if (node->getLeft()) 59 | { 60 | parents.emplace(node); 61 | currNode = node->getLeft(); 62 | } 63 | else if (node->getRight()) 64 | { 65 | parents.emplace(node); 66 | currNode = node->getRight(); 67 | } 68 | else 69 | { 70 | while (!parents.empty() && node == parents.top()->getRight()) 71 | { 72 | node = parents.top(); 73 | parents.pop(); 74 | } 75 | currNode = !parents.empty() ? parents.top()->getRight() : NodePtr(); 76 | } 77 | return *static_cast(this); 78 | } 79 | 80 | protected: 81 | std::weak_ptr> currNode; 82 | std::stack parents; 83 | }; 84 | 85 | template class Node> 86 | class Iterator : public IteratorBase, T, NodeWithParent, Node> 87 | { 88 | using Super = IteratorBase, T, NodeWithParent, Node>; 89 | using NodePtr = typename Node::NodePtr; 90 | 91 | public: 92 | Iterator() = default; 93 | 94 | Iterator(const NodePtr &node) : Super(node) 95 | { 96 | } 97 | 98 | NodePtr operator * () 99 | { 100 | return Super::currNode.lock(); 101 | } 102 | 103 | bool operator != (const Iterator &rh) 104 | { 105 | return Super::currNode.lock() != rh.currNode.lock(); 106 | } 107 | }; 108 | 109 | template class Node> 110 | class Tree; 111 | 112 | template class Node> 113 | auto begin(const Tree &tree) 114 | { 115 | return Iterator(tree.getRoot()); 116 | } 117 | 118 | template class Node> 119 | auto end(const Tree) 120 | { 121 | return Iterator(); 122 | } 123 | -------------------------------------------------------------------------------- /Ch 4. Trees and Graphs/C++14/treetestutils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | template class Node> 13 | class Tree; 14 | 15 | template 16 | class Node; 17 | 18 | namespace TestUtils 19 | { 20 | template class Node> 21 | void printTree(const Tree &tree) 22 | { 23 | using NodePtr = typename Tree::NodePtr; 24 | 25 | T minValue = std::numeric_limits::max(), maxValue = std::numeric_limits::min(); 26 | 27 | // Lambda function is used to hide it from externall access 28 | std::function getDepth = 29 | [&](const NodePtr &node) -> size_t 30 | { 31 | if (!node) 32 | return 0; 33 | 34 | auto depth = std::max(getDepth(node->getLeft()), getDepth(node->getRight())) + 1; 35 | minValue = std::min(minValue, node->getValue()); 36 | maxValue = std::max(maxValue, node->getValue()); 37 | return depth; 38 | }; 39 | 40 | size_t depth = getDepth(tree.getRoot()); 41 | 42 | // bottommost max leaf count 43 | size_t size = std::pow(2, depth - 1); 44 | 45 | // width of node, in digits 46 | size_t digits = (maxValue != 0 || minValue != 0) ? std::log10(std::max(maxValue, std::abs(minValue))) + 1 : 1; 47 | if (minValue < 0) 48 | ++digits; 49 | 50 | const std::string placeholder(digits, ' '); 51 | 52 | std::queue queue; 53 | std::queue childs; 54 | queue.push(tree.getRoot()); 55 | std::cout << "Tree:" << std::endl; 56 | 57 | do 58 | { 59 | // space between nodes 60 | std::string space((size - 1) * (placeholder.length() + 1) + 1, ' '); 61 | 62 | // margin 63 | std::cout << std::string(space.length() / 2, ' ');; 64 | while (!queue.empty()) 65 | { 66 | if (!queue.front()) 67 | { 68 | std::cout << placeholder << space; 69 | childs.emplace(); 70 | childs.emplace(); 71 | } 72 | else 73 | { 74 | std::cout << std::setw(digits) << std::right << queue.front()->getValue() << space; 75 | childs.push(queue.front()->getLeft()); 76 | childs.push(queue.front()->getRight()); 77 | } 78 | queue.pop(); 79 | } 80 | std::cout << std::endl; 81 | queue.swap(childs); 82 | size /= 2; 83 | } while (size > 0); 84 | } 85 | 86 | // The function treeFromArray from the task 4.2 helps us to fill test trees. 87 | template class N = Node> 89 | auto treeFromArray(const T *array, size_t size) 90 | { 91 | using NodePtr = typename Tree::NodePtr; 92 | 93 | std::function subtreeFromArray = 94 | [&subtreeFromArray](const T *array, const NodePtr &parent, int start, int end) -> NodePtr 95 | { 96 | if (end < start) 97 | return nullptr; 98 | 99 | int i = (start + end) / 2; 100 | auto node = std::make_shared>(array[i], parent); 101 | node->setLeftChild(subtreeFromArray(array, node, start, i - 1)); 102 | node->setRightChild(subtreeFromArray(array, node, i + 1, end)); 103 | return node; 104 | }; 105 | 106 | Tree tree; 107 | tree.setRoot(subtreeFromArray(&array[0], nullptr, 0, size - 1)); 108 | return tree; 109 | } 110 | 111 | template class N = Node> 113 | auto treeFromArray(std::initializer_list array) 114 | { 115 | return treeFromArray(array.begin(), array.size()); 116 | } 117 | 118 | template class N = Node> 120 | auto getSampleTree(size_t nodeCount) 121 | { 122 | std::vector v(nodeCount) ; 123 | std::iota(std::begin(v), std::end(v), 0); // Fill with 0, 1, ..., nodeCount - 1. 124 | return treeFromArray(&v[0], v.size()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Ch 5. Bit Manipulation/C++14/5.1-Insertion.cpp: -------------------------------------------------------------------------------- 1 | // Insertion: You are given two 32-bit numbers, N and M, and two bit positions, i and j. Write a method 2 | // to insert M into N such that M starts at bit j and ends at bit i. You can assume that the bits j through 3 | // i have enough space to fit all of M. That is, if M = 10011, you can assume that there are at least 5 4 | // bits between j and i. You would not, for example, have j = 3 and i = 2, because M could not fully 5 | // fit between bit 3 and bit 2. 6 | // EXAMPLE 7 | // Input: N = 10000000000, M = 10011, i = 2, j = 6 8 | // Output: N = 10001001100 9 | 10 | #include 11 | #include 12 | 13 | #include "bitutils.hpp" 14 | 15 | int32_t insertion(int32_t N, int32_t M, int i, int j) 16 | { 17 | int w = j - i; 18 | if (w <= 0) 19 | return N; 20 | 21 | int32_t maskN = (~0 << (j + 1)) | ((1 << i) - 1); 22 | return (N & maskN) | (M << i); 23 | } 24 | 25 | int main() 26 | { 27 | auto result = insertion(0b10000000000, 0b10011, 2, 6); 28 | std::cout << bits(result); 29 | } 30 | -------------------------------------------------------------------------------- /Ch 5. Bit Manipulation/C++14/5.2-BinaryToString.cpp: -------------------------------------------------------------------------------- 1 | // Binary to String: Given a real number between 0 and 1 (e.g., 0.72) that is passed in as a double, 2 | // print the binary representation. If the number cannot be represented accurately in binary with at 3 | // most 32 characters, print "ERROR:' 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | std::string binaryToStringMul(double binary) 13 | { 14 | std::stringstream str; 15 | if (binary < 0 || binary > 1) 16 | return "ERROR"; 17 | if (binary == 1) 18 | return "1"; 19 | if (binary == 0) 20 | return "0"; 21 | 22 | str << "0."; 23 | 24 | while (binary != 0) 25 | { 26 | if (str.tellp() > 32) 27 | return "ERROR"; 28 | 29 | binary *= 2; 30 | if (binary >= 1) 31 | { 32 | str << '1'; 33 | binary -= 1; 34 | } 35 | else 36 | str << '0'; 37 | } 38 | return str.str(); 39 | } 40 | 41 | std::string binaryToStringDiv(double binary) 42 | { 43 | std::stringstream str; 44 | if (binary < 0 || binary > 1) 45 | return "ERROR"; 46 | if (binary == 1) 47 | return "1"; 48 | if (binary == 0) 49 | return "0"; 50 | 51 | double mantissaBit = 0.5; 52 | str << "0."; 53 | 54 | while (binary != 0) 55 | { 56 | if (str.tellp() > 32) 57 | return "ERROR"; 58 | 59 | if (binary >= mantissaBit) 60 | { 61 | str << '1'; 62 | binary -= mantissaBit; 63 | } 64 | else 65 | str << '0'; 66 | mantissaBit /= 2; 67 | } 68 | return str.str(); 69 | } 70 | 71 | int main() 72 | { 73 | double value = 0; 74 | double frac = 1.0 / 2 + 1.0 / 8; 75 | 76 | std::cout << std::setprecision(std::numeric_limits::digits10 + 1); 77 | 78 | for (int i = 0; i < 10; ++i) 79 | { 80 | std::cout << value << ": " << binaryToStringMul(value) << "(b), " << binaryToStringDiv(value) << "(b)\n"; 81 | value += frac; 82 | frac /= 16; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Ch 5. Bit Manipulation/C++14/5.3-FlipBitToWin.cpp: -------------------------------------------------------------------------------- 1 | // Flip Bit to Win: You have an integer and you can flip exactly one bit from a O to a 1. Write code to 2 | // find the length of the longest sequence of 1 s you could create. 3 | // EXAMPLE 4 | // Input: 1775 (or: 11011101111) 5 | // Output: 8 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "bitutils.hpp" 14 | 15 | template 16 | int flipToWin(T bits) 17 | { 18 | static_assert(std::is_unsigned::value, "T must be unsigned integral type"); 19 | 20 | int result = 1; 21 | int lenLeft = 0; 22 | int lenRight = 0; 23 | while (bits != 0) 24 | { 25 | if (bits & 1) 26 | ++lenLeft; 27 | else 28 | { 29 | // The current bit is 0 means that we counted right sequence length. 30 | // If the next bit will be 0, then right sequence length will reset to 0. 31 | lenRight = lenLeft; 32 | lenLeft = 0; 33 | } 34 | bits >>= 1; 35 | result = std::max(lenRight + lenLeft + 1, result); 36 | } 37 | // We can not flip bit to 1 if there was no bit 0 38 | return std::min(result, std::numeric_limits::digits); 39 | } 40 | 41 | int main() 42 | { 43 | for (auto testValue : { 44 | 0b11011101111U 45 | , 0b110111001111U 46 | , 0b1100111001111U 47 | , 0U 48 | , ~0U 49 | }) 50 | std::cout << bits(testValue) << ": " << flipToWin(testValue) << std::endl; 51 | } 52 | -------------------------------------------------------------------------------- /Ch 5. Bit Manipulation/C++14/5.4-NextNumber.cpp: -------------------------------------------------------------------------------- 1 | // Next Number: Given a positive integer, print the next smallest and the previous largest number that 2 | // have the same number of 1 bits in their binary representation. 3 | 4 | #include 5 | #include 6 | #include "bitutils.hpp" 7 | 8 | template 9 | std::tuple nextBiggerSmaller(T v) 10 | { 11 | static_assert(std::is_unsigned::value, "T must be unsigned integral type"); 12 | 13 | auto result = std::make_tuple(0U, 0U); 14 | T rightZeros = 0; // tail zero count 15 | T rightOnes = 0; // count of tightmost ones between zeros 16 | T zeroPos = 0; // first/rightmost zero of 01 bits 17 | T tmp = v; 18 | 19 | while (tmp != 0 && !(tmp & 1)) 20 | { 21 | ++rightZeros; 22 | tmp >>= 1; 23 | } 24 | while (tmp != 0 && (tmp & 1)) 25 | { 26 | ++rightOnes; 27 | tmp >>= 1; 28 | } 29 | zeroPos = rightZeros + rightOnes; 30 | if (0 < zeroPos && zeroPos < std::numeric_limits::digits) 31 | { 32 | tmp = v | (1 << zeroPos); // rightmost non-trailing zero to 1 33 | // at this point we have one more bit 1 34 | tmp &= ~((1 << zeroPos) - 1); // reset all bits right from previously set 35 | tmp |= (1 << (rightOnes - 1)) - 1; // set rightOnes - 1 rightmost bits to 1 36 | std::get<1>(result) = tmp; 37 | } 38 | 39 | rightOnes = rightZeros = 0; 40 | tmp = v; 41 | 42 | while (tmp != 0 && (tmp & 1)) 43 | { 44 | ++rightOnes; 45 | tmp >>= 1; 46 | } 47 | while (tmp != 0 && !(tmp & 1)) 48 | { 49 | ++rightZeros; 50 | tmp >>= 1; 51 | } 52 | T onePos = rightZeros + rightOnes; // first/rightmost one of 10 bits 53 | if (0 < onePos && onePos < std::numeric_limits::digits) 54 | { 55 | tmp = v & ~(1 << onePos); // rightmost non-trailing 1 to zero 56 | // at this point we have one bit 1 less 57 | tmp |= (1 << onePos) - 1; // set all bits right from previously reset to 0 58 | tmp &= ~((1 << (rightZeros - 1)) - 1); // reset rightZeros - 1 rightmost bits to 0 59 | std::get<0>(result) = tmp; 60 | } 61 | 62 | return result; 63 | } 64 | 65 | int main() 66 | { 67 | for (uint16_t v : { 68 | 0b11011101111U 69 | , 0U 70 | , 0b1111111111111111U 71 | , 0b0111111111111111U 72 | , 0b1111111111111110U}) 73 | { 74 | auto minMax = nextBiggerSmaller(v); 75 | auto nextMin = std::get<1>(minMax); 76 | auto prevMax = std::get<0>(minMax); 77 | std::cout << v << " (" << bits(v) << "b " << countBits(v) << " bits)\nNext min: "; 78 | if (nextMin > 0) 79 | std::cout << nextMin << " (" << bits(nextMin) << "b " << countBits(static_cast(nextMin)) << " bits)"; 80 | else 81 | std::cout << "Not existing"; 82 | std::cout << "\nPrev max: "; 83 | if (prevMax > 0) 84 | std::cout << prevMax << " (" << bits(prevMax) << "b " << countBits(static_cast(prevMax)) << " bits)"; 85 | else 86 | std::cout << "Not existing"; 87 | std::cout << std::endl << std::endl; 88 | } 89 | 90 | uint8_t v = 1; // rightmost 91 | do 92 | { 93 | std::cout << bits(v) << '\n'; 94 | v = std::get<1>(nextBiggerSmaller(v)); 95 | } 96 | while (v != 0); 97 | std::cout << std::endl; 98 | v = 1 << (std::numeric_limits::digits - 1); 99 | do 100 | { 101 | std::cout << bits(v) << '\n'; 102 | v = std::get<0>(nextBiggerSmaller(v)); 103 | } 104 | while (v != 0); 105 | } 106 | -------------------------------------------------------------------------------- /Ch 5. Bit Manipulation/C++14/bitutils.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template ::digits> 6 | std::bitset bits(const T &value) 7 | { 8 | return std::bitset(value); 9 | } 10 | 11 | template 12 | size_t countBits(T v) 13 | { 14 | //return std::bitset::digits>(v).count(); 15 | 16 | static_assert(std::is_unsigned::value, "T must be unsigned integral type"); 17 | static_assert(std::numeric_limits::digits <= 64, "Max 64 bits of T supported"); 18 | 19 | constexpr const T m5 = static_cast(0x5555555555555555U); 20 | constexpr const T m3 = static_cast(0x3333333333333333U); 21 | constexpr const T m0F = static_cast(0x0F0F0F0F0F0F0F0FU); 22 | v = v - ((v >> 1) & m5); // put count of each 2 bits into those 2 bits 23 | v = (v & m3) + ((v >> 2) & m3); // put count of each 4 bits into those 4 bits 24 | v = (v + (v >> 4)) & m0F; // put count of each byte bits into those bytes 25 | # if 0 26 | constexpr const T m01 = static_cast(0x0101010101010101U); 27 | v = (v * m01); // B7B6..B0 --> (B7+B6+...+B0) + (B6+B5+...+B0) + ... + B0 28 | return v >> (std::numeric_limits::digits - 8); 29 | # else 30 | if (std::numeric_limits::digits > 8) 31 | v = (v + (v >> 8)); 32 | if (std::numeric_limits::digits > 16) 33 | v = (v + (v >> 16)); 34 | if (std::numeric_limits::digits > 32) 35 | v = (v + (v >> 32)); 36 | return v & 0xFF; 37 | # endif 38 | } 39 | -------------------------------------------------------------------------------- /Ch 6. Math and Logic Puzzles/7.The Apocalypse/The Apocalypse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void std::vector runOneFamily() 6 | { 7 | Random *random = new Random(); 8 | int boys = 0; 9 | int girls = 0; 10 | while (girls == 0) 11 | { 12 | if (random->nextBoolean()) 13 | { 14 | girls += 1; 15 | } 16 | else 17 | { 18 | boys += 1; 19 | } 20 | } 21 | std::vector genders = {girls, boys}; 22 | return genders; 23 | } 24 | 25 | double runNFamilies(int n) 26 | { 27 | int boys = 0; 28 | int girls = 0; 29 | for (int i = 0; i < n; i++) 30 | { 31 | std::vector genders = runOneFamily(); 32 | girls += genders[0]; 33 | boys += genders[1]; 34 | } 35 | return girls / static_cast(boys + girls); 36 | } 37 | 38 | static void main(std::vector &args) 39 | { 40 | double ratio = runNFamilies(10000000); 41 | std::wcout << ratio << std::endl; 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Ch 6. Math and Logic Puzzles/Intro/Prime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() 6 | { 7 | int i,j,sq; 8 | int min; 9 | for(sq = 2; sq <= 10; sq++) 10 | { 11 | min = (sq-1)*(sq-1); 12 | min = min + (min+1)%2; 13 | for(i = min; i < sq*sq; i+=2) 14 | { 15 | for(j = 3; j <= sq; j+=2) 16 | { 17 | if (i%j == 0) 18 | bad; 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Ch 6. Math and Logic Puzzles/Intro/SieveOfEratosthenes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void crossOff(std::vector &flags, int prime) 7 | { 8 | for (int i = prime * prime; i < flags.size(); i += prime) 9 | { 10 | flags[i] = false; 11 | } 12 | } 13 | 14 | int getNextPrime(std::vector &flags, int prime) 15 | { 16 | int next = prime + 1; 17 | while (next < flags.size() && !flags[next]) 18 | { 19 | next++; 20 | } 21 | return next; 22 | } 23 | 24 | void init(std::vector &flags) 25 | { 26 | flags[0] = false; 27 | flags[1] = false; 28 | for (int i = 2; i < flags.size(); i++) 29 | { 30 | flags[i] = true; 31 | } 32 | } 33 | 34 | void std::vector prune(std::vector &flags, int count) 35 | { 36 | std::vector primes(count); 37 | int index = 0; 38 | for (int i = 0; i < flags.size(); i++) 39 | { 40 | if (flags[i]) 41 | { 42 | primes[index] = i; 43 | index++; 44 | } 45 | } 46 | return primes; 47 | } 48 | 49 | void std::vector sieveOfEratosthenes(int max) 50 | { 51 | std::vector flags(max + 1); 52 | 53 | init(flags); 54 | int prime = 2; 55 | 56 | while (prime <= sqrt(max)) 57 | { 58 | 59 | crossOff(flags, prime); 60 | 61 | 62 | prime = getNextPrime(flags, prime); 63 | } 64 | 65 | return flags; 66 | } 67 | 68 | void main(std::vector &args) 69 | { 70 | std::vector primes = sieveOfEratosthenes(4); 71 | for (int i = 0; i < primes.size(); i++) 72 | { 73 | if (primes[i]) 74 | { 75 | std::wcout << i << std::endl; 76 | } 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Ch 7.OOD/1.Deck Of Cards/BlackJackCard.cpp: -------------------------------------------------------------------------------- 1 | class BlackJackCard : public Card 2 | { 3 | public: 4 | BlackJackCard(int c, Suit *s) : Card(c, s) 5 | { 6 | } 7 | 8 | virtual int value() 9 | { 10 | if (isAce()) 11 | { 12 | return 1; 13 | } 14 | else if (faceValue >= 11 && faceValue <= 13) 15 | { 16 | return 10; 17 | } 18 | else 19 | { 20 | return faceValue; 21 | } 22 | } 23 | 24 | virtual int minValue() 25 | { 26 | if (isAce()) 27 | { 28 | return 1; 29 | } 30 | else 31 | { 32 | return value(); 33 | } 34 | } 35 | 36 | virtual int maxValue() 37 | { 38 | if (isAce()) 39 | { 40 | return 11; 41 | } 42 | else 43 | { 44 | return value(); 45 | } 46 | } 47 | 48 | virtual bool isAce() 49 | { 50 | return faceValue == 1; 51 | } 52 | 53 | virtual bool isFaceCard() 54 | { 55 | return faceValue >= 11 && faceValue <= 13; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /Ch 7.OOD/1.Deck Of Cards/BlackJackHand.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class BlackJackHand : public Hand 5 | { 6 | public: 7 | BlackJackHand() 8 | { 9 | 10 | } 11 | 12 | virtual int score() 13 | { 14 | std::vector scores = possibleScores(); 15 | int maxUnder = std::numeric_limits::min(); 16 | int minOver = std::numeric_limits::max(); 17 | for (auto score : scores) 18 | { 19 | if (score > 21 && score < minOver) 20 | { 21 | minOver = score; 22 | } 23 | else if (score <= 21 && score > maxUnder) 24 | { 25 | maxUnder = score; 26 | } 27 | } 28 | return maxUnder == std::numeric_limits::min() ? minOver : maxUnder; 29 | } 30 | 31 | private: 32 | void std::vector possibleScores() 33 | { 34 | std::vector scores; 35 | if (cards->size() == 0) 36 | { 37 | return scores; 38 | } 39 | for (BlackJackCard *card : cards) 40 | { 41 | addCardToScoreList(card, scores); 42 | } 43 | return scores; 44 | } 45 | 46 | void addCardToScoreList(BlackJackCard *card, std::vector &scores) 47 | { 48 | if (scores.empty()) 49 | { 50 | scores.push_back(0); 51 | } 52 | int length = scores.size(); 53 | for (int i = 0; i < length; i++) 54 | { 55 | int score = scores[i]; 56 | scores[i] = score + card->minValue(); 57 | if (card->minValue() != card->maxValue()) 58 | { 59 | scores.push_back(score + card->maxValue()); 60 | } 61 | } 62 | } 63 | 64 | public: 65 | virtual bool busted() 66 | { 67 | return score() > 21; 68 | } 69 | 70 | virtual bool is21() 71 | { 72 | return score() == 21; 73 | } 74 | 75 | virtual bool isBlackJack() 76 | { 77 | if (cards->size() != 2) 78 | { 79 | return false; 80 | } 81 | BlackJackCard *first = cards->get(0); 82 | BlackJackCard *second = cards->get(1); 83 | return (first->isAce() && second->isFaceCard()) || (second->isAce() && first->isFaceCard()); 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /Ch 7.OOD/1.Deck Of Cards/card.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | class Card 6 | { 7 | private: 8 | bool available = true; 9 | 10 | protected: 11 | int faceValue = 0; 12 | 13 | Suit *suit_Renamed; 14 | 15 | public: 16 | Card(int c, Suit *s) 17 | { 18 | faceValue = c; 19 | suit_Renamed = s; 20 | } 21 | 22 | virtual int value() = 0; 23 | 24 | virtual Suit *suit() 25 | { 26 | return suit_Renamed; 27 | } 28 | 29 | 30 | virtual bool isAvailable() 31 | { 32 | return available; 33 | } 34 | 35 | virtual void markUnavailable() 36 | { 37 | available = false; 38 | } 39 | 40 | virtual void markAvailable() 41 | { 42 | available = true; 43 | } 44 | 45 | virtual void print() 46 | { 47 | std::vector faceValues = {L"A", L"2", L"3", L"4", L"5", L"6", L"7", L"8", L"9", L"10", L"J", L"Q", L"K"}; 48 | std::wcout << faceValues[faceValue - 1]; 49 | switch (suit_Renamed) 50 | { 51 | case Club: 52 | std::wcout << std::wstring(L"c"); 53 | break; 54 | case Heart: 55 | std::wcout << std::wstring(L"h"); 56 | break; 57 | case Diamond: 58 | std::wcout << std::wstring(L"d"); 59 | break; 60 | case Spade: 61 | std::wcout << std::wstring(L"s"); 62 | break; 63 | } 64 | std::wcout << std::wstring(L" "); 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /Chapter-10-Sorting-and-Searching/10-1-Sorted-Merge/10-1-Sorted-Merge.cpp: -------------------------------------------------------------------------------- 1 | // Created on: 02/12/2020 (dd/mm/yyyy) 2 | // 3 | // Question 10.1 4 | // Sorted Merge 5 | // 6 | // Explanation: 7 | // To merge the two arrays, we keep an index of the current element in arrays A and B, and compare the values 8 | // each time to determine which element will be chosen. To avoid creating a third array that holds each value 9 | // temporarily, we start from the end where A has empty space, so that we can use A without overwriting any 10 | // elements. 11 | #include 12 | 13 | void merge(int A[], int N, int B[], int M) 14 | { 15 | int i = N-1; // current index for array A 16 | int j = M-1; // current index for array B 17 | int k = N+M-1; // current index for merged array 18 | 19 | while (i >= 0 && j >= 0) { 20 | if (i < 0) { 21 | // if we are done with A, just copy the rest of B to the merged array 22 | // if we are done with B, then no need to do anything 23 | while (j >= 0) { 24 | A[k] = B[j]; 25 | j--; 26 | k--; 27 | } 28 | break; 29 | } 30 | if (A[i] <= B[j]) { 31 | A[k] = B[j]; 32 | j--; 33 | } 34 | else { 35 | A[k] = A[i]; 36 | i--; 37 | } 38 | k--; 39 | } 40 | 41 | return; 42 | } 43 | 44 | int main() 45 | { 46 | // As an example, we can use: 47 | int A[5] = {1, 3, 5, 7, 9}; 48 | int B[4] = {2, 4, 6, 8}; 49 | 50 | // print arrays before 51 | std::cout << "\nArray A before: "; 52 | for (int a = 0; a < 5; a++) { 53 | std::cout << A[a] << " "; 54 | } 55 | std::cout << "\nArray B before: "; 56 | for (int a = 0; a < 4; a++) { 57 | std::cout << B[a] << " "; 58 | } 59 | 60 | merge(A, 5, B, 4); 61 | 62 | // print merged array 63 | int total_size = 4+5; 64 | std::cout << "\nMerged Array: "; 65 | for (int a = 0; a < total_size; a++) { 66 | std::cout << A[a] << " "; 67 | } 68 | 69 | return 0; 70 | } -------------------------------------------------------------------------------- /Chapter-10-Sorting-and-Searching/10-2-Group-Anagrams/10-2-Group-Anagrams.cpp: -------------------------------------------------------------------------------- 1 | // Created on: 11/12/2020 (dd/mm/yyyy) 2 | // 3 | // Question 10.2 4 | // Group Anagrams 5 | // 6 | // Explanation: 7 | // To check if two strings are anagrams of each other, we use a simple function that sorts them (by character) and 8 | // checks if they are the same string. To sort the string array we start from the leftmost element and compare it to 9 | // all other elements, moving all the anagrams to the right of it. Then we go to the first element that isn't an 10 | // anagram of these and do the same process until we reach the end of the array. 11 | #include 12 | #include 13 | #include 14 | 15 | bool anagram_check(std::string s1,std::string s2) // checks if two strings are anagrams of each other 16 | { 17 | if (s1.size() != s2.size()) return false; 18 | std::sort(s1.begin(), s1.end()); 19 | std::sort(s2.begin(), s2.end()); 20 | return s1 == s2; 21 | } 22 | 23 | void group_anagrams(std::string arr[], int size) 24 | { 25 | int cur_index = 0; 26 | while (cur_index < size) { 27 | // in each loop we start with the element at cur_index and move all the anagrams to the right of it 28 | for (int i = cur_index + 1; i < size; i++) { 29 | if (anagram_check(arr[cur_index], arr[i])) { 30 | cur_index++; 31 | std::string temp = arr[i]; 32 | arr[i] = arr[cur_index]; 33 | arr[cur_index] = temp; 34 | } 35 | } 36 | cur_index++; 37 | } 38 | 39 | } 40 | 41 | 42 | int main() 43 | { 44 | // As an example, we can use: 45 | std::string s[6] = {"abcd", "asleep", "notananagram", "cdba", "please", "dcba"}; 46 | 47 | // print array before 48 | std::cout << "Array before: "; 49 | for (int i = 0; i < 6; i++) { 50 | std::cout << s[i] << " "; 51 | } 52 | 53 | group_anagrams(s, 6); 54 | 55 | // print array after 56 | std::cout << "\nArray after: "; 57 | for (int i = 0; i < 6; i++) { 58 | std::cout << s[i] << " "; 59 | } 60 | 61 | return 0; 62 | } -------------------------------------------------------------------------------- /Chapter-16-moderate/test_word_freq: -------------------------------------------------------------------------------- 1 | aa bb cc aa dd aa 2 | xxaa 3 | 4 | xx aa 5 | yy 6 | zz 7 | 8 | -------------------------------------------------------------------------------- /Chapter-16-moderate/word_freq.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | /*count freq 12 | * 13 | * 14 | * 15 | * @parmas: 16 | * filename - the book file name to read the lines and words from 17 | * word - the word to lookup for in the book 18 | * @return value: 19 | * integer - the number of occurences in the document 20 | * 21 | * Assumptions: 22 | * word is a match even is upper case and lower case are not match 23 | * the word maybe part of a line 24 | * 25 | */ 26 | 27 | int countWordFreq(const string & fileName, const string &word) 28 | { 29 | cout << "file path is: " << fileName << endl; 30 | ifstream ifn(fileName); 31 | static map wordFreq; 32 | string tword; 33 | transform(word.begin(), word.end(), tword.begin(), ::tolower); 34 | 35 | if (!wordFreq.empty()) { 36 | cout << "wordFreq is not empty" << endl; 37 | cout << wordFreq[word] << endl; 38 | return wordFreq[word]; 39 | } 40 | 41 | string line; 42 | while (getline(ifn, line)) { 43 | if(line.empty()) { continue; } 44 | stringstream ss(line); 45 | string w; 46 | while(ss >> w) { 47 | transform(w.begin(), w.end(), w.begin(), ::tolower); 48 | wordFreq[w]++; 49 | } 50 | } 51 | 52 | return wordFreq[word]; 53 | } 54 | 55 | int main() 56 | { 57 | string fileName; 58 | 59 | cout << "type the book file (full path): " << endl; 60 | cin >> fileName; 61 | //cout << countWordFreq("../input/test_word_freq", "aa") << endl; 62 | cout << countWordFreq(fileName, "aa") << endl; 63 | 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.1-Three-in-One/FixedMultiStack.cpp: -------------------------------------------------------------------------------- 1 | #include "FixedMultiStack.h" 2 | 3 | FixedMultiStack::FixedMultiStack(int stackCapacity) 4 | { 5 | this->stackCapacity = stackCapacity; 6 | stackArray = new int[numOfStack * stackCapacity](); 7 | stackCapacityUsed = new int[numOfStack](); 8 | } 9 | 10 | FixedMultiStack::~FixedMultiStack() 11 | { 12 | delete [] stackArray; 13 | delete [] stackCapacityUsed; 14 | } 15 | 16 | void FixedMultiStack::push(int stackNum, int value) 17 | { 18 | if(isFull(stackNum)) 19 | std::cout << "Stack " << stackNum << " is full.\n"; 20 | else 21 | { 22 | stackCapacityUsed[stackNum]++; 23 | stackArray[indexOfTop(stackNum)] = value; 24 | } 25 | } 26 | 27 | void FixedMultiStack::pop(int stackNum) 28 | { 29 | if(isEmpty(stackNum)) 30 | std::cout << "Stack " << stackNum << " is empty.\n"; 31 | else 32 | { 33 | int topIndex = indexOfTop(stackNum); 34 | stackArray[topIndex] = 0; 35 | stackCapacityUsed[stackNum]--; 36 | } 37 | } 38 | 39 | int FixedMultiStack::top(int stackNum) const 40 | { 41 | if(isEmpty(stackNum)) 42 | { 43 | std::cout << "Stack " << stackNum << " is empty.\n"; 44 | exit(1); //Or throw an exception. 45 | } 46 | else 47 | return stackArray[indexOfTop(stackNum)]; 48 | } 49 | 50 | bool FixedMultiStack::isEmpty(int stackNum) const 51 | { 52 | return (stackCapacityUsed[stackNum] == 0); 53 | } 54 | 55 | bool FixedMultiStack::isFull(int stackNum) const 56 | { 57 | return (stackCapacityUsed[stackNum] == stackCapacity); 58 | } 59 | 60 | int FixedMultiStack::indexOfTop(int stackNum) const 61 | { 62 | int startIndex = stackNum * stackCapacity; 63 | int capacity = stackCapacityUsed[stackNum]; 64 | return (startIndex + capacity - 1); 65 | } 66 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.1-Three-in-One/FixedMultiStack.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class FixedMultiStack 5 | { 6 | public: 7 | //Create 3 stacks, each stack is of size stackCapacity. 8 | FixedMultiStack(int stackCapacity); 9 | virtual ~FixedMultiStack(); 10 | 11 | //Push an element onto stack stackNum, where stackNum is from 0 to 2. 12 | void push(int stackNum, int value); 13 | 14 | //Pop the top element from stack stackNum, where stackNum is from 0 to 2. 15 | void pop(int stackNum); 16 | 17 | //Return the top element on stack stackNum, where stackNum is from 0 to 2. 18 | int top(int stackNum) const; 19 | 20 | bool isEmpty(int stackNum) const; 21 | bool isFull(int stackNum) const; 22 | 23 | private: 24 | int numOfStack = 3; 25 | int stackCapacity; 26 | int *stackArray; 27 | int *stackCapacityUsed; 28 | 29 | //Return the top index of stack stackNum, where stackNum is from 0 to 2. 30 | int indexOfTop(int stackNum) const; 31 | }; 32 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.2-Stack-Min/Stack.cpp: -------------------------------------------------------------------------------- 1 | #include "Stack.h" 2 | 3 | Stack::Stack() 4 | { 5 | head = nullptr; 6 | stackSize = 0; 7 | } 8 | 9 | Stack::~Stack() 10 | { 11 | StackNode *discard; 12 | while(head != nullptr) 13 | { 14 | discard = head; 15 | head = head->next; 16 | delete discard; 17 | } 18 | } 19 | 20 | void Stack::push(int item) 21 | { 22 | if(isEmpty()) 23 | { 24 | head = new StackNode(item, nullptr); 25 | head->minimum = head; 26 | } 27 | else if(item <= head->minimum->data) 28 | { 29 | head = new StackNode(item, head); 30 | head->minimum = head; 31 | } 32 | else 33 | { 34 | head = new StackNode(item, head); 35 | head->minimum = head->next->minimum; 36 | } 37 | 38 | stackSize++; 39 | } 40 | 41 | void Stack::pop() 42 | { 43 | if(stackSize == 0 || head == nullptr) 44 | return; 45 | 46 | StackNode *discard = head; 47 | head = head->next; 48 | delete discard; 49 | stackSize--; 50 | } 51 | 52 | int Stack::top() const 53 | { 54 | //Or throw an exception 55 | if(stackSize == 0 || head == nullptr) 56 | { 57 | std::cout << "Stack is empty.\n"; 58 | exit(1); 59 | } 60 | return head->data; 61 | } 62 | 63 | int Stack::getMinimum() const 64 | { 65 | //Or throw an exception 66 | if(stackSize == 0 || head == nullptr) 67 | { 68 | std::cout << "Stack is empty.\n"; 69 | exit(1); 70 | } 71 | return (head->minimum->data); 72 | } 73 | 74 | bool Stack::isEmpty() const 75 | { 76 | return (stackSize == 0 || head == nullptr); 77 | } 78 | 79 | int Stack::getSize() const 80 | { 81 | return stackSize; 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.2-Stack-Min/Stack.h: -------------------------------------------------------------------------------- 1 | #ifndef STACK_H 2 | #define STACK_H 3 | 4 | #include "StackNode.h" 5 | #include 6 | #include 7 | 8 | class Stack 9 | { 10 | public: 11 | Stack(); 12 | virtual ~Stack(); 13 | void push(int item); 14 | void pop(); 15 | int top() const; 16 | int getMinimum() const; 17 | 18 | bool isEmpty() const; 19 | int getSize() const; 20 | 21 | private: 22 | StackNode *head; 23 | int stackSize; 24 | }; 25 | 26 | #endif // STACK_H 27 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.2-Stack-Min/StackNode.cpp: -------------------------------------------------------------------------------- 1 | #include "StackNode.h" 2 | 3 | StackNode::StackNode(int data, StackNode *next) 4 | { 5 | this->data = data; 6 | this->next = next; 7 | minimum = nullptr; 8 | } 9 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.2-Stack-Min/StackNode.h: -------------------------------------------------------------------------------- 1 | #ifndef STACKNODE_H 2 | #define STACKNODE_H 3 | 4 | class Stack; 5 | 6 | class StackNode 7 | { 8 | public: 9 | friend class Stack; 10 | StackNode(int data, StackNode *next); 11 | 12 | private: 13 | int data; 14 | StackNode *next; 15 | StackNode *minimum; 16 | }; 17 | 18 | #endif // STACKNODE_H 19 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/3.2_stack_min.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Cracking the coding interview edition 6 3 | * Problem 3-2 : Return the min from a stack. 4 | */ 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | //Using an additional stack keeping track of the mins. 11 | class stackWithMin{ 12 | private: 13 | stack s1, s2; 14 | 15 | public: 16 | void push(int x){ 17 | s1.push(x); 18 | if(min()>=x){ 19 | s2.push(x); 20 | } 21 | } 22 | void pop(){ 23 | if(min()==s1.top()){ 24 | s2.pop(); 25 | } 26 | s1.pop(); 27 | } 28 | int min(){ 29 | if(s2.empty()){ 30 | return INT_MAX; //Maximum value for an object of type int (climits is used) 31 | } 32 | return s2.top(); 33 | } 34 | bool empty(){ 35 | return s1.empty(); 36 | } 37 | int top(){ 38 | return s1.top(); 39 | } 40 | }; 41 | 42 | int main(){ 43 | stackWithMin myStack; 44 | int stacktop; 45 | int arr[] = {6, 3, 5, 2, 2, 9, 2, 8, 1, 1}; 46 | for(int i=0; i<10; i++){ 47 | myStack.push(arr[i]); 48 | cout<<"push in the element "< 6 | #include 7 | #include 8 | using namespace std; 9 | #define STACK_NUM 100 10 | 11 | class newStack{ 12 | private: 13 | stack *myStack; 14 | int threshold; 15 | int curStack; 16 | public: 17 | newStack(){ 18 | threshold = 10; 19 | myStack = new stack[STACK_NUM]; //allocates the memory of an array of stacks 20 | curStack = 0; 21 | } 22 | void push(int data){ 23 | if(myStack[curStack].size()>=threshold){ 24 | curStack++; 25 | } 26 | myStack[curStack].push(data); 27 | } 28 | void pop(){ 29 | if(myStack[curStack].empty()){ 30 | if(curStack == 0){ 31 | cout<<"Current stack is empty\n"; 32 | return; 33 | } 34 | curStack--; 35 | } 36 | myStack[curStack].pop(); 37 | } 38 | int top(){ 39 | if(myStack[curStack].empty()){ 40 | if(curStack == 0){ 41 | return INT_MIN; 42 | } 43 | curStack--; 44 | } 45 | return myStack[curStack].top(); 46 | } 47 | bool empty(){ 48 | if(curStack == 0){ 49 | return myStack[curStack].empty(); 50 | } 51 | else 52 | return false; 53 | } 54 | void popAt(int index){ 55 | if(myStack[index].empty()){ 56 | cout< 7 | #include 8 | using namespace std; 9 | 10 | 11 | /*EnQueue(x) 12 | 1) Push x to stack1 (assuming size of stacks is unlimited). 13 | 14 | DeQueue(x) 15 | 1) If both stacks are empty then error. 16 | 2) If stack2 is empty 17 | While stack1 is not empty, push everything from stack1 to stack2. 18 | 3) Pop the element from stack2 and return it. 19 | */ 20 | 21 | class Queue{ 22 | private: 23 | stack stack1, stack2; 24 | public: 25 | void EnQueue(int data){ 26 | stack1.push(data); 27 | } 28 | int DeQueue(){ 29 | if(stack1.empty() && stack2.empty()){ 30 | printf("Queue is empty!"); 31 | getchar(); 32 | exit(0); 33 | } 34 | if(stack2.empty()){ 35 | while(!stack1.empty()){ 36 | stack2.push(stack1.top()); 37 | stack1.pop(); 38 | } 39 | } 40 | int temp = stack2.top(); 41 | stack2.pop(); 42 | return temp; 43 | } 44 | int size(){ 45 | return stack1.size() + stack2.size(); 46 | } 47 | 48 | }; 49 | 50 | int main(){ 51 | Queue q; 52 | for(int i=0; i<10; i++){ 53 | cout<<"EnQueue :"< 7 | #include 8 | using namespace std; 9 | 10 | void sortStack(stack *st){ 11 | stack sorted; //top contains largest element, an additional temporary stack 12 | while(!(*st).empty()){ 13 | int tmp = (*st).top(); 14 | (*st).pop(); 15 | while(!sorted.empty() && tmp mystack; 29 | int arr[] = {6, 4, 8, 9, 10, 99, 7, 1, 100}; 30 | for(int i=0; i 7 | #include 8 | using namespace std; 9 | 10 | class animal{ 11 | private: 12 | queue dog, cat; 13 | int order; 14 | public: 15 | animal(){ 16 | order = 1; 17 | } 18 | int enque(string a){ 19 | if(a=="dog"){ 20 | dog.push(order); 21 | order++; 22 | } 23 | else if(a=="cat"){ 24 | cat.push(order); 25 | order++; 26 | } 27 | return order-1; 28 | } 29 | int dequeAny(){ 30 | int tmp; 31 | if(dog.front()>cat.front()){ 32 | tmp = cat.front(); 33 | cat.pop(); 34 | } 35 | else{ 36 | tmp = dog.front(); 37 | dog.pop(); 38 | } 39 | return tmp; 40 | } 41 | int dequeDog(){ 42 | if(dog.empty()){ 43 | printf("There is no more dogs!"); 44 | getchar(); 45 | exit(0); 46 | } 47 | int tmp = dog.front(); 48 | dog.pop(); 49 | return tmp; 50 | } 51 | int dequeCat(){ 52 | if(cat.empty()){ 53 | printf("There is no more cats!"); 54 | getchar(); 55 | exit(0); 56 | } 57 | int tmp = cat.front(); 58 | cat.pop(); 59 | return tmp; 60 | 61 | } 62 | }; 63 | 64 | int main(){ 65 | animal a; 66 | cout<<"Shelter received an dog with index "< 5 | #include "stack.hpp" 6 | 7 | template 8 | class StackMin 9 | { 10 | public: 11 | template 12 | void push(U &&value) 13 | { 14 | if (minStack.isEmpty() || value <= minStack.peek()) 15 | minStack.push(value); 16 | stack.push(std::forward(value)); 17 | } 18 | 19 | T &peek() 20 | { 21 | return stack.peek(); 22 | } 23 | 24 | T &min() 25 | { 26 | return minStack.peek(); 27 | } 28 | 29 | T pop() 30 | { 31 | auto value = stack.pop(); 32 | if (value == min()) 33 | minStack.pop(); 34 | return value; 35 | } 36 | 37 | bool isEmpty() 38 | { 39 | return stack.isEmpty(); 40 | } 41 | 42 | private: 43 | Stack stack; 44 | Stack minStack; 45 | }; 46 | 47 | int main() 48 | { 49 | StackMin stack; 50 | for (auto v : {5, 10, 4, 9, 3, 3, 8, 2, 2, 7, 6}) 51 | { 52 | stack.push(v); 53 | std::cout << "Pushed value: " << v << ", min value: " << stack.min() << std::endl; 54 | } 55 | while (!stack.isEmpty()) 56 | { 57 | auto v = stack.pop(); 58 | std::cout << "Popped value: " << v; 59 | if (stack.isEmpty()) 60 | std::cout << ", stack is empty" << std::endl; 61 | else 62 | std::cout << ", min value: " << stack.min() << std::endl; 63 | } 64 | return 0; 65 | } -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/3.3-StackOfPlates.cpp: -------------------------------------------------------------------------------- 1 | // Stack of Plates: Imagine a (literal) stack of plates. If the stack gets too high, it might topple. 2 | // Therefore, in real life, we would likely start a new stack when the previous stack exceeds some 3 | // threshold. Implement a data structure SetOfStacks that mimics this. SetOfStacks should be 4 | // composed of several stacks and should create a new stack once a previous one exceeds capacity. 5 | // SetOfStacks.push() and SetOfStacks.pop() should behave identically to a singles stack 6 | // (that is, pop() should return the same values as it would if there just a single stack). 7 | 8 | #include 9 | #include "stack.hpp" 10 | 11 | template 12 | class SetOfStacks 13 | { 14 | public: 15 | template 16 | void push(U &&value) 17 | { 18 | if (stacks.isEmpty() || stacks.peek().size() >= Capacity) 19 | stacks.push(Stack()); // start new stack 20 | stacks.peek().push(std::forward(value)); 21 | } 22 | 23 | T &peek() 24 | { 25 | return stacks.peek().peek(); 26 | } 27 | 28 | T pop() 29 | { 30 | T value = stacks.peek().pop(); 31 | if (stacks.peek().isEmpty()) 32 | stacks.pop(); 33 | return value; 34 | } 35 | 36 | // Number of limited stacks 37 | size_t size() const 38 | { 39 | return stacks.size(); 40 | } 41 | 42 | private: 43 | Stack> stacks; 44 | }; 45 | 46 | // If Capacity is 1 we do not need stack of stacks. 47 | template 48 | class SetOfStacks : public Stack 49 | { 50 | }; 51 | 52 | // Forbid Capacity 0 53 | template 54 | class SetOfStacks 55 | { 56 | public: 57 | SetOfStacks() = delete; 58 | }; 59 | 60 | int main() 61 | { 62 | SetOfStacks stack; 63 | 64 | for (int i = 0; i < 11; ++i) 65 | { 66 | stack.push(i); 67 | std::cout << i << " is pushed into the stack " << stack.size() << std::endl; 68 | } 69 | 70 | std::cout << std::endl; 71 | 72 | while (stack.size() != 0) 73 | { 74 | size_t stackNo = stack.size(); 75 | std::cout << stack.pop() << " is popped from the stack " << stackNo << std::endl; 76 | } 77 | 78 | std::cout << std::endl; 79 | 80 | SetOfStacks stack1; 81 | 82 | for (int i = 0; i < 11; ++i) 83 | { 84 | stack1.push(i); 85 | std::cout << i << " is pushed into the stack " << stack1.size() << std::endl; 86 | } 87 | 88 | std::cout << std::endl; 89 | 90 | while (!stack1.isEmpty()) 91 | { 92 | size_t stackNo = stack1.size(); 93 | std::cout << stack1.pop() << " is popped from the stack " << stackNo << std::endl; 94 | } 95 | 96 | return 0; 97 | } -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/3.3-StackOfPlatesFU.cpp: -------------------------------------------------------------------------------- 1 | // Stack of Plates 2 | // FOLLOW UP 3 | // Implement a function popAt(int index) which performs pop operation on a specified sub-stack. 4 | 5 | #include 6 | #include 7 | 8 | template 9 | class SetOfStacks 10 | { 11 | public: 12 | template 13 | void push(U &&value) 14 | { 15 | if (stacks.empty() || stacks.back().size() >= Capacity) 16 | stacks.emplace_back(1, std::forward(value)); 17 | else 18 | stacks.back().push_back(std::forward(value)); 19 | } 20 | 21 | T &peek() 22 | { 23 | return stacks.back().back(); 24 | } 25 | 26 | T pop() 27 | { 28 | T value = stacks.back().back(); 29 | stacks.back().pop_back(); 30 | if (stacks.back().empty()) 31 | stacks.pop_back(); 32 | return value; 33 | } 34 | 35 | // O(N) 36 | T popAt(int index) 37 | { 38 | if (index < 0 || index >= stacks.size()) 39 | throw OutOfIndexException(); 40 | T value = stacks[index].back(); 41 | stacks[index].pop_back(); 42 | shiftLeftTo(index); 43 | return value; 44 | } 45 | 46 | // Number of used limited stacks 47 | size_t size() const 48 | { 49 | return stacks.size(); 50 | } 51 | 52 | class OutOfIndexException 53 | { 54 | }; 55 | 56 | 57 | private: 58 | 59 | void shiftLeftTo(int index) 60 | { 61 | if (index == stacks.size() - 1) 62 | { 63 | // last stack 64 | if (stacks.back().empty()) 65 | stacks.pop_back(); 66 | } 67 | else 68 | { 69 | stacks[index].push_back(stacks[index + 1].front()); 70 | stacks[index + 1].pop_front(); 71 | shiftLeftTo(index + 1); 72 | } 73 | } 74 | 75 | std::deque> stacks; 76 | }; 77 | 78 | // Special case if capacity is 1. In this case popAt(int index) makes a specified sub-stack empty, 79 | // it should be then removed instead of shifting left values. 80 | template 81 | class SetOfStacks 82 | { 83 | public: 84 | template 85 | void push(U &&value) 86 | { 87 | stacks.push_back(std::forward(value)); 88 | } 89 | 90 | T &peek() 91 | { 92 | return stacks.at(stacks.size() - 1); 93 | } 94 | 95 | T pop() 96 | { 97 | T value = stacks.back(); 98 | stacks.pop_back(); 99 | return value; 100 | } 101 | 102 | T popAt(int index) 103 | { 104 | if (index < 0 || index >= stacks.size()) 105 | throw OutOfIndexException(); 106 | T value = stacks.at(index); 107 | stacks.erase(stacks.begin() + index); 108 | return value; 109 | } 110 | 111 | size_t size() const 112 | { 113 | return stacks.size(); 114 | } 115 | 116 | class OutOfIndexException 117 | { 118 | }; 119 | 120 | 121 | private: 122 | 123 | void shiftLeftTo(int index) 124 | { 125 | if (index == stacks.size() - 1) 126 | { 127 | // last stack 128 | if (stacks.back().empty()) 129 | stacks.pop_back(); 130 | } 131 | else 132 | { 133 | stacks[index].push_back(stacks[index + 1].front()); 134 | stacks[index + 1].pop_front(); 135 | shiftLeftTo(index + 1); 136 | } 137 | } 138 | 139 | std::deque stacks; 140 | }; 141 | 142 | 143 | // Forbid capacity 0 144 | template 145 | class SetOfStacks 146 | { 147 | public: 148 | SetOfStacks() = delete; 149 | }; 150 | 151 | int main() 152 | { 153 | SetOfStacks stack; 154 | for (int i = 0; i < 13; ++i) 155 | { 156 | stack.push(i); 157 | std::cout << i << " is pushed into the stack " << stack.size() << std::endl; 158 | } 159 | 160 | std::cout << std::endl; 161 | stack.popAt(4); 162 | stack.popAt(4); 163 | 164 | while (stack.size() != 0) 165 | { 166 | size_t stackNo = stack.size(); 167 | std::cout << stack.pop() << " is popped from the stack " << stackNo << std::endl; 168 | } 169 | 170 | std::cout << std::endl; 171 | 172 | SetOfStacks stack1; 173 | for (int i = 0; i < 13; ++i) 174 | { 175 | stack1.push(i); 176 | std::cout << i << " is pushed into the stack " << stack1.size() << std::endl; 177 | } 178 | 179 | std::cout << std::endl; 180 | stack1.popAt(4); 181 | stack1.popAt(4); 182 | 183 | while (stack1.size() != 0) 184 | { 185 | size_t stackNo = stack1.size(); 186 | std::cout << stack1.pop() << " is popped from the stack " << stackNo << std::endl; 187 | } 188 | return 0; 189 | } 190 | -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/3.4-QueueViaStacks.cpp: -------------------------------------------------------------------------------- 1 | // Queue via Stacks: Implement a MyQueue class which implements a queue using two stacks. 2 | 3 | #include 4 | #include "stack.hpp" 5 | 6 | template 7 | class MyQueue 8 | { 9 | public: 10 | template 11 | void add(U &&value) 12 | { 13 | newValues.push(std::forward(value)); 14 | } 15 | 16 | T peek() 17 | { 18 | if (reversed.isEmpty()) 19 | move(newValues, reversed); 20 | return reversed.peek(); 21 | } 22 | 23 | T remove() 24 | { 25 | if (reversed.isEmpty()) 26 | move(newValues, reversed); 27 | return reversed.pop(); 28 | } 29 | 30 | bool isEmpty() 31 | { 32 | return newValues.isEmpty() && reversed.isEmpty(); 33 | } 34 | 35 | private: 36 | static void move(Stack &from, Stack &to) 37 | { 38 | while (!from.isEmpty()) 39 | to.push(from.pop()); 40 | } 41 | Stack newValues; 42 | Stack reversed; 43 | }; 44 | 45 | int main() 46 | { 47 | MyQueue queue; 48 | for (int i = 0; i < 10; ++i) 49 | { 50 | queue.add(i); 51 | std::cout << "Queued value " << i << std::endl; 52 | } 53 | 54 | for (int i = 0; i < 5; ++i) 55 | std::cout << "Removed value " << queue.remove() << std::endl; 56 | 57 | for (int i = 10; i < 15; ++i) 58 | { 59 | queue.add(i); 60 | std::cout << "Queued value " << i << std::endl; 61 | } 62 | 63 | while (!queue.isEmpty()) 64 | std::cout << "Removed value " << queue.remove() << std::endl; 65 | 66 | return 1; 67 | } -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/3.5-SortStack.cpp: -------------------------------------------------------------------------------- 1 | // Sort Stack: Write a program to sort a stack such that the smallest items are on the top. You can use 2 | // an additonal temporary stack, but you may not copy the elements into any other data struture 3 | // (such as an array). The stack support the following operations: pop, peek, and isEmpty. 4 | 5 | #include 6 | #include "stack.hpp" 7 | 8 | template 9 | class SortedStack 10 | { 11 | public: 12 | SortedStack() : sorted(false) 13 | { 14 | } 15 | 16 | template 17 | void push(U &&value) 18 | { 19 | stack.push(std::forward(value)); 20 | sorted = false; 21 | } 22 | 23 | T &peek() 24 | { 25 | sort(); 26 | return stack.peek(); 27 | } 28 | 29 | T pop() 30 | { 31 | sort(); 32 | return stack.pop(); 33 | } 34 | 35 | bool isEmpty() const 36 | { 37 | return stack.isEmpty(); 38 | } 39 | 40 | private: 41 | void sort() 42 | { 43 | if (sorted) 44 | return; 45 | 46 | Stack helper; 47 | while (!stack.isEmpty()) 48 | { 49 | T value = stack.pop(); 50 | 51 | // Move greater than 'value' elements from 'helper' to 'stack' 52 | while (!helper.isEmpty() && value < helper.peek()) 53 | stack.push(helper.pop()); 54 | 55 | // Place 'value' above smaller element into 'helper' 56 | helper.push(std::move(value)); 57 | } 58 | 59 | // Copy from 'helper' into 'stack' in reversed order 60 | while (!helper.isEmpty()) 61 | stack.push(helper.pop()); 62 | sorted = true; 63 | } 64 | 65 | Stack stack; 66 | bool sorted; 67 | }; 68 | 69 | int main() 70 | { 71 | SortedStack stack; 72 | for (auto v : {5, 10, 4, 9, 3, 3, 8, 1, 2, 2, 7, 6}) 73 | { 74 | stack.push(v); 75 | std::cout << "Pushed value: " << v << std::endl; 76 | } 77 | 78 | std::cout << std::endl; 79 | 80 | while (!stack.isEmpty()) 81 | { 82 | auto v = stack.pop(); 83 | std::cout << "Popped value: " << v << std::endl; 84 | } 85 | return 0; 86 | } -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/3.6-AnimalShelter.cpp: -------------------------------------------------------------------------------- 1 | // Animal Shelter: An animal shelter, which holds only dogs and cats operates on a strictly "first in, first 2 | // out" basis. People must adopt either the "oldest" (based on arrival time) of all animals at the shelter, 3 | // or they can select whether they would prefer a dog or a cat (and will receive the oldest animal of 4 | // that type). They cannot select which specific animal they would like. Create the data structures to 5 | // maintain this system and implement operations such as enqueue, dequeueAny, dequeueDog, 6 | // and dequeueCat. You may use the built-in LinkedList data structure. 7 | 8 | #include 9 | #include 10 | #include 11 | #include "queue.hpp" 12 | 13 | class Animal 14 | { 15 | protected: 16 | Animal(std::string &&animalName) : name(std::move(animalName)) 17 | { 18 | orderNo = std::numeric_limits::max(); 19 | } 20 | 21 | public: 22 | virtual ~Animal() 23 | { 24 | } 25 | 26 | void setOrder(size_t order) 27 | { 28 | orderNo = order; 29 | } 30 | 31 | size_t getOrder() const 32 | { 33 | return orderNo; 34 | } 35 | 36 | const std::string &getName() const 37 | { 38 | return name; 39 | } 40 | 41 | bool operator < (const Animal &other) 42 | { 43 | return orderNo < other.orderNo; 44 | } 45 | 46 | template 47 | static std::shared_ptr create(std::string &&name) 48 | { 49 | return std::make_shared(std::move(name)); 50 | } 51 | 52 | private: 53 | std::string name; 54 | size_t orderNo; 55 | }; 56 | 57 | class Dog: public Animal 58 | { 59 | public: 60 | Dog(std::string &&name) : Animal(std::move(name)) 61 | { 62 | } 63 | }; 64 | 65 | class Cat: public Animal 66 | { 67 | public: 68 | Cat(std::string &&name) : Animal(std::move(name)) 69 | { 70 | } 71 | }; 72 | 73 | class Shelter 74 | { 75 | public: 76 | Shelter() : nextOrderNo(0) 77 | { 78 | } 79 | 80 | void enqueue(std::shared_ptr &&animal) 81 | { 82 | if (auto dog = std::dynamic_pointer_cast(animal)) 83 | { 84 | dog->setOrder(nextOrderNo++); 85 | dogs.add(std::move(dog)); 86 | } 87 | else if (auto cat = std::dynamic_pointer_cast(animal)) 88 | { 89 | cat->setOrder(nextOrderNo++); 90 | cats.add(std::move(cat)); 91 | } 92 | else 93 | throw BadAnimalException(); 94 | } 95 | 96 | std::shared_ptr dequeueAny() 97 | { 98 | if (dogs.isEmpty()) 99 | return dequeueCat(); 100 | else if (cats.isEmpty()) 101 | return dequeueDog(); 102 | else if (*dogs.peek() < *cats.peek()) 103 | return dequeueDog(); 104 | else 105 | return dequeueCat(); 106 | } 107 | 108 | std::shared_ptr dequeueCat() 109 | { 110 | return std::static_pointer_cast(cats.remove()); 111 | } 112 | 113 | std::shared_ptr dequeueDog() 114 | { 115 | return std::static_pointer_cast(dogs.remove()); 116 | } 117 | 118 | class BadAnimalException {}; 119 | 120 | private: 121 | Queue> dogs; 122 | Queue> cats; 123 | size_t nextOrderNo; 124 | }; 125 | 126 | int main() 127 | { 128 | Shelter shelter; 129 | for (auto name : {"Dog 1", "Cat 1", "Dog 2", "Dog 3 ", "Cat 2", "Cat 3", "Cat 4", "Dog 4", "Dog 5", "Dog 6", "Cat 5", "Cat 6", "Dog 7", "Dog 8", "Cat 7", "Dog 9"}) 130 | { 131 | if (name[0] == 'D') 132 | shelter.enqueue(Animal::create(std::move(name))); 133 | else if (name[0] == 'C') 134 | shelter.enqueue(Animal::create(std::move(name))); 135 | } 136 | 137 | std::cout << "any --> " << shelter.dequeueAny()->getName() << std::endl; 138 | std::cout << "any --> " << shelter.dequeueAny()->getName() << std::endl; 139 | 140 | std::cout << "dog --> " << shelter.dequeueDog()->getName() << std::endl; 141 | std::cout << "cat --> " << shelter.dequeueCat()->getName() << std::endl; 142 | std::cout << "cat --> " << shelter.dequeueCat()->getName() << std::endl; 143 | std::cout << "cat --> " << shelter.dequeueCat()->getName() << std::endl; 144 | std::cout << "cat --> " << shelter.dequeueCat()->getName() << std::endl; 145 | std::cout << "dog --> " << shelter.dequeueDog()->getName() << std::endl; 146 | std::cout << "dog --> " << shelter.dequeueDog()->getName() << std::endl; 147 | std::cout << "cat --> " << shelter.dequeueCat()->getName() << std::endl; 148 | std::cout << "any --> " << shelter.dequeueAny()->getName() << std::endl; 149 | return 0; 150 | } -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/queue.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Queue 5 | { 6 | public: 7 | Queue() : first(nullptr), last(nullptr), queueSize(0) 8 | { 9 | } 10 | 11 | Queue(Queue &&other) : first(std::move(other.first)), last(std::move(other.last)), queueSize(std::move(other.queueSize)) 12 | { 13 | } 14 | 15 | ~Queue() 16 | { 17 | while (!isEmpty()) 18 | remove(); 19 | } 20 | 21 | template 22 | void add(U &&value) 23 | { 24 | auto n = new Node(std::forward(value)); 25 | if (!first) 26 | first = n; 27 | else 28 | last->next = n; 29 | last = n; 30 | ++queueSize; 31 | } 32 | 33 | T &peek() 34 | { 35 | if (!first) 36 | throw QueueIsEmptyException(); 37 | return first->value; 38 | } 39 | 40 | T remove() 41 | { 42 | if (!first) 43 | throw QueueIsEmptyException(); 44 | auto value(std::move(first->value)); 45 | auto n = first; 46 | first = n->next; 47 | if (!first) 48 | last = nullptr; 49 | delete n; 50 | --queueSize; 51 | return value; 52 | } 53 | 54 | bool isEmpty() const 55 | { 56 | return !first; 57 | } 58 | 59 | size_t size() const 60 | { 61 | return queueSize; 62 | } 63 | 64 | class QueueIsEmptyException 65 | { 66 | }; 67 | 68 | private: 69 | struct Node 70 | { 71 | Node(T &&v): value(std::move(v)), next(nullptr) 72 | { 73 | } 74 | 75 | T value; 76 | Node *next; 77 | }; 78 | 79 | Node *first; 80 | Node *last; 81 | size_t queueSize; 82 | }; -------------------------------------------------------------------------------- /Chapter-3-Stacks-and-Queues/C++14/stack.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | class Stack 5 | { 6 | public: 7 | Stack() : top(nullptr), stackSize(0) 8 | { 9 | } 10 | 11 | Stack(Stack &&other) : top(std::move(other.top)), stackSize(std::move(other.stackSize)) 12 | { 13 | } 14 | 15 | ~Stack() 16 | { 17 | while (!isEmpty()) 18 | pop(); 19 | } 20 | 21 | template 22 | void push(U &&value) 23 | { 24 | auto n = new Node(std::forward(value), top); 25 | top = n; 26 | ++stackSize; 27 | } 28 | 29 | T &peek() 30 | { 31 | if (!top) 32 | throw StackIsEmptyException(); 33 | return top->value; 34 | } 35 | 36 | T pop() 37 | { 38 | if (!top) 39 | throw StackIsEmptyException(); 40 | auto value(std::move(top->value)); 41 | auto n = top; 42 | top = n->next; 43 | delete n; 44 | --stackSize; 45 | return value; 46 | } 47 | 48 | bool isEmpty() const 49 | { 50 | return !top; 51 | } 52 | 53 | size_t size() const 54 | { 55 | return stackSize; 56 | } 57 | 58 | class StackIsEmptyException 59 | { 60 | }; 61 | 62 | private: 63 | struct Node 64 | { 65 | Node(T &&v, Node *n): value(std::move(v)), next(n) 66 | { 67 | } 68 | 69 | Node(const T &v, Node *n): value(v), next(n) 70 | { 71 | } 72 | 73 | T value; 74 | Node *next; 75 | }; 76 | 77 | Node *top; 78 | size_t stackSize; 79 | }; 80 | -------------------------------------------------------------------------------- /Chapter-4-tree-and-graph/4.10_check_subtree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | struct node{ 5 | int data; 6 | node *right, *left; 7 | }; 8 | 9 | void createMinimalBst(node* &root, int arr[], int start, int end){ 10 | if(start>end) 11 | return; 12 | if(root==NULL){ 13 | node *ptr = new node; 14 | int ind = start + (end-start)/2; 15 | ptr->data = arr[ind]; 16 | ptr->left = NULL; 17 | ptr->right = NULL; 18 | root = ptr; 19 | createMinimalBst(root->left, arr, start, ind-1); 20 | createMinimalBst(root->right, arr, ind+1, end); 21 | } 22 | } 23 | 24 | /*Implemented the alternative approach described in the book.*/ 25 | bool MatchTree(node* root, node* subRoot){ 26 | if(root == NULL && subRoot == NULL) 27 | return true; 28 | else if(root == NULL || subRoot == NULL) 29 | return false; 30 | else if(root->data != subRoot->data) 31 | return false; 32 | else 33 | return MatchTree(root->left, subRoot->left) && MatchTree(root->right, subRoot->right); 34 | } 35 | 36 | bool isSubTree(node* root, node* subRoot){ 37 | if(root == NULL) 38 | return false; 39 | else if(root->data == subRoot->data && MatchTree(root, subRoot)) 40 | return true; 41 | return isSubTree(root->left, subRoot) || isSubTree(root->right, subRoot); 42 | } 43 | 44 | bool constainsTree(node* root, node* subRoot){ 45 | if(subRoot == NULL) return true; 46 | return isSubTree(root, subRoot); 47 | } 48 | 49 | 50 | int main(){ 51 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; // Bigger Tree 52 | int arr1[] = {1, 2, 3, 4}; // Subtree 53 | node *root, *subRoot; 54 | root = subRoot = NULL; 55 | createMinimalBst(root, arr, 0, 8); 56 | createMinimalBst(subRoot, arr1, 0, 3); 57 | cout<<"Is it a subtree? "< 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | struct node{ 8 | int data; 9 | node *right, *left; 10 | }; 11 | 12 | void createMinimalBst(node* &root, int arr[], int start, int end){ 13 | if(start>end) 14 | return; 15 | if(root==NULL){ 16 | node *ptr = new node; 17 | int ind = start + (end-start)/2; 18 | ptr->data = arr[ind]; 19 | ptr->left = NULL; 20 | ptr->right = NULL; 21 | root = ptr; 22 | createMinimalBst(root->left, arr, start, ind-1); 23 | createMinimalBst(root->right, arr, ind+1, end); 24 | } 25 | } 26 | 27 | /*We use the Reservoir sampling to get a node uniformly at random, 28 | WITHOUT knowing the total number of nodes. 29 | The idea is, do a whatever order of traversal, 30 | if it is the kth node we are traveling, 31 | then replace the previously selected node with probability 1/k. 32 | 33 | (1) Initialize result as first node 34 | result = node 35 | (2) Initialize n = 2 36 | (3) Now one by one consider all nodes from 2nd node onward. 37 | (3.a) Generate a random number from 0 to n-1. 38 | Let the generated random number be j. 39 | (3.b) If j is equal to 0 (we could choose other fixed number 40 | between 0 to n-1), then replace result with current node. 41 | (3.c) n = n+1 42 | (3.d) node = node->left OR node->right determined by the traversal scheme. 43 | */ 44 | node* randomSelect(node* input_node) { 45 | node* selectedNode = input_node; 46 | stack nodeStack; 47 | nodeStack.push(input_node); 48 | srand(time(0)); 49 | int count = 1, j = 1; 50 | while(!nodeStack.empty()){ 51 | node* temp = nodeStack.top(); 52 | nodeStack.pop(); 53 | j = rand(); 54 | cout << "Random number generated: " << j % count <<"\n"; 55 | if(j % count == 0){ 56 | selectedNode = temp; 57 | } 58 | if(temp->left != nullptr) 59 | nodeStack.push(temp->left); 60 | if(temp->right != nullptr) 61 | nodeStack.push(temp->right); 62 | count++; 63 | } 64 | return selectedNode; 65 | } 66 | 67 | int main(){ 68 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 69 | node* root; 70 | root = nullptr; 71 | createMinimalBst(root, arr, 0, 10); 72 | node *random_node = randomSelect(root); 73 | cout<<"A random node is obtained: "<data; 74 | } 75 | -------------------------------------------------------------------------------- /Chapter-4-tree-and-graph/4.2_minimal_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct node{ 6 | int data; 7 | node *right, *left; 8 | }; 9 | 10 | void createBst(node* &root, int arr[], int start, int end){ 11 | if(start>end) 12 | return; 13 | if(root==NULL){ 14 | node *ptr = new node; 15 | int ind = start + (end-start)/2; 16 | ptr->data = arr[ind]; 17 | ptr->left = NULL; 18 | ptr->right = NULL; 19 | root = ptr; 20 | createBst(root->left, arr, start, ind-1); 21 | createBst(root->right, arr, ind+1, end); 22 | } 23 | } 24 | 25 | void postorder(node* p, int indent=0) 26 | { 27 | if(p != NULL) { 28 | if(p->right) { 29 | postorder(p->right, indent+4); 30 | } 31 | if (indent) { 32 | std::cout << std::setw(indent) << ' '; 33 | } 34 | if (p->right) std::cout<<" /\n" << std::setw(indent) << ' '; 35 | std::cout<< p->data << "\n "; 36 | if(p->left) { 37 | std::cout << std::setw(indent) << ' ' <<" \\\n"; 38 | postorder(p->left, indent+4); 39 | } 40 | } 41 | } 42 | 43 | int main(){ 44 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 45 | node* root; 46 | root = NULL; 47 | createBst(root, arr, 0, 8); 48 | printf("Postorder Traversal of constructed BST \n"); 49 | postorder(root); 50 | } 51 | -------------------------------------------------------------------------------- /Chapter-4-tree-and-graph/4.3_list_of_depths.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | struct node{ 7 | int data; 8 | node *right, *left; 9 | }; 10 | 11 | /*We just use the code from last problem, created a binary search tree with minimum height. And then we create linked list at each level of the tree.*/ 12 | 13 | void createMinimalBst(node* &root, int arr[], int start, int end){ 14 | if(start>end) 15 | return; 16 | if(root==NULL){ 17 | node *ptr = new node; 18 | int ind = start + (end-start)/2; 19 | ptr->data = arr[ind]; 20 | ptr->left = NULL; 21 | ptr->right = NULL; 22 | root = ptr; 23 | createMinimalBst(root->left, arr, start, ind-1); 24 | createMinimalBst(root->right, arr, ind+1, end); 25 | } 26 | } 27 | 28 | void findLevelLinkedLists(vector > &res, node* root){ 29 | list li; 30 | li.push_back(root); 31 | res.push_back(li); 32 | int depth = 0; 33 | while(!res[depth].empty()){ 34 | list l; 35 | list::iterator iter; 36 | for(iter = res[depth].begin(); iter!=res[depth].end(); iter++ ){ 37 | node *ptr = *iter; 38 | if(ptr->left) 39 | l.push_back(ptr->left); 40 | if(ptr->right) 41 | l.push_back(ptr->right); 42 | } 43 | res.push_back(l); 44 | depth++; 45 | } 46 | } 47 | 48 | void printLevelLinkedLists(vector > res){ 49 | vector >::iterator iter; 50 | for(iter = res.begin(); iter!= res.end(); iter++){ 51 | list li = *iter; //iter is a pointer to list 52 | list::iterator it; //it is a pointer to node* 53 | for(it = li.begin(); it!=li.end(); it++){ 54 | node* ptr = *it; 55 | cout<data<<" "; 56 | } 57 | cout<<'\n'; 58 | } 59 | } 60 | 61 | int main(){ 62 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 63 | node* root; 64 | root = NULL; 65 | createMinimalBst(root, arr, 0, 8); 66 | vector> level_list; 67 | findLevelLinkedLists(level_list, root); 68 | printLevelLinkedLists(level_list); 69 | } 70 | -------------------------------------------------------------------------------- /Chapter-4-tree-and-graph/4.4_check_balanced.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct node{ 6 | int data; 7 | node *right, *left; 8 | }; 9 | 10 | /*We just use the code from last problem, created a binary search tree with minimum height. Then we check if the tree is balanced.*/ 11 | 12 | void createMinimalBst(node* &root, int arr[], int start, int end){ 13 | if(start>end) 14 | return; 15 | if(root==NULL){ 16 | node *ptr = new node; 17 | int ind = start + (end-start)/2; 18 | ptr->data = arr[ind]; 19 | ptr->left = NULL; 20 | ptr->right = NULL; 21 | root = ptr; 22 | createMinimalBst(root->left, arr, start, ind-1); 23 | createMinimalBst(root->right, arr, ind+1, end); 24 | } 25 | } 26 | int height(struct node* node); 27 | /* Returns true if binary tree with root as root is height-balanced */ 28 | bool isBalanced(struct node *root) 29 | { 30 | int lh; /* for height of left subtree */ 31 | int rh; /* for height of right subtree */ 32 | 33 | /* If tree is empty then return true */ 34 | if(root == NULL) 35 | return 1; 36 | 37 | /* Get the height of left and right sub trees */ 38 | lh = height(root->left); 39 | rh = height(root->right); 40 | 41 | if( abs(lh-rh) <= 1 && 42 | isBalanced(root->left) && 43 | isBalanced(root->right)) 44 | return 1; 45 | 46 | /* If we reach here then tree is not height-balanced */ 47 | return 0; 48 | } 49 | 50 | /* UTILITY FUNCTIONS TO TEST isBalanced() FUNCTION */ 51 | 52 | /* returns maximum of two integers */ 53 | int max(int a, int b) 54 | { 55 | return (a >= b)? a: b; 56 | } 57 | 58 | /* The function Compute the "height" of a tree. Height is the 59 | number of nodes along the longest path from the root node 60 | down to the farthest leaf node.*/ 61 | int height(struct node* node) 62 | { 63 | /* base case tree is empty */ 64 | if(node == NULL) 65 | return 0; 66 | 67 | /* If tree is not empty then height = 1 + max of left 68 | height and right heights */ 69 | return 1 + max(height(node->left), height(node->right)); 70 | } 71 | 72 | int main(){ 73 | int arr[] = {2, 2, 3, 4, 5, 6, 7, 8, 9}; //is BST 74 | node* root; 75 | root = NULL; 76 | createMinimalBst(root, arr, 0, 8); 77 | if(isBalanced(root)) 78 | printf("Tree is balanced"); 79 | else 80 | printf("Tree is not balanced"); 81 | 82 | getchar(); 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /Chapter-4-tree-and-graph/4.5_validate_BST.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct node{ 6 | int data; 7 | node *right, *left; 8 | }; 9 | 10 | /*We just use the code from last problem, created a binary search tree with minimum height. Then we check if the tree is balanced search tree.*/ 11 | 12 | void createMinimalBst(node* &root, int arr[], int start, int end){ 13 | if(start>end) 14 | return; 15 | if(root==NULL){ 16 | node *ptr = new node; 17 | int ind = start + (end-start)/2; 18 | ptr->data = arr[ind]; 19 | ptr->left = NULL; 20 | ptr->right = NULL; 21 | root = ptr; 22 | createMinimalBst(root->left, arr, start, ind-1); 23 | createMinimalBst(root->right, arr, ind+1, end); 24 | } 25 | } 26 | /*The check is performed recursively. The min/max solution. We proceed through the tree with this approach. When we branch left, the max gets updated to the data of current node. When we 27 | branch right, the min gets updated to the data of current node. If anything fails these checks, we stop and return false.*/ 28 | bool isBST(node* root, int min, int max){ 29 | if(root==NULL){ 30 | return true; 31 | } 32 | if(root->data<=min || root->data>max){ 33 | return false; 34 | } 35 | if (!isBST(root->left, min, root->data) || !isBST(root->right, root->data, max)){ 36 | return false; 37 | } 38 | return true; 39 | } 40 | 41 | int main(){ 42 | int arr[] = {1, 2, 3, 4, 15, 6, 7, 8, 9}; //NOT a BST since we assume a sorted array is provided before we create the BST 43 | // int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; //is a BST 44 | node* root; 45 | root = NULL; 46 | createMinimalBst(root, arr, 0, 8); 47 | cout< 2 | using namespace std; 3 | 4 | struct node{ 5 | int data; 6 | node *right, *left; 7 | }; 8 | 9 | void createMinimalBst(node* &root, int arr[], int start, int end){ 10 | if(start>end) 11 | return; 12 | if(root==NULL){ 13 | node *ptr = new node; 14 | int ind = start + (end-start)/2; 15 | ptr->data = arr[ind]; 16 | ptr->left = NULL; 17 | ptr->right = NULL; 18 | root = ptr; 19 | createMinimalBst(root->left, arr, start, ind-1); 20 | createMinimalBst(root->right, arr, ind+1, end); 21 | } 22 | } 23 | 24 | //root1 is decsendent of root 25 | bool isDescendant(node *root, node *root1){ 26 | if(root == NULL) 27 | return false; 28 | if(root == root1) 29 | return true; 30 | return isDescendant(root->left, root1) || isDescendant(root->right, root1); 31 | } 32 | 33 | /*We travel down to see where is the divergent point such that two query nodes are NOT in the same branch*/ 34 | node* commonAncestor(node *root, node *root1, node *root2){ 35 | if(root==NULL) 36 | return NULL; 37 | // if root happens to be one of the query nodes, then of course the first common ancestor is root itself 38 | if(root == root1 || root == root2) 39 | return root; 40 | bool root1_on_left = isDescendant(root->left, root1); 41 | bool root2_on_left = isDescendant(root->left, root2); 42 | // if both query nodes are in the left subtree, we go further to the left 43 | if(root1_on_left && root2_on_left) 44 | return commonAncestor(root->left, root1, root2); 45 | // if root is the divergent point, then root is the 46 | // first common ancestor 47 | else if(root1_on_left || root2_on_left) 48 | return root; 49 | // if both query nodes are in the right subtree, namely, we go further to the right 50 | else 51 | return commonAncestor(root->right, root1, root2); 52 | } 53 | 54 | int main(){ 55 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 56 | node* root; 57 | root = NULL; 58 | createMinimalBst(root, arr, 0, 8); 59 | node *ancestor = commonAncestor(root, root->left->left->right, root->left->right->right); 60 | cout<data; 61 | } 62 | -------------------------------------------------------------------------------- /Chapter-4-tree-and-graph/4.9_BST_sequences.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | struct node{ 6 | int data; 7 | node *right, *left; 8 | }; 9 | 10 | void createMinimalBst(node* &root, int arr[], int start, int end){ 11 | if(start>end) 12 | return; 13 | if(root==NULL){ 14 | node *ptr = new node; 15 | int ind = start + (end-start)/2; 16 | ptr->data = arr[ind]; 17 | ptr->left = NULL; 18 | ptr->right = NULL; 19 | root = ptr; 20 | createMinimalBst(root->left, arr, start, ind-1); 21 | createMinimalBst(root->right, arr, ind+1, end); 22 | } 23 | } 24 | 25 | /*The crucial point is that root must come before all its children. 26 | We do it recursivley, at each level: 27 | We first compute all permutations of left sub-tree sequence, 28 | and then do it for right sub-tree sequence. 29 | 30 | The critical part is then merge these two sequences. 31 | So called weaving in the book. 32 | 33 | Let m be the number of nodes in the left sub-tree 34 | and n be the number of nodes in the right sub-tree. 35 | Then the number of all possible sequences after merging step is (m+n)!/(m!n!) (binomial coefficient). 36 | */ 37 | vector > findAllSeq(node *ptr) 38 | { 39 | //Base Case 1: 40 | //If ptr is NULL, then return a vector with an empty sequence. 41 | if (ptr == NULL) { 42 | vector seq; 43 | vector > v; 44 | v.push_back(seq); 45 | return v; 46 | } 47 | 48 | //Base Case 2: 49 | //If ptr is a leaf node, then return a vector with a single sequence. 50 | //Its trivial that this sequence will contain only a single element, i.e. value of that node. 51 | if (ptr -> left == NULL && ptr -> right == NULL) { 52 | vector seq; 53 | seq.push_back(ptr -> data); 54 | vector > v; 55 | v.push_back(seq); 56 | return v; 57 | } 58 | 59 | //Divide Part (this part is very simple.) 60 | //We assume that we have a function that can solve this problem, 61 | //and thus we solve it for left sub tree and right sub tree. 62 | vector > results, left, right; 63 | left = findAllSeq(ptr -> left); 64 | right = findAllSeq(ptr -> right); 65 | int size = left[0].size() + right[0].size() + 1; 66 | 67 | //Merging the two solution.(The crux is in this step.) 68 | //Now we have two set containg distinct sequences: 69 | //i. left - all sequences in this set will generate left subtree. 70 | //ii. right - all sequences in this set will generate right subtree. 71 | 72 | vector flags(left[0].size(), 0); 73 | for (int k = 0; k < right[0].size(); k++) 74 | flags.push_back(1); 75 | 76 | //vector > results 77 | //for all sequences L in left 78 | // for all sequences R in right 79 | // create a vector flag with l.size() 0's and R.size() 1's 80 | // for all permutations of flag 81 | // generate the corresponding merged sequence. 82 | // append the current node's value in beginning 83 | // add this sequence to the results. 84 | // 85 | //return results. 86 | //Say, L={1, 2, 3} R={4, 5}, then we enumerate all possible permutations of {0,0,0,1,1}, 87 | //which yield (3+2)!/(3!2!) sequences. Then we put back {1, 2, 3} at positions of 0s and 88 | //{4, 5} at positions of 1s. 89 | for (int i = 0; i < left.size(); i++) { 90 | for (int j = 0; j < right.size(); j++) { 91 | do { 92 | vector tmp(size); 93 | tmp[0] = ptr -> data; 94 | int l = 0, r = 0; 95 | for (int k = 0; k < flags.size(); k++) { 96 | tmp[k+1] = (flags[k]) ? right[j][r++] : left[i][l++]; 97 | } 98 | results.push_back(tmp); 99 | } while (next_permutation(flags.begin(), flags.end())); 100 | } 101 | } 102 | 103 | return results; 104 | } 105 | 106 | void printAllSeq(vector > &AllSeq){ 107 | int i = 1; 108 | for (vector >::iterator iter = AllSeq.begin() ; iter != AllSeq.end(); ++iter){ 109 | vector seq = *iter; 110 | cout<<"The " <::iterator it = seq.begin() ; it != seq.end(); ++it){ 113 | cout << ' ' << *it; 114 | } 115 | cout << '\n'; 116 | } 117 | } 118 | 119 | int main(){ 120 | int arr[] = {1, 2, 3, 4, 5, 6, 7}; 121 | node* root; 122 | root = nullptr; 123 | createMinimalBst(root, arr, 0, 6); 124 | vector > all_sequences = findAllSeq(root); 125 | printAllSeq(all_sequences); 126 | } 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ Solutions to [Cracking The Coding Interview 6th Ed.](http://www.crackingthecodinginterview.com/) -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2-1-remove-dups.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Cracking the coding interview edition 6 3 | * Problem 2-1 : Remove duplicates from an unsorted linked list. 4 | * Approach 1 : Naive approach of iterating and remove all further duplicates of current node. 5 | * Space complexity O(1) & time complexity O(n^2) 6 | * Approach 2: Use a hash table, space complexity O(n), time complexity O(n) 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | struct Node { 16 | int data = 0; 17 | Node * next = nullptr; 18 | }; 19 | 20 | /** 21 | * [insert - insert a node at the head of list] 22 | * @param head [head of the list] 23 | * @param data [new node's data] 24 | */ 25 | void insert( Node * & head, int data ) 26 | { 27 | Node * newNode = new Node; 28 | newNode->data = data; 29 | newNode->next = head; 30 | head = newNode; 31 | } 32 | 33 | /** 34 | * [printList Helper routine to print list] 35 | * @param head [head of the list] 36 | */ 37 | void printList( Node * head ) { 38 | while( head ) { 39 | std::cout << head->data << "-->"; 40 | head = head->next; 41 | } 42 | std::cout << "nullptr" << std::endl; 43 | } 44 | 45 | //generate a random int between min and max 46 | /** 47 | * [random_range helper routine to generate a random number between min and max (including)] 48 | * @param min [min of range] 49 | * @param max [max of range] 50 | * @return [A random number between min and max] 51 | */ 52 | static inline int random_range(const int min, const int max) { 53 | std::random_device rd; 54 | std::mt19937 mt(rd()); 55 | std::uniform_int_distribution distribution(min, max); 56 | return distribution(mt); 57 | } 58 | 59 | 60 | // Method 1 61 | //space complexity O(1) 62 | // time complexity O(n^2) 63 | /** 64 | * [removeDuplicates Remove duplicates without using extra space] 65 | * @param head [head of list] 66 | */ 67 | void removeDuplicates( Node * head ) { 68 | if ( head == nullptr || ( head && (head->next == nullptr))) { 69 | return; 70 | } 71 | Node * curr = head; 72 | while(curr) { 73 | Node * runner = curr; 74 | while (runner->next != nullptr) { 75 | if (runner->next->data == curr->data) { 76 | runner->next = runner->next->next; 77 | } else { 78 | runner = runner->next; 79 | } 80 | } 81 | curr = curr->next; 82 | } 83 | } 84 | 85 | // Method 2 86 | // space complexity - O(n) 87 | // time complexity - O(n) 88 | /** 89 | * [removeDuplicates1 - Remove duplicates from the list using hash table] 90 | * @param head [head of list] 91 | */ 92 | void removeDuplicates1( Node * head ) { 93 | if ( head == nullptr || ( head && (head->next == nullptr) )) { 94 | return ; 95 | } 96 | std::unordered_map node_map; 97 | Node * prev = head; 98 | Node * curr = head->next; 99 | node_map[head->data] = 1; 100 | while( curr != nullptr ) { 101 | while (curr && node_map.find(curr->data) != node_map.end()) { 102 | curr = curr->next; 103 | } 104 | prev->next = curr; 105 | prev = curr; 106 | if (curr) { 107 | node_map[curr->data] = 1; 108 | curr = curr->next; 109 | } 110 | } 111 | } 112 | 113 | 114 | 115 | int main() { 116 | std::cout << "Method 1 : \n"; 117 | Node * head = nullptr; 118 | for ( int i = 0; i < 10; ++i ) { 119 | insert(head, random_range(1,7)); 120 | } 121 | printList(head); 122 | removeDuplicates(head); 123 | printList(head); 124 | 125 | std::cout << "Method 2 : \n"; 126 | Node * head1 = nullptr; 127 | for ( int i = 0; i < 10; ++i ) { 128 | insert(head1, random_range(1,7)); 129 | } 130 | printList(head1); 131 | removeDuplicates1(head1); 132 | printList(head1); 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2-2-kthToLast.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview edition 6 3 | * Problem 2.2 4 | * Return kth to last 5 | * Implement an algorithm to find the kth to last element of a singly linked list. 6 | * We can assume we are not provided the length of the list. 7 | * 8 | * Approaches: 9 | * 1. Iterative: 10 | * Use two pointers 11 | * Move first pointer k places. 12 | * Now move second pointer(from start) and first pointer (from k+1) simultanously. 13 | * When second pointer would have reached end, first pointer would be at kth node. 14 | * 15 | * 2. Recursive: 16 | * Maintain an index to keep track of node. 17 | * Solve the problem for n-1 nodes and add 1 to index. 18 | * Since each parent call is adding 1, when counter reaches k, 19 | * we have reached length-k node from start, which is kth node from last. 20 | */ 21 | 22 | #include 23 | 24 | struct Node { 25 | int data; 26 | Node * next; 27 | Node(int d) : data{ d }, next{ nullptr } { } 28 | }; 29 | 30 | 31 | /** 32 | * Insert to the head of the list 33 | * @param head - Current head of list 34 | * @param data - new node's data 35 | */ 36 | void insert( Node * & head, int data ) { 37 | Node * newNode = new Node(data); 38 | newNode->next = head; 39 | head = newNode; 40 | } 41 | 42 | /** 43 | * [deleteList - delete the entire list] 44 | * @param head - head of the list 45 | */ 46 | void deleteList( Node * & head ) { 47 | Node * nextNode; 48 | while(head) { 49 | nextNode = head->next; 50 | delete(head); 51 | head = nextNode; 52 | } 53 | } 54 | 55 | /** 56 | * printList - Helper routine to print the list 57 | * @param head - Current head of the list. 58 | */ 59 | void printList( Node * head ) { 60 | while(head) { 61 | std::cout << head->data << "-->"; 62 | head = head->next; 63 | } 64 | std::cout << "null" << std::endl; 65 | } 66 | 67 | /** 68 | * [kthToLastHelper - helper routine to find nth node for recursive approach 69 | * @param head - head of the list 70 | * @param k - the k value for finding kth element from last of the list. 71 | * @param i - an index maintained to keep track of current node. 72 | * @return - kth node from last. 73 | */ 74 | Node * kthToLastHelper( Node * head, int k , int & i) { 75 | if ( head == nullptr ) { 76 | return nullptr; 77 | } 78 | 79 | Node * node = kthToLastHelper(head->next, k, i); 80 | i = i + 1; 81 | //if we have solved problem k times from last. 82 | if ( i == k ) { 83 | return head; 84 | } 85 | return node; 86 | } 87 | 88 | /** 89 | * kthToLastRecursive - Recursive approach for finding kth to last element of list. 90 | * @param head - head of node 91 | * @param k - the k value for finding kth element from last of the list. 92 | * @return - kth node from last. 93 | */ 94 | Node * kthToLastRecursive( Node * head, int k ) { 95 | int i = 0; 96 | return kthToLastHelper(head, k, i); 97 | } 98 | 99 | /** 100 | * kthToLastIterative - Iterative approach for finding kth to last element of list. 101 | * @param head - head of node 102 | * @param k - the k value for finding kth element from last of the list. 103 | * @return - kth node from last. 104 | */ 105 | Node * kthToLastIterative( Node * head, int k ) { 106 | if ( head == nullptr ) { 107 | return head; 108 | } 109 | 110 | Node * ptr1 = head; 111 | Node * ptr2 = head; 112 | 113 | int i = 0; 114 | while( i < k && ptr1 ) { 115 | ptr1 = ptr1->next; 116 | ++i; 117 | } 118 | 119 | //out of bounds 120 | if ( i < k ) { 121 | return nullptr; 122 | } 123 | 124 | while( ptr1 != nullptr ) { 125 | ptr1 = ptr1->next; 126 | ptr2 = ptr2->next; 127 | } 128 | 129 | return ptr2; 130 | } 131 | 132 | 133 | 134 | int main() { 135 | Node * head = nullptr; 136 | for ( int i = 7; i > 0; i-- ) { 137 | insert(head, i); 138 | } 139 | std::cout << "List: "; 140 | printList(head); 141 | 142 | std::cout << "4th node from last (Recursive) : "; 143 | Node *node4 = kthToLastRecursive(head, 4); 144 | if ( node4 != nullptr ) { 145 | std::cout << node4->data << std::endl; 146 | } else { 147 | std::cout << "NULL NODE\n"; 148 | } 149 | 150 | std::cout << "4th node from last (Iterative) : "; 151 | node4 = kthToLastIterative(head, 4); 152 | if ( node4 != nullptr ) { 153 | std::cout << node4->data << std::endl; 154 | } else { 155 | std::cout << "NULL NODE\n"; 156 | } 157 | 158 | deleteList(head); 159 | 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2-3-delete-middle-node.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview - edition 6 3 | * Problem 2.3 Delete middle node: 4 | * Implement an algorithm to delete a node in the middle of a singly linked list. 5 | * We are given pointer to that node. 6 | * 7 | * Approach: 8 | * In order to remove a node 'A' from a list, We will need to connect pointer of 9 | * A's previous node to A's next node. Here we don't have access to previous node. 10 | * However, we have pointer to that node, we can copy the data of next node to 11 | * the pointed node and then remove the next node. 12 | * Assumption here is that we are not given last node of the list for deletion. 13 | */ 14 | 15 | #include 16 | 17 | struct Node { 18 | char data; 19 | Node * next; 20 | Node( char c ) : data{ c }, next{ nullptr } { } 21 | }; 22 | 23 | /** 24 | * [printList - Helper routine to print the list] 25 | * @param head [head of the list] 26 | */ 27 | void printList( Node * head ) { 28 | while( head ) { 29 | std::cout << head->data << "-->"; 30 | head = head->next; 31 | } 32 | std::cout << "nullptr" << std::endl; 33 | } 34 | 35 | /** 36 | * [deleteNode - delete the "node" from the list] 37 | * @param node [node to be deleted] 38 | */ 39 | void deleteNode( Node * node ) { 40 | if ( node == nullptr || node->next == nullptr ) { 41 | return; 42 | } 43 | Node * nextNode = node->next; 44 | node->data = nextNode->data; 45 | node->next = nextNode->next; 46 | delete nextNode; 47 | } 48 | 49 | int main() { 50 | Node * head = new Node('a'); 51 | head->next = new Node('b'); 52 | head->next->next = new Node('c'); 53 | head->next->next->next = new Node('d'); 54 | head->next->next->next->next = new Node('e'); 55 | std::cout << "List before deletion:\n"; 56 | printList(head); 57 | std::cout << "Deleting node containing data as 'c'\n"; 58 | deleteNode(head->next->next); 59 | std::cout << "List after deletion:\n"; 60 | printList(head); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2-4-partition.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview edition 6 3 | * Problem 2.4 Partition: 4 | * Write code to partition linked list around a value x, such that 5 | * nodes less than x come before all the nodes greater than or equal to x. 6 | * If x is in the list, the values of x only need to be after the elements less 7 | * than x. 8 | * Example 9 | * 3-->5-->8-->5-->10-->2-->1 (x = 5) 10 | * 3-->1-->2-->10-->5-->5-->8 11 | * 12 | * Approach: 13 | * Start with first node, and add every thing bigger or equal to x at tail 14 | * and smaller values at head. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | struct Node { 21 | int data; 22 | Node * next; 23 | Node( int d ) : data{ d }, next{ nullptr } { } 24 | }; 25 | 26 | void insert( Node * & head, int data ) { 27 | Node * newNode = new Node(data); 28 | if ( head == nullptr ) { 29 | head = newNode; 30 | } else { 31 | Node * curr = head; 32 | while( curr->next ) { 33 | curr = curr->next; 34 | } 35 | curr->next = newNode; 36 | } 37 | } 38 | 39 | void printList( Node * head ) { 40 | while ( head ) { 41 | std::cout << head->data << "-->"; 42 | head = head->next; 43 | } 44 | std::cout << "nullptr" << std::endl; 45 | } 46 | 47 | 48 | /* We start with a new list. Elements bigger than the pivot element are put at the tail list 49 | and elements smaller are put at the head list*/ 50 | Node * partition( Node * listhead , int x ) { 51 | Node * head = nullptr; 52 | Node * headInitial = nullptr; /*The initial node of list head*/ 53 | Node * tail = nullptr; 54 | Node * tailInitial = nullptr; /*The initial node of list tail*/ 55 | Node * curr = listhead; 56 | while( curr != nullptr ) { 57 | Node * nextNode = curr->next; 58 | if ( curr->data < x ) { 59 | if (head == nullptr) { 60 | head = curr; 61 | headInitial = head; 62 | } 63 | //insert curr node to head list 64 | head->next = curr; 65 | head = curr; 66 | } else { 67 | if (tail == nullptr) { 68 | tail = curr; 69 | tailInitial = tail; 70 | } 71 | // insert curr node to tail list 72 | tail->next = curr; 73 | tail = curr; 74 | } 75 | curr = nextNode; 76 | } 77 | head->next = tailInitial; /*Now, we connect the head list to tail list.*/ 78 | tail->next = nullptr; 79 | return headInitial; 80 | } 81 | 82 | 83 | 84 | 85 | 86 | int main() { 87 | Node * head = nullptr; 88 | for ( int i = 0; i < 10; ++i ) { 89 | insert(head, rand() % 9); 90 | } 91 | std::cout << "List before partition around 5:\n"; 92 | printList(head); 93 | std::cout << "List after partition around 5:\n"; 94 | printList(partition(head, 5)); 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2-7-intersection.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview edition 6 3 | * Problem 2.7 Intersection 4 | * Given two linked lists, if they both intersect at some point. 5 | * Find out the intersecting point else return nullptr. 6 | * Intersection is defined based on reference not value. 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | struct Node { 13 | int data; 14 | Node * next; 15 | Node( int d ) : data{ d }, next{ nullptr } { } 16 | }; 17 | 18 | /** 19 | * [printList Helper routine to print list] 20 | * @param head [head of the list] 21 | */ 22 | void printList( Node * head ) 23 | { 24 | while( head ) { 25 | std::cout << head->data << "-->"; 26 | head = head->next; 27 | } 28 | std::cout << "NULL" << std::endl; 29 | } 30 | 31 | int listLen( Node * head ) 32 | { 33 | int count = 0; 34 | while( head ) { 35 | head = head->next; 36 | count++; 37 | } 38 | return count; 39 | } 40 | 41 | /** 42 | * [intersectionPoint Returns the point of intersection of two lists] 43 | * @param head1 [ head of list 1 ] 44 | * @param head2 [ head of list 2 ] 45 | * @return [ Intersecting node, if lists intersect, else nullptr] 46 | */ 47 | Node * intersectionPoint( Node * head1, Node * head2 ) 48 | { 49 | int len1 = listLen(head1); 50 | int len2 = listLen(head2); 51 | //figure out the bigger list ( and smaller ) 52 | //ptr points to bigger list, let us move the difference 53 | //between the two. 54 | Node * ptr1 = ( len1 > len2 ) ? head1 : head2; 55 | Node * ptr2 = ( len1 > len2 ) ? head2 : head1; 56 | int i = 0; 57 | while ( i < std::abs(len1 - len2) && ptr1 ) { 58 | ptr1 = ptr1->next; 59 | ++i; 60 | } 61 | //Now we have equal nodes to travel on both the nodes 62 | // traversing and comparing the pointers. 63 | 64 | while( ptr1 && ptr2 ) { 65 | if ( ptr1 == ptr2 ) { 66 | return ptr1; 67 | } 68 | ptr1 = ptr1->next; 69 | ptr2 = ptr2->next; 70 | } 71 | return nullptr; 72 | } 73 | 74 | 75 | int main() 76 | { 77 | Node * list1 = new Node(3); 78 | list1->next = new Node(6); 79 | list1->next->next = new Node(9); 80 | list1->next->next->next = new Node(12); 81 | list1->next->next->next->next = new Node(15); 82 | list1->next->next->next->next->next = new Node(18); 83 | 84 | Node * list2 = new Node(7); 85 | list2->next = new Node(10); 86 | list2->next->next = list1->next->next->next; 87 | 88 | printList(list1); 89 | printList(list2); 90 | 91 | Node * intersectingNode = intersectionPoint( list1 , list2 ); 92 | if (intersectingNode) { 93 | std::cout << "Intersecting Node of lists is :" << intersectingNode->data << std::endl; 94 | } else { 95 | std::cout << "Lists do not interset" << std::endl; 96 | } 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2-8-loop-detection.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview, edition 6 3 | * Problem 2.8 Loop Detection 4 | * Problem : Determine if a linkedlist has a loop. If it has a loop, find the start of loop. 5 | * NOTE: I have followed the approach provided in book, however, once I find start of loop, 6 | * I remove the loop. So that we can test our solution. Read comment at line 25. 7 | */ 8 | 9 | #include 10 | 11 | struct Node { 12 | int data; 13 | Node * next; 14 | Node( int d ) : data{ d }, next{ nullptr } { } 15 | }; 16 | 17 | void removeLoop( Node * loopNode, Node * head ) 18 | { 19 | Node * ptr1 = head; 20 | Node * ptr2 = loopNode; 21 | while ( ptr1->next != ptr2->next ) { 22 | ptr1 = ptr1->next; 23 | ptr2 = ptr2->next; 24 | } 25 | //ptr2 has reached start of loop, now removing the loop. 26 | ptr2->next = nullptr; 27 | } 28 | 29 | bool detectAndRemoveCycle( Node * head ) 30 | { 31 | if ( head == nullptr) { 32 | return false; 33 | } 34 | Node * fastPtr = head; 35 | Node * slowPtr = head; 36 | while( slowPtr && fastPtr && fastPtr->next) 37 | { 38 | fastPtr = fastPtr->next->next; 39 | slowPtr = slowPtr->next; 40 | if ( fastPtr == slowPtr ) { 41 | removeLoop( slowPtr, head ); 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | 49 | 50 | void insert( Node * & head, int data ) 51 | { 52 | Node * newNode = new Node( data ); 53 | if ( head == nullptr ) { 54 | head = newNode; 55 | } else { 56 | Node * temp = head; 57 | while( temp->next != nullptr ) { 58 | temp = temp->next; 59 | } 60 | temp->next = newNode; 61 | } 62 | } 63 | 64 | void printList( Node * head ) 65 | { 66 | while( head ) { 67 | std::cout << head->data << "-->"; 68 | head = head->next; 69 | } 70 | std::cout << "NULL" << std::endl; 71 | } 72 | 73 | 74 | int main() 75 | { 76 | Node * head = nullptr; 77 | insert( head , 1 ); 78 | insert( head , 2 ); 79 | insert( head , 3 ); 80 | insert( head , 4 ); 81 | insert( head , 5 ); 82 | std::cout << "Current List:\n"; 83 | printList( head ); 84 | std::cout << "Inserting loop, connecting 5 to 2 \n"; 85 | head->next->next->next->next->next = head->next; 86 | std::cout << "Detecting and deleting loop\n"; 87 | detectAndRemoveCycle(head); 88 | std::cout << "Back to the same old list\n"; 89 | printList( head ); 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /chapter-2-Linked-Lists/2.4cpp_partition: -------------------------------------------------------------------------------- 1 | /** 2 | * Cracking the coding interview edition 6 3 | * Problem 2.4 Partition: 4 | * Write code to partition linked list around a value x, such that 5 | * nodes less than x come before all the nodes greater than or equal to x. 6 | * If x is in the list, the values of x only need to be after the elements less 7 | * than x. 8 | * Example 9 | * 3-->5-->8-->5-->10-->2-->1 (x = 5) 10 | * 3-->1-->2-->10-->5-->5-->8 11 | * 12 | * Approach: 13 | * Use quicksort partition approach by swapping the values of the nodes 14 | * in-place. Complexity is O(n). 15 | */ 16 | typedef struct node { 17 | int val; 18 | struct node *next; 19 | } node; 20 | 21 | void swap(node *n1, node *n2) 22 | { 23 | int tmp; 24 | if (n1 == NULL || n2 == NULL) 25 | return; 26 | tmp = n1->val; 27 | n1->val = n2->val; 28 | n2->val = tmp; 29 | } 30 | 31 | bool findnSwap(node *head, int p) 32 | { 33 | node *tmpHead = head; 34 | 35 | while (head) { 36 | if (head->val == p) { 37 | swap(head, tmpHead); 38 | return true; 39 | } 40 | head = head->next; 41 | } 42 | return false; 43 | } 44 | 45 | void partitionList(node *head, int p) 46 | { 47 | node *tmpHead = head; 48 | node *prevP = head; 49 | if (head == NULL) 50 | return; 51 | 52 | if (!findnSwap(head, p)) 53 | return; 54 | 55 | node *partition = head->next; 56 | head = head->next; 57 | 58 | while (head) { 59 | if (p > head->val) { 60 | swap(head, partition); 61 | prevP = partition; 62 | partition = partition->next; 63 | } 64 | head = head->next; 65 | } 66 | swap(tmpHead, prevP); 67 | } 68 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8-1-Triple-Step.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int countWays(int n , vector v){ 7 | 8 | if (n==0){ 9 | return 1; 10 | } 11 | 12 | int sum = 0; 13 | 14 | for (int i = 0; i < v.size(); ++i) 15 | { 16 | if(n>=v[i]){ 17 | sum = sum + countWays((n-v[i]),v); 18 | } 19 | } 20 | return sum; 21 | } 22 | 23 | int main(int argc, char const *argv[]) 24 | { 25 | 26 | vector v; // vector to store possible step sizes 27 | v.push_back(1); 28 | v.push_back(2); 29 | v.push_back(3); 30 | 31 | int noOfWays = countWays(6,v); 32 | cout< 2 | #include 3 | using namespace std; 4 | 5 | int ways(int amount, vector denom){ 6 | 7 | if (!amount){ 8 | return 1; 9 | } 10 | 11 | int n = denom.size(); 12 | if(n==1){ 13 | if(amount%denom[0]) 14 | return 0; 15 | else 16 | return 1; 17 | } 18 | int curr = denom[n-1]; 19 | int sum = 0; 20 | denom.pop_back(); 21 | sum += ways(amount,denom); 22 | while(amount>=curr){ 23 | sum += ways(amount-curr,denom); 24 | amount = amount-curr; 25 | } 26 | return sum; 27 | } 28 | 29 | int main(){ 30 | int amount = 8; 31 | vector denom; 32 | denom.push_back(2); 33 | denom.push_back(3); 34 | 35 | cout< 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct Point { 10 | int row; 11 | int column; 12 | Point(int r, int c) : row(r), column(c) {} 13 | }; 14 | 15 | 16 | 17 | ////////////////////////////////////////////////////// 18 | //Implementation with memoization/caching 19 | ////////////////////////////////////////////////////// 20 | 21 | //Checks if path is valid and simultaneously adds position to a result vector 22 | bool getPath(int** matrix, int currRow, int currColumn, vector& path, unordered_set& duplicateVisits){ 23 | 24 | //if out of bounds or curr position is off limits, return false 25 | if (currRow < 0 || currColumn < 0 || matrix[currRow][currColumn] == -1){ 26 | return false; 27 | } 28 | 29 | Point* currPos = new Point(currRow, currColumn); 30 | 31 | //If we have already visited this position, then return false 32 | if (duplicateVisits.find(currPos) != duplicateVisits.end()){ 33 | return false; 34 | } 35 | 36 | 37 | bool atOrigin = currRow == 0 && currColumn == 0; 38 | 39 | //Everytime robot moves up or left and it is a valid position, add the point to result vector 40 | if (atOrigin || getPath(matrix, currRow-1, currColumn, path, duplicateVisits) || getPath(matrix, currRow, currColumn-1, path, duplicateVisits)){ 41 | path.push_back(currPos); 42 | return true; 43 | } 44 | 45 | //Keep track of already visited points 46 | duplicateVisits.insert(currPos); 47 | 48 | return false; 49 | } 50 | 51 | vector getPath(int** matrix, int rows, int columns){ 52 | //create result vector 53 | vector path; 54 | 55 | //create unordered set to keep track of already visited points 56 | unordered_set duplicateVisits; 57 | 58 | //Bounds checking 59 | if (rows != 0 || matrix != nullptr){ 60 | //Start checking positions from bottom right to top left 61 | if (getPath(matrix, rows - 1, columns - 1, path, duplicateVisits)){ 62 | return path; 63 | } 64 | } 65 | //Return an empty vector indicating path does not exist 66 | return path; 67 | 68 | } 69 | 70 | 71 | ////////////////////////////////////////////////////// 72 | //Implementation without memoization/caching 73 | ////////////////////////////////////////////////////// 74 | 75 | 76 | 77 | //Checks if path is valid and simultaneously adds position to a result vector 78 | //bool getPath(int** matrix, int currRow, int currColumn, vector& path){ 79 | // 80 | // //if out of bounds or curr position is off limits, return false 81 | // if (currRow < 0 || currColumn < 0 || matrix[currRow][currColumn] == -1){ 82 | // return false; 83 | // } 84 | // 85 | // bool atOrigin = currRow == 0 && currColumn == 0; 86 | // 87 | // //Everytime robot moves up or left and it is a valid position, add the point to result vector 88 | // if (atOrigin || getPath(matrix, currRow-1, currColumn, path) || getPath(matrix, currRow, currColumn-1, path)){ 89 | // Point* currPos = new Point(currRow, currColumn); 90 | // path.push_back(currPos); 91 | // return true; 92 | // } 93 | // return false; 94 | // 95 | // 96 | // 97 | // 98 | //} 99 | // 100 | //vector getPath(int** matrix, int rows, int columns){ 101 | // //create result vector 102 | // vector path; 103 | // 104 | // //Bounds checking 105 | // if (rows != 0 || matrix != nullptr){ 106 | // //Start checking positions from bottom-right 107 | // if (getPath(matrix, rows - 1, columns - 1, path)){ 108 | // return path; 109 | // } 110 | // 111 | // 112 | // } 113 | // //Otherwise return an empty vector indicating path does not exist 114 | // return path; 115 | // 116 | //} 117 | 118 | 119 | int** createMatrix(int rows, int columns){ 120 | //initialize number of rows 121 | int** matrix = new int*[rows]; 122 | //in each row, add a new column array 123 | for (int i = 0; i < rows; ++i){ 124 | matrix[i] = new int[columns]; 125 | } 126 | //place values (1 indicates position is valid, -1 indicates it is invalid) 127 | for (int i = 0; i < rows; ++i){ 128 | for (int j = 0; j < columns; ++j){ 129 | matrix[i][j] = 1; 130 | } 131 | } 132 | return matrix; 133 | 134 | } 135 | 136 | int main() { 137 | 138 | //create a 5x7 matrix (5 rows and 7 columns) 139 | int** matrix = createMatrix(5, 7); 140 | //set specific points as off-limits 141 | matrix[1][3] = -1; 142 | matrix[2][5] = -1; 143 | matrix[3][2] = -1; 144 | matrix[0][1] = -1; 145 | 146 | 147 | vector path = getPath(matrix, 5, 7); 148 | if (path.size() == 0){ 149 | cerr << "Path does not exist!" << endl; 150 | 151 | } 152 | else { 153 | for (int i = 0; i < path.size(); ++i){ 154 | cout << "[" << path[i]->row << "]" << "[" << path[i]->column << "]" << endl; 155 | } 156 | 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8-3-Magic-Index.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int findMagicUtil(vector v, int start, int end){ 6 | 7 | int n = v.size(); 8 | 9 | if (start<0 || end>=v.size()){ // index out of bounds 10 | return -1; 11 | } 12 | 13 | if (start>end){ 14 | return -1; 15 | } 16 | 17 | int mid = start + (end-start)/2; // to avoid overflow. effectively, equals (start+end)/2 18 | if (mid==v[mid]){ 19 | return mid; 20 | } 21 | else{ 22 | if (findMagicUtil(v,start,min(v[mid],mid))!=-1){ 23 | return findMagicUtil(v,start,min(v[mid],mid)); 24 | } 25 | 26 | return (findMagicUtil(v,max(v[mid],mid),end)); 27 | } 28 | } 29 | 30 | int findMagic(vector v){ 31 | 32 | int n = v.size(); 33 | if(n==0){ 34 | return -1; 35 | } 36 | 37 | return findMagicUtil(v,0,n-1); 38 | } 39 | 40 | int main(int argc, char const *argv[]) 41 | { 42 | // Follow Up covered: Not Distinct 43 | vector v; 44 | v.push_back(-10); 45 | v.push_back(-1); 46 | v.push_back(2); 47 | v.push_back(2); 48 | v.push_back(2); 49 | v.push_back(3); 50 | v.push_back(5); 51 | v.push_back(8); 52 | v.push_back(9); 53 | v.push_back(12); 54 | v.push_back(13); 55 | 56 | cout< 2 | #include 3 | using namespace std; 4 | 5 | int multiply(int a, int b, vector& dp) 6 | { 7 | int bigger = a < b ? b:a; 8 | int smaller = a > 1; //divide by 2 20 | 21 | int side1 = multiply(s,bigger,dp); 22 | int side2 = 0; 23 | if (smaller%2) 24 | side2 = side1+bigger; 25 | else 26 | side2 = side1; 27 | 28 | dp[smaller] = side2 +side1; 29 | return side1+side2; 30 | } 31 | 32 | int main() 33 | { 34 | int m = 7, n = 6; 35 | int smaller = m>n?n:m; 36 | int bigger = m>n?m:n; 37 | std::vector dp(smaller+1,-1); 38 | cout< 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void findPermutations(string s, string curr,vector& res){ 8 | 9 | int n = s.size(); 10 | if (!n) 11 | { 12 | res.push_back(curr); 13 | return; 14 | } 15 | 16 | for (int i = 0; i < n; ++i) 17 | { 18 | string first = curr+s.substr(i,1); 19 | string rem = s.substr(0,i) + s.substr(i+1,n-i-1); 20 | findPermutations(rem,first,res); 21 | } 22 | } 23 | 24 | int main() 25 | { 26 | string s = "abc"; 27 | string curr =""; 28 | vector res; 29 | findPermutations(s,curr,res); 30 | for (int i = 0; i < res.size(); ++i) 31 | cout< 2 | #include 3 | 4 | using namespace std; 5 | 6 | void printPerms(string, string = ""); 7 | 8 | int main() 9 | { 10 | printPerms("abbc"); 11 | } 12 | 13 | void printPerms(string remainder, string prefix) 14 | { 15 | long length = remainder.length(); 16 | 17 | if (!length) cout << prefix << endl; 18 | 19 | bool dup[128]; 20 | 21 | memset(dup, false, sizeof(bool) * 128); 22 | 23 | for (int i = 0; i < length; ++i) 24 | { 25 | if (dup[remainder.at(i)]) continue; 26 | 27 | string str1 = i == 0 ? "" : remainder.substr(0,i); 28 | 29 | string str2 = i == length - 1 ? "" : remainder.substr(i+1,length); 30 | 31 | printPerms(str1 + str2, prefix + remainder.at(i)); 32 | 33 | dup[remainder.at(i)] = true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8-8-Permutation-with-dups.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void findPermutations(string curr, map m, vector& res, int n){ 8 | 9 | int curr_length = curr.length(); 10 | if (n==curr_length){ 11 | res.push_back(curr); 12 | return; 13 | } 14 | 15 | for (map::iterator i = m.begin(); i!=m.end(); i++){ 16 | if (i->second!=0){ 17 | char c = i->first; 18 | string f = curr+c; 19 | i->second--; 20 | findPermutations(f,m,res,n); 21 | i->second++; 22 | } 23 | } 24 | } 25 | 26 | int main() 27 | { 28 | string s = "abbc"; 29 | string curr =""; 30 | map m; 31 | int n = s.length(); 32 | for (int i = 0; i < n; i++) 33 | { 34 | if (m.find(s[i])!=m.end()) 35 | m.find(s[i])->second++; 36 | else 37 | m.insert(make_pair(s[i],1)); 38 | } 39 | vector res; 40 | findPermutations(curr,m,res,n); 41 | for (int i = 0; i < res.size(); i++) 42 | { 43 | cout< 2 | #include 3 | #include 4 | 5 | #define COUNT 3 6 | 7 | using namespace std; 8 | 9 | vector> * print_all_parentheses_internal(size_t count); 10 | 11 | void print_all_parentheses(size_t count); 12 | 13 | int main() 14 | { 15 | print_all_parentheses(COUNT); 16 | return 0; 17 | } 18 | 19 | vector> * print_all_parentheses_internal(size_t count) 20 | { 21 | if (count == 1) 22 | { 23 | deque d; 24 | d.push_back('('); 25 | d.push_back(')'); 26 | 27 | vector> * v = new vector>(); 28 | 29 | v->push_back(d); 30 | 31 | return v; 32 | } 33 | 34 | vector> * v = print_all_parentheses_internal(count - 1); 35 | 36 | long size = v->size(); 37 | 38 | for (int i = 0; i < size; ++i) 39 | { 40 | deque tmp1 = v->at(i); 41 | deque tmp2 = v->at(i); 42 | 43 | v->at(i).push_front(')'); 44 | v->at(i).push_front('('); 45 | 46 | tmp1.push_front('('); 47 | tmp1.push_back(')'); 48 | 49 | v->push_back(tmp1); 50 | 51 | if (i) 52 | { 53 | tmp2.push_back('('); 54 | tmp2.push_back(')'); 55 | 56 | v->push_back(tmp2); 57 | } 58 | } 59 | 60 | return v; 61 | } 62 | 63 | void print_all_parentheses(size_t count) 64 | { 65 | vector> * v = print_all_parentheses_internal(count); 66 | 67 | long size = v->size(); 68 | 69 | for (int i = 0; i < size; ++i) 70 | { 71 | deque::iterator it = v->at(i).begin(); 72 | 73 | while (it != v->at(i).end()) cout << *it++; 74 | 75 | cout << endl; 76 | } 77 | 78 | delete v; 79 | } 80 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8-9-parens.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void print_all_parentheses_internal(size_t count, size_t opened, size_t closed, std::string arangement){ 5 | 6 | if(closed > opened){ 7 | return; 8 | } 9 | else if(opened > count){ 10 | return; 11 | } 12 | else if(arangement.size()==2*count){ 13 | std::cout << arangement << std::endl; 14 | } 15 | 16 | print_all_parentheses_internal(count,opened+1,closed, arangement+"("); 17 | print_all_parentheses_internal(count,opened ,closed+1,arangement+")"); 18 | } 19 | 20 | void print_all_parentheses(size_t count){ 21 | print_all_parentheses_internal(count, 0, 0, ""); 22 | } 23 | 24 | int main(int argc, const char* argv[]) { 25 | print_all_parentheses(3); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.10_Paint_Fill.cpp: -------------------------------------------------------------------------------- 1 | // A C++ program to implement flood fill algorithm 2 | #include 3 | using namespace std; 4 | 5 | // dimensions of paint screen 6 | #define M 8 7 | #define N 6 8 | 9 | // A recursive function to replace previous color 'prevC' at '(x, y)' 10 | // and all surrounding pixels of (x, y) with new color 'newC' and 11 | void floodFillUtil(int screen[][N], int x, int y, int prevC, int newC) 12 | { 13 | // Base cases 14 | if (x < 0 || x >= M || y < 0 || y >= N) 15 | return; 16 | if (screen[x][y] != prevC) 17 | return; 18 | 19 | // Replace the color at (x, y) 20 | screen[x][y] = newC; 21 | 22 | // Recur for north, east, south and west 23 | floodFillUtil(screen, x+1, y, prevC, newC); 24 | floodFillUtil(screen, x-1, y, prevC, newC); 25 | floodFillUtil(screen, x, y+1, prevC, newC); 26 | floodFillUtil(screen, x, y-1, prevC, newC); 27 | } 28 | 29 | // It mainly finds the previous color on (x, y) and 30 | // calls floodFillUtil() 31 | void floodFill(int screen[][N], int x, int y, int newC) 32 | { 33 | int prevC = screen[x][y]; 34 | floodFillUtil(screen, x, y, prevC, newC); 35 | } 36 | 37 | // Driver program to test above function 38 | int main() 39 | { 40 | int screen[M][N] = {{1, 1, 1, 1, 1, 1}, 41 | {1, 1, 1, 1, 1, 1}, 42 | {1, 0, 0, 1, 1, 0}, 43 | {1, 2, 2, 2, 2, 0}, 44 | {1, 1, 1, 2, 2, 0}, 45 | {1, 1, 1, 2, 2, 2}, 46 | {1, 1, 1, 1, 1, 2}, 47 | {1, 1, 1, 1, 1, 2}, 48 | }; 49 | int x = 4, y = 4, newC = 3; 50 | floodFill(screen, x, y, newC); 51 | 52 | cout << "Updated screen after call to floodFill: \n"; 53 | for (int i=0; i 5 | 6 | // A recursive function used by countWays 7 | int countWays(int n, int m) 8 | { 9 | int res[n+1]; 10 | res[0] = 1; 11 | for (int i=1; i<=n; i++) 12 | { 13 | res[i] = 0; 14 | for (int j=1; j<=m && j<=i; j++) 15 | res[i] += res[i-j]; 16 | } 17 | return res[n]; 18 | } 19 | 20 | // Driver program to test above functions 21 | int main () 22 | { 23 | int s = 8, m = 3; //The problem in the book is for m=3. 24 | printf("Number of ways = %d", countWays(s, m)); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.2_Grid_Paths.cpp: -------------------------------------------------------------------------------- 1 | //We count the number of unique paths from top left corner to the bottom right corner. 2 | //Dynamical Programming approach 3 | 4 | #include 5 | int cntways(int m, int n) 6 | { 7 | int ways[m][n]; //m is the number of rows and n is the number of columns of this grid 8 | for (int i = 0; i < m; ++i) 9 | { 10 | for (int j = 0; j < n; ++j) 11 | { 12 | if(i == 0 && j == 0) //base case, the number of path to origin is 1 13 | ways[i][j] = 1; 14 | else if(i == 0) 15 | ways[i][j] = ways[i][j-1]; //if row number is zero, then the path to here can only from left 16 | else if(j == 0) 17 | ways[i][j] = ways[i-1][j]; //if column number is zero, then the path to here can only from top 18 | else 19 | ways[i][j] = ways[i-1][j] + ways[i][j-1]; //for a general grid point, the path to here can from left or top 20 | } 21 | } 22 | 23 | return ways[m-1][n-1]; 24 | } 25 | // Driver program to test above functions 26 | int main () 27 | { 28 | int m = 8, n = 3; //The problem in the book is for m=3. 29 | printf("Number of paths = %d", cntways(m, n)); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.3_Magic_Index.cpp: -------------------------------------------------------------------------------- 1 | //We use the binary search to deterimine the point such that A[i]=i. 2 | //This algorithm runs in O(logn) time. 3 | 4 | #include 5 | 6 | int binarySearch(int arr[], int low, int high) 7 | { 8 | if(high >= low) 9 | { 10 | int mid = (low + high)/2; 11 | if(mid == arr[mid]) 12 | return mid; 13 | if(mid > arr[mid]) 14 | return binarySearch(arr, (mid + 1), high); 15 | else 16 | return binarySearch(arr, low, (mid -1)); 17 | } 18 | 19 | /* Return -1 if there is no Fixed Point */ 20 | return -1; 21 | } 22 | 23 | /* Driver program to check above functions */ 24 | int main() 25 | { 26 | int arr[10] = {-10, -1, 0, 3, 10, 11, 30, 50, 100}; 27 | int n = sizeof(arr)/sizeof(arr[0]); 28 | printf("Fixed Point is %d", binarySearch(arr, 0, n-1)); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.4_Power_Set.cpp: -------------------------------------------------------------------------------- 1 | //We use the solution 2 described in the book. 2 | //Namely, for a set with length n, we simply iterate over all binary numbers with n bits. 3 | //For each number, the corresponding set is constrcted as follows: 4 | //if ith position is 1, then we put ith element into the set. 5 | //otherwise, we do not select ith element. 6 | //Each number corresponds exactly to one set. 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | void printPowerSet(char *set, int set_size) 13 | { 14 | /*set_size of power set of a set with set_size 15 | n is 2**n, empty set included*/ 16 | unsigned int pow_set_size = pow(2, set_size); 17 | int counter, j; 18 | 19 | /*Run from counter 000..0 to 111..1*/ 20 | for(counter = 0; counter < pow_set_size; counter++) 21 | { 22 | for(j = 0; j < set_size; j++) 23 | { 24 | /* Check if jth bit in the counter is set 25 | If set then print jth element from set */ 26 | if(counter & (1< 2 | 3 | /*The first method is rather simple and only add operation is used.*/ 4 | int recursive_multiply(int a, int b, int adder) 5 | { 6 | if (b == 1) return a; 7 | a += adder; 8 | b--; 9 | return recursive_multiply(a, b, adder); 10 | } 11 | 12 | int multiply1(int a, int b) 13 | { 14 | if (a ==0 || b == 0) return 0; 15 | return recursive_multiply(a, b, a); 16 | } 17 | 18 | /*The second method is the Solution 3 discussed in the book, where division operation is used.*/ 19 | int multiply2(int a, int b){ 20 | if (b==1) return a; 21 | int b_half = b >> 1; //divide by 2 22 | int half_result = multiply2(a, b_half); 23 | if (b % 2 == 0){ 24 | return half_result + half_result; 25 | } 26 | else { 27 | return half_result + half_result + a; 28 | } 29 | } 30 | 31 | int main(){ 32 | int a = 7, b = 9; 33 | printf("The result from method 1 is %i \n", multiply1(a, b)); 34 | printf("The result from method 2 is %i", multiply2(a, b)); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.6_Tower_of_Hanoi.cpp: -------------------------------------------------------------------------------- 1 | // C++ Program for Iterative Tower of Hanoi 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | //Function to show the movement of disks 9 | void moveDisk(const char *fromPeg, const char *toPeg, int disk) 10 | { 11 | printf("Move the disk %d from \'%s\' to \'%s\'\n", 12 | disk, fromPeg, toPeg); 13 | } 14 | 15 | // Function to implement legal movement between 16 | // two poles 17 | void moveDisksBetweenTwoPoles(stack &start, stack &dest, const char *s, const char *d) 18 | { 19 | int pole1TopDisk, pole2TopDisk; 20 | if (!start.empty()) 21 | { 22 | pole1TopDisk = start.top(); 23 | start.pop(); 24 | } else { 25 | pole1TopDisk = INT_MIN; 26 | } 27 | 28 | if (!dest.empty()) 29 | { 30 | pole2TopDisk = dest.top(); 31 | dest.pop(); 32 | } else { 33 | pole2TopDisk = INT_MIN; 34 | } 35 | 36 | 37 | // When pole 1 is already empty [Condition pole1TopDisk == INT_MIN is different than stack.empty(), 38 | // which checks whether the stack is empty AFTER pop an element! 39 | if (pole1TopDisk == INT_MIN) 40 | { 41 | start.push(pole2TopDisk); 42 | moveDisk(d, s, pole2TopDisk); 43 | } 44 | 45 | // When pole2 pole is already empty 46 | else if (pole2TopDisk == INT_MIN) 47 | { 48 | dest.push(pole1TopDisk); 49 | moveDisk(s, d, pole1TopDisk); 50 | } 51 | 52 | // When top disk of pole1 > top disk of pole2 53 | else if (pole1TopDisk > pole2TopDisk) 54 | { 55 | start.push(pole1TopDisk); 56 | start.push(pole2TopDisk); 57 | moveDisk(d, s, pole2TopDisk); 58 | } 59 | 60 | // When top disk of pole1 < top disk of pole2 61 | else 62 | { 63 | dest.push(pole2TopDisk); 64 | dest.push(pole1TopDisk); 65 | moveDisk(s, d, pole1TopDisk); 66 | } 67 | } 68 | 69 | 70 | 71 | //Function to implement TOH puzzle 72 | void tohIterative(int num_of_disks, stack &start, stack &aux, stack &dest) 73 | { 74 | int i, total_num_of_moves; 75 | const char* s = "Starting", *d = "Destination", *a = "Auxiliary"; 76 | 77 | //If number of disks is even, then interchange 78 | //destination pole and auxiliary pole 79 | if (num_of_disks % 2 == 0) 80 | { 81 | const char *temp = d; 82 | d = a; 83 | a = temp; 84 | } 85 | total_num_of_moves = pow(2, num_of_disks) - 1; 86 | 87 | //Larger disks will be pushed first 88 | for (i = num_of_disks; i >= 1; i--) 89 | start.push(i); 90 | 91 | for (i = 1; i <= total_num_of_moves; i++) 92 | { 93 | if (i % 3 == 1) 94 | moveDisksBetweenTwoPoles(start, dest, s, d); 95 | 96 | else if (i % 3 == 2) 97 | moveDisksBetweenTwoPoles(start, aux, s, a); 98 | 99 | else if (i % 3 == 0) 100 | moveDisksBetweenTwoPoles(aux, dest, a, d); 101 | } 102 | } 103 | 104 | // Driver Program 105 | int main() 106 | { 107 | // Input: number of disks 108 | unsigned num_of_disks = 3; 109 | 110 | stack start, dest, aux; 111 | 112 | tohIterative(num_of_disks, start, aux, dest); 113 | return 0; 114 | } 115 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.7_Permutations_without_Dups.cpp: -------------------------------------------------------------------------------- 1 | // C++ program to print all permutations with duplicates allowed 2 | // We use the back tracking strategy 3 | #include 4 | #include 5 | 6 | /* Function to swap values at two pointers */ 7 | void swap(char *x, char *y) 8 | { 9 | char temp; 10 | temp = *x; 11 | *x = *y; 12 | *y = temp; 13 | } 14 | 15 | /* Function to print permutations of string 16 | This function takes three parameters: 17 | 1. String 18 | 2. Starting index of the string 19 | 3. Ending index of the string. */ 20 | void permute(char *a, int l, int r) 21 | { 22 | int i; 23 | if (l == r) 24 | printf("%s\n", a); 25 | else 26 | { 27 | for (i = l; i <= r; i++) 28 | { 29 | swap((a+l), (a+i)); 30 | permute(a, l+1, r); 31 | swap((a+l), (a+i)); //backtrack 32 | } 33 | } 34 | } 35 | 36 | /* Driver program to test above functions */ 37 | int main() 38 | { 39 | char str[] = "ABCDE"; 40 | int n = strlen(str); 41 | permute(str, 0, n-1); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.8_Permutations_with_Dups.cpp: -------------------------------------------------------------------------------- 1 | /// C++ Program to print all permutations of a string in sorted order. 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | 8 | void iter_swap(char *ptr1, char *ptr2) { 9 | 10 | char tmp = *ptr1; *ptr1 = *ptr2; 11 | *ptr2 = tmp; 12 | 13 | } 14 | 15 | char * min_element(char *start, char *end) { // end is 1 beyond the last valid element 16 | 17 | if(start == end) return end; // empty range 18 | char *min_pos = start; 19 | for(char *iter = start+1; iter != end; ++iter) { 20 | if(*iter < *min_pos) min_pos = iter; 21 | } 22 | return min_pos; 23 | } 24 | 25 | void permute(char *str_start, char *str, int length) { 26 | int counter = 0; 27 | if(length == 0) { 28 | printf("%s\n", str_start); 29 | ++counter; 30 | return; 31 | } else { 32 | // Find the smallest char in the string set it to be the first character. Solve the subproblem for the smaller string. 33 | char *smallest = min_element(str, str + length); 34 | iter_swap(str, smallest); 35 | permute(str_start, str+1, length-1); 36 | 37 | // Look for the smallest element strictly greater than the first element of the current string 38 | char *smallest_greater = str + length; 39 | for(char *i = str+1; i != str+length; ++i){ 40 | if(*i > *str && (smallest_greater == str + length || *i < *smallest_greater)) 41 | smallest_greater = i; 42 | } 43 | while(smallest_greater != str+length) { 44 | // If such an element is found, swap it into the first slot and recurse 45 | iter_swap(str, smallest_greater); 46 | permute(str_start, str+1, length-1); 47 | 48 | // Repeat the loop if possible for the next greater character 49 | smallest_greater = str + length; 50 | for(char *i = str+1; i != str+length; ++i) 51 | if(*i > *str && (smallest_greater == str + length || *i < *smallest_greater)) 52 | smallest_greater = i; 53 | } 54 | } 55 | } 56 | 57 | // Driver program to test above function 58 | int main() 59 | { 60 | char str[] = "ACCB"; 61 | permute(str, str, strlen(str)); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /chapter-8-recursion-and-Dynamic-Programming/8.9_Parens.cpp: -------------------------------------------------------------------------------- 1 | //We use the second solution provided in the book. 2 | 3 | # include 4 | # define MAX_SIZE 100 5 | 6 | void _printParenthesis(int pos, int n, int left, int right); 7 | 8 | /* Wrapper over _printParenthesis()*/ 9 | void printParenthesis(int n) 10 | { 11 | if(n > 0) 12 | _printParenthesis(0, n, 0, 0); 13 | return; 14 | } 15 | 16 | void _printParenthesis(int pos, int n, int left, int right) //left/right is the number of left/right parentheses already used 17 | { 18 | static char str[MAX_SIZE]; 19 | 20 | if(left == n && right == n) //If both types of parentheses are used up, we print the sequence 21 | { 22 | printf("%s \n", str); 23 | return; 24 | } 25 | else 26 | { 27 | if(left > right) { 28 | str[pos] = ')'; 29 | _printParenthesis(pos+1, n, left, right+1); //position index always increases by 1 30 | } 31 | if(left < n) { 32 | str[pos] = '('; 33 | _printParenthesis(pos+1, n, left+1, right); 34 | } 35 | } 36 | } 37 | 38 | /* driver program to test above functions */ 39 | int main() 40 | { 41 | int n = 4; 42 | printParenthesis(n); 43 | return 0; 44 | } 45 | --------------------------------------------------------------------------------