diff --git a/09_backtracking/0_intro.cpp b/09_backtracking/0_intro.cpp new file mode 100644 index 0000000..d85e219 --- /dev/null +++ b/09_backtracking/0_intro.cpp @@ -0,0 +1,15 @@ +/* + what is backtracking ? + video: https://youtu.be/SJ_pXT-L5IE + + how it is implemented (logically) + video: https://youtu.be/DKCbsiDBN6c + + + Backtracking Algorithm: + Backtracking is an algorithmic-technique for solving problems recursively by trying + to build a solution incrementally. Solving one piece at a time, and removing those solutions + that fail to satisfy the constraints of the problem at any point of time (by time, here, + is referred to the time elapsed till reaching any level of the search tree) is the process of backtracking. + +*/ diff --git a/09_backtracking/10_tug_of_war.cpp b/09_backtracking/10_tug_of_war.cpp new file mode 100644 index 0000000..5999b19 --- /dev/null +++ b/09_backtracking/10_tug_of_war.cpp @@ -0,0 +1,54 @@ +/* + link (little confusing) : https://www.geeksforgeeks.org/tug-of-war/ + + video: https://youtu.be/Q1fLW_zQr3M +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +static string allComb = ""; +static int minDiff = INT_MAX; + + +void tugOfWar(int arr[], int n, int idx, vector set1, vector set2, int soset1, int soset2) { + if (idx == n) { + int diff = abs(soset1 - soset2); + + if (diff < minDiff) { + minDiff = diff; + + string ans = ""; + + for (int x : set1) ans += " " + to_string(x); + ans += " " + "$"; + for (int x : set2) ans += " " + to_string(x); + + allComb = ans.substr(1); + } + return; + } + + if (set1.size() < (n + 1) / 2) { + set1.push_back(arr[idx]); + solve(arr, n, idx + 1, set1, set2, soset1 + arr[idx], soset2); + set1.pop_back(); + } + + if (set2.size() < (n + 1) / 2) { + set2.push_back(arr[idx]); + solve(arr, n, idx + 1, set1, set2, soset1, soset2 + arr[idx]); + set2.pop_back(); + } +} + + +int main() { + int arr[] = { 23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4 }; + int n = sizeof(arr) / sizeof(arr[0]); + + vector set1, set2; + + tugOfWar(arr, n, 0, set1, set2, 0, 0); + return 0; +} diff --git a/09_backtracking/11_find_shortest_safe_route_in_path_with_landmines.cpp b/09_backtracking/11_find_shortest_safe_route_in_path_with_landmines.cpp new file mode 100644 index 0000000..658e6ec --- /dev/null +++ b/09_backtracking/11_find_shortest_safe_route_in_path_with_landmines.cpp @@ -0,0 +1,194 @@ +/* + link: https://www.geeksforgeeks.org/find-shortest-safe-route-in-a-path-with-landmines/ + + note: + calculate length of the shortest safe route possible from any cell + in the first column to any cell in the last column of the matrix. +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +// C++ program to find shortest safe Route in +// the matrix with landmines +#include +using namespace std; +#define R 12 +#define C 10 + +// These arrays are used to get row and column +// numbers of 4 neighbours of a given cell +int rowNum[] = { -1, 0, 0, 1 }; +int colNum[] = { 0, -1, 1, 0 }; + +// A function to check if a given cell (x, y) +// can be visited or not +bool isSafe(int mat[R][C], int visited[R][C], + int x, int y) +{ + if (mat[x][y] == 0 || visited[x][y]) + return false; + + return true; +} + +// A function to check if a given cell (x, y) is +// a valid cell or not +bool isValid(int x, int y) +{ + if (x < R && y < C && x >= 0 && y >= 0) + return true; + + return false; +} + +// A function to mark all adjacent cells of +// landmines as unsafe. Landmines are shown with +// number 0 +void markUnsafeCells(int mat[R][C]) +{ + for (int i = 0; i < R; i++) + { + for (int j = 0; j < C; j++) + { + // if a landmines is found + if (mat[i][j] == 0) + { + // mark all adjacent cells + for (int k = 0; k < 4; k++) + if (isValid(i + rowNum[k], j + colNum[k])) + mat[i + rowNum[k]][j + colNum[k]] = -1; + } + } + } + + // mark all found adjacent cells as unsafe + for (int i = 0; i < R; i++) + { + for (int j = 0; j < C; j++) + { + if (mat[i][j] == -1) + mat[i][j] = 0; + } + } + + // Uncomment below lines to print the path + /*for (int i = 0; i < R; i++) + { + for (int j = 0; j < C; j++) + { + cout << std::setw(3) << mat[i][j]; + } + cout << endl; + }*/ +} + +// Function to find shortest safe Route in the +// matrix with landmines +// mat[][] - binary input matrix with safe cells marked as 1 +// visited[][] - store info about cells already visited in +// current route +// (i, j) are coordinates of the current cell +// min_dist --> stores minimum cost of shortest path so far +// dist --> stores current path cost +void findShortestPathUtil(int mat[R][C], int visited[R][C], + int i, int j, int& min_dist, int dist) +{ + // if destination is reached + if (j == C - 1) + { + // update shortest path found so far + min_dist = min(dist, min_dist); + return; + } + + // if current path cost exceeds minimum so far + if (dist > min_dist) + return; + + // include (i, j) in current path + visited[i][j] = 1; + + // Recurse for all safe adjacent neighbours + for (int k = 0; k < 4; k++) + { + if (isValid(i + rowNum[k], j + colNum[k]) && + isSafe(mat, visited, i + rowNum[k], j + colNum[k])) + { + findShortestPathUtil(mat, visited, i + rowNum[k], + j + colNum[k], min_dist, dist + 1); + } + } + + // Backtrack + visited[i][j] = 0; +} + +// A wrapper function over findshortestPathUtil() +void findShortestPath(int mat[R][C]) +{ + // stores minimum cost of shortest path so far + int min_dist = INT_MAX; + + // create a boolean matrix to store info about + // cells already visited in current route + int visited[R][C]; + + // mark adjacent cells of landmines as unsafe + markUnsafeCells(mat); + + // start from first column and take minimum + for (int i = 0; i < R; i++) + { + // if path is safe from current cell + if (mat[i][0] == 1) + { + // initialize visited to false + memset(visited, 0, sizeof visited); + + // find shortest route from (i, 0) to any + // cell of last column (x, C - 1) where + // 0 <= x < R + findShortestPathUtil(mat, visited, i, 0, + min_dist, 0); + +// if min distance is already found + if (min_dist == C - 1) + break; + } + } + + // if destination can be reached + if (min_dist != INT_MAX) + cout << "Length of shortest safe route is " + << min_dist; + + else // if the destination is not reachable + cout << "Destination not reachable from " + << "given source"; +} + +// Driver code +int main() +{ + // input matrix with landmines shown with number 0 + int mat[R][C] = + { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, + { 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 } + }; + + // find shortest path + findShortestPath(mat); + + return 0; +} diff --git a/09_backtracking/12_combinational_sum.cpp b/09_backtracking/12_combinational_sum.cpp new file mode 100644 index 0000000..df6dd3c --- /dev/null +++ b/09_backtracking/12_combinational_sum.cpp @@ -0,0 +1,139 @@ +/* + link: https://practice.geeksforgeeks.org/problems/combination-sum-1587115620/1 + + sol: https://www.geeksforgeeks.org/combinational-sum/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// C++ program to find all combinations that +// sum to a given value +#include +using namespace std; + +// Print all members of ar[] that have given +void findNumbers(vector& ar, int sum, + vector >& res, vector& r, + int i) +{ + // if we get exact answer + if (sum == 0) { + res.push_back(r); + return; + } + + // Recur for all remaining elements that + // have value smaller than sum. + while (i < ar.size() && sum - ar[i] >= 0) { + + // Till every element in the array starting + // from i which can contribute to the sum + r.push_back(ar[i]); // add them to list + + // recur for next numbers + findNumbers(ar, sum - ar[i], res, r, i); + i++; + + // Remove number from list (backtracking) + r.pop_back(); + } +} + +// Returns all combinations +// of ar[] that have given +// sum. +vector > combinationSum(vector& ar, + int sum) +{ + // sort input array + sort(ar.begin(), ar.end()); + + // remove duplicates + ar.erase(unique(ar.begin(), ar.end()), ar.end()); + + vector r; + vector > res; + findNumbers(ar, sum, res, r, 0); + + return res; +} + +// Driver code +int main() +{ + vector ar; + ar.push_back(2); + ar.push_back(4); + ar.push_back(6); + ar.push_back(8); + int n = ar.size(); + + int sum = 8; // set value of sum + vector > res = combinationSum(ar, sum); + + // If result is empty, then + if (res.size() == 0) { + cout << "Emptyn"; + return 0; + } + + // Print all combinations stored in res. + for (int i = 0; i < res.size(); i++) { + if (res[i].size() > 0) { + cout << " ( "; + for (int j = 0; j < res[i].size(); j++) + cout << res[i][j] << " "; + cout << ")"; + } + } +} + + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + alternate solution +*/ +vector> ans; + +void solve(int idx, vector currVec, int sum, vector& v, int B) { + if (sum > B || idx >= v.size()) return; + + if (sum == B) { + ans.push_back(currVec); + return; + } + + while (idx < v.size() && sum <= B) { + + currVec.push_back(v[idx]); + + if (v[idx] + sum <= B) solve(idx, currVec, sum + v[idx], v, B); + + currVec.pop_back(); + + idx++; + } +} + + +vector> combinationSum(vector& A, int B) { + + ans.clear(); + + set s; + for (int i : A) s.insert(i); + + vector v(s.begin(), s.end()); + + solve(0, {}, 0, v, B); + + return ans; +} diff --git a/09_backtracking/13_maximum_no_possible_by_doing_atmost_k_swaps.cpp b/09_backtracking/13_maximum_no_possible_by_doing_atmost_k_swaps.cpp new file mode 100644 index 0000000..183093e --- /dev/null +++ b/09_backtracking/13_maximum_no_possible_by_doing_atmost_k_swaps.cpp @@ -0,0 +1,147 @@ +/* + link: https://practice.geeksforgeeks.org/problems/largest-number-in-k-swaps-1587115620/1 + + video: https://youtu.be/5crucASFoA4 + (just to understand as it will give TLE in GFG) + + sol: https://www.geeksforgeeks.org/find-maximum-number-possible-by-doing-at-most-k-swaps/ +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + Time Complexity: O((n^2)^k). + For every recursive call n^2 recursive calls is generated until + the value of k is 0. So total recursive calls are O((n^2)^k). + + Space Complexity:O(n). +*/ +void recur( + string str, int k, string& max) +{ + // Return if no swaps left + if (k == 0) + return; + + int n = str.length(); + + // Consider every digit + for (int i = 0; i < n - 1; i++) { + + // Compare it with all digits after it + for (int j = i + 1; j < n; j++) { + // if digit at position i + // is less than digit + // at position j, swap it + // and check for maximum + // number so far and recurse + // for remaining swaps + if (str[i] < str[j]) { + // swap str[i] with str[j] + swap(str[i], str[j]); + + // If current num is more + // than maximum so far + if (str.compare(max) > 0) + max = str; + + // recurse of the other k - 1 swaps + recur(str, k - 1, max); + + // Backtrack + swap(str[i], str[j]); + } + } + } +} + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(n^k). + For every recursive call n recursive calls is generated until + the value of k is 0. So total recursive calls are O((n)^k). + + SC: O(N) +*/ + +// C++ program to find maximum +// integer possible by doing +// at-most K swap operations on +// its digits. +#include +using namespace std; + +// Function to find maximum +// integer possible by +// doing at-most K swap operations +// on its digits +void findMaximumNum( + string str, int k, + string& max, int ctr) +{ + // return if no swaps left + if (k == 0) + return; + + int n = str.length(); + + // Consider every digit after + // the cur position + char maxm = str[ctr]; + for (int j = ctr + 1; j < n; j++) { + // Find maximum digit greater + // than at ctr among rest + if (maxm < str[j]) + maxm = str[j]; + } + + // If maxm is not equal to k, + // decrement k + if (maxm != str[ctr]) + --k; + + // search this maximum among the rest + for (int j = ctr; j < n; j++) { + // If digit equals maxm swap + // the digit with current + // digit and recurse for the rest + if (str[j] == maxm) { + // swap str[ctr] with str[j] + swap(str[ctr], str[j]); + + // If current num is more than + // maximum so far + if (str.compare(max) > 0) + max = str; + + // recurse other swaps after cur + findMaximumNum(str, k, max, ctr + 1); + + // Backtrack + swap(str[ctr], str[j]); + } + } +} + +// Driver code +int main() +{ + string str = "129814999"; + int k = 4; + + string max = str; + findMaximumNum(str, k, max, 0); + + cout << max << endl; + + return 0; +} diff --git a/09_backtracking/14_print_all_permutations_of_string.cpp b/09_backtracking/14_print_all_permutations_of_string.cpp new file mode 100644 index 0000000..cca12d9 --- /dev/null +++ b/09_backtracking/14_print_all_permutations_of_string.cpp @@ -0,0 +1,108 @@ +/* + link: https://practice.geeksforgeeks.org/problems/permutations-of-a-given-string2041/1 + + sol: https://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/ +*/ + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + here duplicate will also be included + + Time Complexity: + O(n*n!) The time complexity is the same as the above approach, + i.e. there are n! permutations and it requires O(n) time to print a permutation. +*/ + +// C++ program to print all +// permutations with duplicates allowed +#include +using namespace std; + + +// Function to print permutations of string +// This function takes three parameters: +// 1. String +// 2. Starting index of the string +// 3. Ending index of the string. +void permute(string a, int l, int r) +{ + // Base case + if (l == r) + cout << a << endl; + else + { + // Permutations made + for (int i = l; i <= r; i++) + { + + // Swapping done + swap(a[l], a[i]); + + // Recursion called + permute(a, l + 1, r); + + //backtrack + swap(a[l], a[i]); + } + } +} + +// Driver Code +int main() +{ + string str = "ABC"; + int n = str.size(); + permute(str, 0, n - 1); + return 0; +} + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + by ignoring element every time + (but here duplicate wont print) + + Time Complexity: + O(n*n!) The time complexity is the same as the above approach, + i.e. there are n! permutations and it requires O(n) time to print a permutation. +*/ +#include +#include +using namespace std; + +void permute(string s, string answer) +{ + if (s.length() == 0) + { + cout << answer << " "; + return; + } + for (int i = 0; i < s.length(); i++) + { + char ch = s[i]; + string left_substr = s.substr(0, i); + string right_substr = s.substr(i + 1); + string rest = left_substr + right_substr; + permute(rest, answer + ch); + } +} + +int main() +{ + string s; + string answer = ""; + + cout << "Enter the string : "; + cin >> s; + + cout << "\nAll possible strings are : "; + permute(s, answer); + return 0; +} diff --git a/09_backtracking/15_find_if_there_is_path_of_more_than_k_length_from_source.cpp b/09_backtracking/15_find_if_there_is_path_of_more_than_k_length_from_source.cpp new file mode 100644 index 0000000..fc38e3a --- /dev/null +++ b/09_backtracking/15_find_if_there_is_path_of_more_than_k_length_from_source.cpp @@ -0,0 +1,3 @@ +/* + ref: graph/36_find_if_there... +*/ diff --git a/09_backtracking/16_longest_possible_route_in_matrix_with_hurdles.cpp b/09_backtracking/16_longest_possible_route_in_matrix_with_hurdles.cpp new file mode 100644 index 0000000..6b14a1b --- /dev/null +++ b/09_backtracking/16_longest_possible_route_in_matrix_with_hurdles.cpp @@ -0,0 +1,150 @@ +/* + link: https://www.geeksforgeeks.org/longest-possible-route-in-a-matrix-with-hurdles/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// C++ program to find Longest Possible Route in a +// matrix with hurdles +#include +using namespace std; +#define R 3 +#define C 10 + +// A Pair to store status of a cell. found is set to +// true of destination is reachable and value stores +// distance of longest path +struct Pair +{ + // true if destination is found + bool found; + + // stores cost of longest path from current cell to + // destination cell + int value; +}; + +// Function to find Longest Possible Route in the +// matrix with hurdles. If the destination is not reachable +// the function returns false with cost INT_MAX. +// (i, j) is source cell and (x, y) is destination cell. +Pair findLongestPathUtil(int mat[R][C], int i, int j, + int x, int y, bool visited[R][C]) +{ + + // if (i, j) itself is destination, return true + if (i == x && j == y) + { + Pair p = { true, 0 }; + return p; + } + + // if not a valid cell, return false + if (i < 0 || i >= R || j < 0 || j >= C || + mat[i][j] == 0 || visited[i][j]) + { + Pair p = { false, INT_MAX }; + return p; + } + + // include (i, j) in current path i.e. + // set visited(i, j) to true + visited[i][j] = true; + + // res stores longest path from current cell (i, j) to + // destination cell (x, y) + int res = INT_MIN; + + // go left from current cell + Pair sol = findLongestPathUtil(mat, i, j - 1, x, y, visited); + + // if destination can be reached on going left from current + // cell, update res + if (sol.found) + res = max(res, sol.value); + + // go right from current cell + sol = findLongestPathUtil(mat, i, j + 1, x, y, visited); + + // if destination can be reached on going right from current + // cell, update res + if (sol.found) + res = max(res, sol.value); + + // go up from current cell + sol = findLongestPathUtil(mat, i - 1, j, x, y, visited); + + // if destination can be reached on going up from current + // cell, update res + if (sol.found) + res = max(res, sol.value); + + // go down from current cell + sol = findLongestPathUtil(mat, i + 1, j, x, y, visited); + + // if destination can be reached on going down from current + // cell, update res + if (sol.found) + res = max(res, sol.value); + + // Backtrack + visited[i][j] = false; + + // if destination can be reached from current cell, + // return true + if (res != INT_MIN) + { + Pair p = { true, 1 + res }; + return p; + } + + // if destination can't be reached from current cell, + // return false + else + { + Pair p = { false, INT_MAX }; + return p; + } +} + +// A wrapper function over findLongestPathUtil() +void findLongestPath(int mat[R][C], int i, int j, int x, + int y) +{ + // create a boolean matrix to store info about + // cells already visited in current route + bool visited[R][C]; + + // initialize visited to false + memset(visited, false, sizeof visited); + + // find longest route from (i, j) to (x, y) and + // print its maximum cost + Pair p = findLongestPathUtil(mat, i, j, x, y, visited); + if (p.found) + cout << "Length of longest possible route is " + << p.value; + +// If the destination is not reachable + else + cout << "Destination not reachable from given source"; +} + +// Driver code +int main() +{ + // input matrix with hurdles shown with number 0 + int mat[R][C] = + { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + { 1, 1, 0, 1, 1, 0, 1, 1, 0, 1 }, + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } + }; + + // find longest path with source (0, 0) and + // destination (1, 7) + findLongestPath(mat, 0, 0, 1, 7); + + return 0; +} diff --git a/09_backtracking/17_print_all_possible_path_from_top_left_to_bottom_right_in_MN_matrix.cpp b/09_backtracking/17_print_all_possible_path_from_top_left_to_bottom_right_in_MN_matrix.cpp new file mode 100644 index 0000000..37d36cf --- /dev/null +++ b/09_backtracking/17_print_all_possible_path_from_top_left_to_bottom_right_in_MN_matrix.cpp @@ -0,0 +1,71 @@ +/* + link: https://www.geeksforgeeks.org/print-all-possible-paths-from-top-left-to-bottom-right-of-a-mxn-matrix/ + + note: also refer other 3 code from **link** +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(2^n*m) + SC: O(n) +*/ +#include +using namespace std; + +// function to display the path +void display(vector& ans) { + for (auto i : ans) { + cout << i << " "; + } + cout << endl; +} + +// a function which check whether our step is safe or not +bool issafe(int r, int c, vector>& visited, int n, int m) { + return (r < nand c < mand visited[r] != -1); // return true if all values satisfied else false +} + + +void FindPaths(vector>& grid, int r, int c, int n, int m, vector& ans) { +// when we hit the last cell we reach to destination then direclty push the path + if (r == n - 1 and c == m - 1) { + ans.push_back(grid[r]); + display(ans); // function to display the path stored in ans vector + ans.pop_back(); // pop back because we need to backtrack to explore more path + return; + } + + // we will store the current value in ch and mark the visited place as -1 + int ch = grid[r]; + + ans.push_back(ch); // push the path in ans array + grid[r] = -1; // mark the visited place with -1 + + // if is it safe to take next downward step then take it + if (issafe(r + 1, c, grid, n, m)) { + FindPaths(grid, r + 1, c, n, m, ans); + } + + // if is it safe to take next rightward step then take it + if (issafe(r, c + 1, grid, n, m)) { + FindPaths(grid, r, c + 1, n, m, ans); + } + + // backtracking step we need to make values original so to we can visit it by some another path + grid[r] = ch; + + // remove the current path element we explore + ans.pop_back(); + return; +} + +int main() { + int n = 3, m = 3; + vector >grid{ {1,2,3},{4,5,6},{7,8,9} }; + vectorans; // it will store the path which we have covered + + FindPaths(grid, 0, 0, n, m, ans); // here 0,0 are initial position to start with + return 0; +} diff --git a/09_backtracking/18_partition_of_set_into_K_subset_with_equal_sum.cpp b/09_backtracking/18_partition_of_set_into_K_subset_with_equal_sum.cpp new file mode 100644 index 0000000..c77eb03 --- /dev/null +++ b/09_backtracking/18_partition_of_set_into_K_subset_with_equal_sum.cpp @@ -0,0 +1,305 @@ +/* + link: https://practice.geeksforgeeks.org/problems/partition-array-to-k-subsets/1 + + video (also possible set will be stored): https://youtu.be/rszwy53vaP0 + note: here in this problem we just have to say is it possible or not ?! + but still we have included which sets + + + sol: https://www.geeksforgeeks.org/partition-set-k-subsets-equal-sum/ + sol: https://www.geeksforgeeks.org/partition-of-a-set-into-k-subsets-with-equal-sum-using-bitmask-and-dp/ +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// explanation is given in video +bool solve(int a[], int vidx, int n, int k, vector& subsetSum, int extraSet, vector>& ans) { + if (vidx >= n) { + if (extraSet == k) { + bool flag = true; + + for (int i = 0;i < subsetSum.size() - 1;i++) { + if (subsetSum[i] != subsetSum[i + 1]) { + flag = false; + break; + } + } + + if (flag) { + return true; + } + } + return false; + } + + + + for (int i = 0; i < k; i++) { + if (ans[i].size() > 0) { + ans[i].push_back(a[vidx]); + subsetSum[i] += a[vidx]; + if (solve(a, vidx + 1, n, k, subsetSum, extraSet, ans)) return true; + subsetSum[i] -= a[vidx]; + ans[i].pop_back(); + } + else { + ans[i].push_back(a[vidx]); + subsetSum[i] += a[vidx]; + if (solve(a, vidx + 1, n, k, subsetSum, extraSet + 1, ans)) return true; + subsetSum[i] -= a[vidx]; + ans[i].pop_back(); + break; + } + } + return false; +} + +bool isKPartitionPossible(int a[], int n, int k) +{ + int sum = 0; + vector subsetSum(k); + vector> ans(k); + + for (int i = 0;i < n;i++) sum += a[i]; + + if (k > n || sum % k != 0) return false; + + return solve(a, 0, n, k, subsetSum, 0, ans); +} + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + alternate method + +*/ +// C++ program to check whether an array can be +// partitioned into K subsets of equal sum +#include +using namespace std; + +// Recursive Utility method to check K equal sum +// subsetition of array +/** + array - given input array + subsetSum array - sum to store each subset of the array + taken - boolean array to check whether element + is taken into sum partition or not + K - number of partitions needed + N - total number of element in array + curIdx - current subsetSum index + limitIdx - lastIdx from where array element should + be taken */ +bool isKPartitionPossibleRec(int arr[], int subsetSum[], bool taken[], + int subset, int K, int N, int curIdx, int limitIdx) +{ + if (subsetSum[curIdx] == subset) + { + /* current index (K - 2) represents (K - 1) subsets of equal + sum last partition will already remain with sum 'subset'*/ + if (curIdx == K - 2) + return true; + + // recursive call for next subsetition + return isKPartitionPossibleRec(arr, subsetSum, taken, subset, + K, N, curIdx + 1, N - 1); + } + + // start from limitIdx and include elements into current partition + for (int i = limitIdx; i >= 0; i--) + { + // if already taken, continue + if (taken[i]) + continue; + int tmp = subsetSum[curIdx] + arr[i]; + + // if temp is less than subset then only include the element + // and call recursively + if (tmp <= subset) + { + // mark the element and include into current partition sum + taken[i] = true; + subsetSum[curIdx] += arr[i]; + bool nxt = isKPartitionPossibleRec(arr, subsetSum, taken, + subset, K, N, curIdx, i - 1); + +// after recursive call unmark the element and remove from +// subsetition sum + taken[i] = false; + subsetSum[curIdx] -= arr[i]; + if (nxt) + return true; + } + } + return false; +} + +// Method returns true if arr can be partitioned into K subsets +// with equal sum +bool isKPartitionPossible(int arr[], int N, int K) +{ + // If K is 1, then complete array will be our answer + if (K == 1) + return true; + + // If total number of partitions are more than N, then + // division is not possible + if (N < K) + return false; + + // if array sum is not divisible by K then we can't divide + // array into K partitions + int sum = 0; + for (int i = 0; i < N; i++) + sum += arr[i]; + if (sum % K != 0) + return false; + + // the sum of each subset should be subset (= sum / K) + int subset = sum / K; + int subsetSum[K]; + bool taken[N]; + + // Initialize sum of each subset from 0 + for (int i = 0; i < K; i++) + subsetSum[i] = 0; + + // mark all elements as not taken + for (int i = 0; i < N; i++) + taken[i] = false; + + // initialize first subsubset sum as last element of + // array and mark that as taken + subsetSum[0] = arr[N - 1]; + taken[N - 1] = true; + + // call recursive method to check K-substitution condition + return isKPartitionPossibleRec(arr, subsetSum, taken, + subset, K, N, 0, N - 1); +} + +// Driver code to test above methods +int main() +{ + int arr[] = { 2, 1, 4, 5, 3, 3 }; + int N = sizeof(arr) / sizeof(arr[0]); + int K = 3; + + if (isKPartitionPossible(arr, N, K)) + cout << "Partitions into equal sum is possible.\n"; + else + cout << "Partitions into equal sum is not possible.\n"; +} + + + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + using DP and bitmasking +*/ +// C++ program to check if the +// given array can be partitioned +// into K subsets with equal sum +#include +using namespace std; + +// Function to check whether +// K required partitions +// are possible or not +bool isKPartitionPossible(int arr[], + int N, int K) +{ + if (K == 1) + // Return true as the + // entire array is the + // answer + return true; + + // If total number of + // partitions exceeds + // size of the array + if (N < K) + return false; + + int sum = 0; + for (int i = 0; i < N; i++) + sum += arr[i]; + // If the array sum is not + // divisible by K + if (sum % K != 0) + // No such partitions are + // possible + return false; + + // Required sum of + // each subset + int target = sum / K; + + // Initialize dp array with -1 + int dp[(1 << 15)]; + for (int i = 0; i < (1 << N); i++) + dp[i] = -1; + + // Sum of empty subset + // is zero + dp[0] = 0; + + // Iterate over all subsets/masks + for (int mask = 0; mask < (1 << N); mask++) { + // if current mask is invalid, continue + if (dp[mask] == -1) + continue; + + // Iterate over all array elements + for (int i = 0; i < N; i++) { + // Check if the current element + // can be added to the current + // subset/mask + if (!(mask & (1 << i)) + && dp[mask] + + arr[i] + <= target) { + // transition + dp[mask | (1 << i)] + = (dp[mask] + + arr[i]) + % target; + } + } + } + + if (dp[(1 << N) - 1] == 0) + return true; + else + return false; +} + +// Driver Code +int main() +{ + int arr[] = { 2, 1, 4, 5, 3, 3 }; + int N = sizeof(arr) / sizeof(arr[0]); + int K = 3; + + if (isKPartitionPossible(arr, N, K)) { + cout << "Partitions into equal "; + cout << "sum is possible.\n"; + } + else { + cout << "Partitions into equal "; + cout << "sum is not possible.\n"; + } +} diff --git a/09_backtracking/19_kth_permutation_sequence_of_first_N_natural_no.cpp b/09_backtracking/19_kth_permutation_sequence_of_first_N_natural_no.cpp new file mode 100644 index 0000000..faeefd7 --- /dev/null +++ b/09_backtracking/19_kth_permutation_sequence_of_first_N_natural_no.cpp @@ -0,0 +1,100 @@ +/* + sol: https://www.geeksforgeeks.org/find-the-k-th-permutation-sequence-of-first-n-natural-numbers/ + + link: https://leetcode.com/problems/permutation-sequence/ + + video: https://youtu.be/wT7gcXLYoao + (watch the explanation) +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + recursive solution + + TC: O(N!) + O(N logN) => O(N!) + N! to generate every combination + N logN to sort all the permutation + + SC: O(N) => as we keep deep copy of every combination +*/ + +set finalAns; +void permute(string s, string answer) +{ + if (s.length() == 0) + { + // cout << answer << endl; + finalAns.insert(answer); + return; + } + for (int i = 0; i < s.length(); i++) + { + char ch = s[i]; + string left_substr = s.substr(0, i); + string right_substr = s.substr(i + 1); + string rest = left_substr + right_substr; + permute(rest, answer + ch); + } +} +string getPermutation(int n, int k) { + string str = ""; + for (int i = 1; i <= n; i++) { + str += i + '0'; + } + + permute(str, ""); + + int i = 0; + + for (auto curr : finalAns) { + i++; + if (i == k) return curr; + } + return ""; +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + efficient solution + + TC: O(N * N) => 1st for iterating to all no. and 2nd for erasing each time in each itertation + SC: O(N) => for storing all no. +*/ +class Solution { + public: + string getPermutation(int n, int k) { + int fact = 1; + vector numbers; + for (int i = 1;i < n;i++) { + fact = fact * i; + numbers.push_back(i); + } + numbers.push_back(n); + string ans = ""; + + k = k - 1; // as we will doing operation on 0th based indexing + + while (true) { + ans = ans + to_string(numbers[k / fact]); + numbers.erase(numbers.begin() + k / fact); + + // IMP + if (numbers.size() == 0) { + break; + } + + // as we remove top unnecessary combination + k = k % fact; + + // it also equal to fact /= size-1; each time + fact = fact / numbers.size(); + } + return ans; + } +}; \ No newline at end of file diff --git a/09_backtracking/1_rat_in_maze.cpp b/09_backtracking/1_rat_in_maze.cpp new file mode 100644 index 0000000..3066248 --- /dev/null +++ b/09_backtracking/1_rat_in_maze.cpp @@ -0,0 +1,265 @@ +/* + link: https://practice.geeksforgeeks.org/problems/rat-in-a-maze-problem/1 + + sol: https://www.geeksforgeeks.org/rat-in-a-maze-backtracking-2/ + + sol(no. of ways): https://www.geeksforgeeks.org/count-number-ways-reach-destination-maze/ + + video: https://youtu.be/rKo9MPe0c5A + video2: https://youtu.be/bLGZhJlt4y0 +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + simple using dfs or backtracking + + [Depth First Search (DFS) uses the concept of backtracking at its very core. + So, in DFS, we basically try exploring all the paths from the given node + recursively until we reach the goal. After we search in a particular branch + of a tree in DFS, we can land up in two possible states.] + + TC: O((N ^ 2) ^ 4) + SC: O(N * N) +*/ + +int N; +vector ans; + + +void dfs(int x, int y, string s, vector>& m, vector>& vis) { + if (x < 0 || y < 0 || x >= N || y >= N) return; + if (m[x][y] == 0 || vis[x][y] == 1) return; + + if (x == N - 1 && y == N - 1) { + ans.push_back(s); + return; + } + vis[x][y] = 1; + + dfs(x + 1, y, s + "D", m, vis); + dfs(x, y + 1, s + "R", m, vis); + dfs(x, y - 1, s + "L", m, vis); + dfs(x - 1, y, s + "U", m, vis); + + vis[x][y] = 0; +} + +vector findPath(vector>& m, int n) { + ans.clear(); + N = n; + + if (m[N - 1][N - 1] == 0 || m[0][0] == 0) return ans; + + vector> vis(N, vector(N, 0)); + + dfs(0, 0, "", m, vis); + sort(ans.begin(), ans.end()); + + return ans; +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + Rat in a Maze | Backtracking-2 + + TC: O(2^(n^2)) +*/ + +/* A recursive utility function +to solve Maze problem */ +bool solveMazeUtil( + int maze[N][N], int x, + int y, int sol[N][N]) +{ + // if (x, y is goal) return true + if ( + x == N - 1 && y == N - 1 + && maze[x][y] == 1) { + sol[x][y] = 1; + return true; + } + + // Check if maze[x][y] is valid + if (isSafe(maze, x, y) == true) { + // Check if the current block is already part of solution path. + if (sol[x][y] == 1) + return false; + + // mark x, y as part of solution path + sol[x][y] = 1; + + /* Move forward in x direction */ + if (solveMazeUtil( + maze, x + 1, y, sol) + == true) + return true; + + /* If moving in x direction + doesn't give solution then + Move down in y direction */ + if (solveMazeUtil( + maze, x, y + 1, sol) + == true) + return true; + + /* If moving in y direction + doesn't give solution then + Move back in x direction */ + if (solveMazeUtil( + maze, x - 1, y, sol) + == true) + return true; + + /* If moving backwards in x direction + doesn't give solution then + Move upwards in y direction */ + if (solveMazeUtil( + maze, x, y - 1, sol) + == true) + return true; + + /* If none of the above movements + work then BACKTRACK: unmark + x, y as part of solution path */ + sol[x][y] = 0; + return false; + } + + return false; +} +/* A utility function to check if x, +y is valid index for N*N maze */ +bool isSafe(int maze[N][N], int x, int y) +{ + // if (x, y outside maze) return false + if ( + x >= 0 && x < N && y >= 0 + && y < N && maze[x][y] == 1) + return true; + + return false; +} + +/* This function solves the Maze problem +using Backtracking. It mainly uses +solveMazeUtil() to solve the problem. +It returns false if no path is possible, +otherwise return true and prints the path +in the form of 1s. Please note that there +may be more than one solutions, this +function prints one of the feasible +solutions.*/ +bool solveMaze(int maze[N][N]) +{ + int sol[N][N] = { { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } }; + + if (solveMazeUtil( + maze, 0, 0, sol) + == false) { + printf("Solution doesn't exist"); + return false; + } + + printSolution(sol); + return true; +} + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + Count number of ways to reach destination in a Maze + + TC: O(R * C) +*/ + +#define R 4 +#define C 4 + +// Returns count of possible paths in a maze[R][C] +// from (0,0) to (R-1,C-1) +int countPaths(int maze[][C]) +{ + // If the initial cell is blocked, there is no + // way of moving anywhere + if (maze[0][0] == -1) + return 0; + + // Initializing the leftmost column + for (int i = 0; i < R; i++) + { + if (maze[i][0] == 0) + maze[i][0] = 1; + + // If we encounter a blocked cell in leftmost + // row, there is no way of visiting any cell + // directly below it. + else + break; + } + + // Similarly initialize the topmost row + for (int i = 1; i < C; i++) + { + if (maze[0][i] == 0) + maze[0][i] = 1; + + // If we encounter a blocked cell in bottommost + // row, there is no way of visiting any cell + // directly below it. + else + break; + } + + // The only difference is that if a cell is -1, + // simply ignore it else recursively compute + // count value maze[i][j] + for (int i = 1; i < R; i++) + { + for (int j = 1; j < C; j++) + { + // If blockage is found, ignore this cell + if (maze[i][j] == -1) + continue; + + // If we can reach maze[i][j] from maze[i-1][j] + // then increment count. + if (maze[i - 1][j] > 0) + maze[i][j] = (maze[i][j] + maze[i - 1][j]); + + // If we can reach maze[i][j] from maze[i][j-1] + // then increment count. + if (maze[i][j - 1] > 0) + maze[i][j] = (maze[i][j] + maze[i][j - 1]); + } + } + + // If the final cell is blocked, output 0, otherwise + // the answer + return (maze[R - 1][C - 1] > 0) ? maze[R - 1][C - 1] : 0; +} + +// Driver code +int main() +{ + int maze[R][C] = { {0, 0, 0, 0}, + {0, -1, 0, 0}, + {-1, 0, 0, 0}, + {0, 0, 0, 0} }; + cout << countPaths(maze); + return 0; +} diff --git a/09_backtracking/2_print_all_solution_in_N_queen_problem.cpp b/09_backtracking/2_print_all_solution_in_N_queen_problem.cpp new file mode 100644 index 0000000..07b5b4b --- /dev/null +++ b/09_backtracking/2_print_all_solution_in_N_queen_problem.cpp @@ -0,0 +1,258 @@ +/* + link: https://www.geeksforgeeks.org/printing-solutions-n-queen-problem/ + + video: https://youtu.be/i05Ju7AftcM +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N ^ 3) +*/ +bool isSafe(int col, int row, vector& board, int n) { + int tempRow = row; + int tempCol = col; + + // check upper diagonal + while (row >= 0 && col >= 0) { + if (board[row][col] == 'Q') return false; + row--; + col--; + } + + // check current row + row = tempRow; + col = tempCol; + while (col >= 0) { + if (board[row][col] == 'Q') return false; + col--; + } + + // check bottom diagonal + row = tempRow; + col = tempCol; + while (row < n && col >= 0) { + if (board[row][col] == 'Q') return false; + row++; + col--; + } + + return true; +} + +void solve(int col, vector& board, vector>& ans, int n) { + if (col == n) { + ans.push_back(board); + return; + } + + for (int row = 0;row < n;row++) { + if (isSafe(col, row, board, n)) { + board[row][col] = 'Q'; + solve(col + 1, board, ans, n); + board[row][col] = '.'; + } + } +} + + +vector> solveNQueens(int n) { + vector> ans; + vector board(n); + string s(n, '.'); + + for (int i = 0;i < n;i++) board[i] = s; + + solve(0, board, ans, n); + return ans; +} + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N ^ 2) + + check for left row: very simple by maintaining leftRow + check for upper diagonal: by maintaining upperDiagonal and store in it row+col + check for lower diagonal: by maintaining lowerDiagonal and store in it (n-1) + col-row + but to understand how come up with (n-1) + col-row plz proceed to the video +*/ +class Solution { + + public: + void solve(int col, vector& board, vector>& ans, + vector& leftRow, + vector& upperDiagonal, vector& lowerDiagonal, int n) + { + if (col == n) { + ans.push_back(board); + return; + } + + + for (int row = 0;row < n;row++) { + if (leftRow[row] == 0 && lowerDiagonal[row + col] == 0 + && upperDiagonal[n - 1 + col - row] == 0) { + + board[row][col] = 'Q'; + leftRow[row] = 1; + lowerDiagonal[row + col] = 1; + upperDiagonal[n - 1 + col - row] = 1; + solve(col + 1, board, ans, leftRow, upperDiagonal, lowerDiagonal, n); + + // again undoing it so that we can use that pos for different combination + board[row][col] = '.'; + leftRow[row] = 0; + lowerDiagonal[row + col] = 0; + upperDiagonal[n - 1 + col - row] = 0; + } + } + } + public: + vector> solveNQueens(int n) { + vector> ans; + vector board(n); + string s(n, '.'); + for (int i = 0;i < n;i++) { + board[i] = s; + } + vector leftRow(n, 0), upperDiagonal(2 * n - 1, 0), lowerDiagonal(2 * n - 1, 0); + solve(0, board, ans, leftRow, upperDiagonal, lowerDiagonal, n); + return ans; + } + +}; + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* */ +/* C/C++ program to solve N Queen Problem using +backtracking */ +#include +using namespace std; + +vector > result; + +/* A utility function to check if a queen can +be placed on board[row][col]. Note that this +function is called when "col" queens are +already placed in columns from 0 to col -1. +So we need to check only left side for +attacking queens */ +bool isSafe(vector > board, + int row, int col) +{ + int i, j; + int N = board.size(); + + /* Check this row on left side */ + for (i = 0; i < col; i++) + if (board[row][i]) + return false; + + /* Check upper diagonal on left side */ + for (i = row, j = col; i >= 0 && j >= 0; i--, j--) + if (board[i][j]) + return false; + + /* Check lower diagonal on left side */ + for (i = row, j = col; j >= 0 && i < N; i++, j--) + if (board[i][j]) + return false; + + return true; +} + +/* A recursive utility function to solve N +Queen problem */ +bool solveNQUtil(vector >& board, int col) +{ + /* base case: If all queens are placed + then return true */ + int N = board.size(); + if (col == N) { + vector v; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (board[i][j] == 1) + v.push_back(j + 1); + } + } + result.push_back(v); + return true; + } + + /* Consider this column and try placing + this queen in all rows one by one */ + bool res = false; + for (int i = 0; i < N; i++) { + /* Check if queen can be placed on + board[i][col] */ + if (isSafe(board, i, col)) { + /* Place this queen in board[i][col] */ + board[i][col] = 1; + + // Make result true if any placement + // is possible + res = solveNQUtil(board, col + 1) || res; + + /* If placing queen in board[i][col] + doesn't lead to a solution, then + remove queen from board[i][col] */ + board[i][col] = 0; // BACKTRACK + } + } + + /* If queen can not be place in any row in + this column col then return false */ + return res; +} + +/* This function solves the N Queen problem using +Backtracking. It mainly uses solveNQUtil() to +solve the problem. It returns false if queens +cannot be placed, otherwise return true and +prints placement of queens in the form of 1s. +Please note that there may be more than one +solutions, this function prints one of the +feasible solutions.*/ + +vector > nQueen(int n) +{ + result.clear(); + vector > board(n, vector(n, 0)); + + if (solveNQUtil(board, 0) == false) { + return {}; + } + + sort(result.begin(), result.end()); + return result; +} + +// Driver Code +int main() +{ + int n = 4; + vector > v = nQueen(n); + + for (auto ar : v) { + cout << "["; + for (auto it : ar) + cout << it << " "; + cout << "]"; + } + + return 0; +} diff --git a/09_backtracking/3_word_break_problem_using_backtracking.cpp b/09_backtracking/3_word_break_problem_using_backtracking.cpp new file mode 100644 index 0000000..e367585 --- /dev/null +++ b/09_backtracking/3_word_break_problem_using_backtracking.cpp @@ -0,0 +1,56 @@ +/* + link: https://practice.geeksforgeeks.org/problems/word-break-part-23249/1 + + video: https://youtu.be/LmHWIsBQBU4 + + sol (DP solution): https://www.geeksforgeeks.org/word-break-problem-dp-32-set-2/ +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N * N), one for to iterate the string and other to recursively perform again + SC: O(dict.size()) +*/ + +// to access dict. word in O(1) +unordered_set dict; +// to push the final ans. +vector allAns; + +void backtracking(string str, string ans) { + // it means we reach the end for the certain combination + if (str.size() == 0) { + // to remove the extra space at the end we did ans.size()-1 + allAns.push_back(ans.substr(0, ans.size() - 1)); + return; + } + + for (int i = 0;i < str.size();i++) { + // get left sub-string each time + string left = str.substr(0, i + 1); + + // if left sub-string is present + if (dict.find(left) != dict.end()) { + + // find the right sub-string and try it recursively to break; + string right = str.substr(i + 1); + backtracking(right, ans + left + " "); + } + } +} + +vector wordBreak(int n, vector& wordDict, string s) +{ + dict.clear(); + allAns.clear(); + + for (string curr : wordDict) dict.insert(curr); + + // trying out every break possible + backtracking(s, ""); + + return allAns; +} \ No newline at end of file diff --git a/09_backtracking/4_remove_invalid_paranthesis.cpp b/09_backtracking/4_remove_invalid_paranthesis.cpp new file mode 100644 index 0000000..3b217ae --- /dev/null +++ b/09_backtracking/4_remove_invalid_paranthesis.cpp @@ -0,0 +1,66 @@ +/* + link: https://leetcode.com/problems/remove-invalid-parentheses/ + + video (this code gives TLE so tweaked code is below): https://youtu.be/Cbbf5qe5stw +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// this function will return how many +int getMin(string s) { + stack st; + + for (char c : s) { + if (c == '(') st.push(c); + // we are using else if as to ignore letters + else if (c == ')') { + if (st.size() == 0) st.push(c); + else if (st.top() == ')') st.push(c); + else if (st.top() == '(') st.pop(); + } + } + return st.size(); +} + + +void backtracking(string s, int minRemAllowed, set& hs, unordered_set& vis) { + // track record of every string visited at every stack call + vis.insert(s); + + // if no more letters to remove + if (minRemAllowed == 0) { + // and our string is balanced then add to the set + if (getMin(s) == 0) { + hs.insert(s); + } + return; + } + + for (int i = 0; i < s.size(); i++) { + // get left ignoring the ith letter + string left = s.substr(0, i); + // get right ignoring the ith letter + string right = s.substr(i + 1); + + // if currently formed string is already visited then ignore the stack call + if (vis.find(left + right) != vis.end()) continue; + backtracking(left + right, minRemAllowed - 1, hs, vis); + } +} + + +vector removeInvalidParentheses(string s) { + // vs.clear(); + + int minRemoval = getMin(s); + set hs; + unordered_set vis; + + backtracking(s, minRemoval, hs, vis); + + // finally convert set to vector + vector vs(hs.begin(), hs.end()); + + return vs; +} \ No newline at end of file diff --git a/09_backtracking/5_sudoku_solver.cpp b/09_backtracking/5_sudoku_solver.cpp new file mode 100644 index 0000000..a2fa787 --- /dev/null +++ b/09_backtracking/5_sudoku_solver.cpp @@ -0,0 +1,70 @@ +/* + link: https://practice.geeksforgeeks.org/problems/solve-the-sudoku-1587115621/1 + + video: https://youtu.be/FWAIf_EVUKE + + (for more ref. or codes): https://www.geeksforgeeks.org/sudoku-backtracking-7/ +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(9^(n*n)) as every N*N place in box has 9 possibilities +*/ +bool isValid(int row, int col, int curr, int grid[N][N]) { + for (int i = 0; i < 9; i++) { + // checking in row + if (grid[i][col] == curr) return false; + + // checking in col + if (grid[row][i] == curr) return false; + + // checking in current block of sudoku + if (grid[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == curr) return false; + + } + return true; +} + +bool SolveSudoku(int grid[N][N]) +{ + // for every position + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + // if it is to fill then... + if (grid[i][j] == 0) { + // for every possible no. + for (int curr = 1; curr <= 9; curr++) { + // if current no. is valid to fill then we will go for the recursion (possibilities) + if (isValid(i, j, curr, grid)) { + // fill current pos + grid[i][j] = curr; + // recur for next empty pos + if (SolveSudoku(grid)) return true; + // if valid filled position didn't return true + // because other no. might not accomodate validly + // again empty the current pos + else grid[i][j] = 0; + } + } + // if not even single no. accomodated return false + return false; + } + } + } + // if sudoku size is 0x0 + return true; +} + +//Function to print grids of the Sudoku. +void printGrid(int grid[N][N]) +{ + // Your code here + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + cout << grid[i][j] << " "; + } + } +} \ No newline at end of file diff --git a/09_backtracking/6_M_coloring_problem.cpp b/09_backtracking/6_M_coloring_problem.cpp new file mode 100644 index 0000000..521cb02 --- /dev/null +++ b/09_backtracking/6_M_coloring_problem.cpp @@ -0,0 +1,195 @@ +/* + link: https://practice.geeksforgeeks.org/problems/m-coloring-problem-1587115620/1 + + video: https://youtu.be/wuVwUK25Rfc +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + alternative code +*/ +bool isSafe(int node, int color[], bool graph[101][101], int n, int col) { + for (int k = 0;k < n;k++) { + if (k != node && graph[k][node] == 1 && color[k] == col) { + return false; + } + } + return true; +} +bool solve(int node, int color[], int m, int N, bool graph[101][101]) { + if (node == N) { + return true; + } + + for (int i = 1;i <= m;i++) { + if (isSafe(node, color, graph, N, i)) { + color[node] = i; + if (solve(node + 1, color, m, N, graph)) return true; + color[node] = 0; + } + + } + return false; +} + +//Function to determine if graph can be coloured with at most M colours such +//that no two adjacent vertices of graph are coloured with same colour. +bool graphColoring(bool graph[101][101], int m, int N) +{ + int color[N] = { 0 }; + if (solve(0, color, m, N, graph)) return true; + return false; +} + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + Time Complexity: O(m^V). + There are total O(m^V) combination of colors. So time complexity is O(m^V). + The upperbound time complexity remains the same but the average time taken will be less. + + Space Complexity: O(V). + Recursive Stack of graphColoring(…) function will require O(V) space. +*/ +// C++ program for solution of M +// Coloring problem using backtracking +#include +using namespace std; + +// Number of vertices in the graph +#define V 4 + +void printSolution(int color[]); + +/* A utility function to check if +the current color assignment +is safe for vertex v i.e. checks +whether the edge exists or not +(i.e, graph[v][i]==1). If exist +then checks whether the color to +be filled in the new vertex(c is +sent in the parameter) is already +used by its adjacent +vertices(i-->adj vertices) or +not (i.e, color[i]==c) */ +bool isSafe(int v, bool graph[V][V], + int color[], int c) +{ + for (int i = 0; i < V; i++) + if (graph[v][i] && c == color[i]) + return false; + + return true; +} + +/* A recursive utility function +to solve m coloring problem */ +bool graphColoringUtil(bool graph[V][V], int m, + int color[], int v) +{ + + /* base case: If all vertices are + assigned a color then return true */ + if (v == V) + return true; + + /* Consider this vertex v and + try different colors */ + for (int c = 1; c <= m; c++) + { + + /* Check if assignment of color + c to v is fine*/ + if (isSafe(v, graph, color, c)) + { + color[v] = c; + + /* recur to assign colors to + rest of the vertices */ + if (graphColoringUtil( + graph, m, color, v + 1) == true) + return true; + + /* If assigning color c doesn't + lead to a solution then remove it */ + color[v] = 0; + } + } + + /* If no color can be assigned to + this vertex then return false */ + return false; +} + +/* This function solves the m Coloring +problem using Backtracking. It mainly +uses graphColoringUtil() to solve the +problem. It returns false if the m +colors cannot be assigned, otherwise +return true and prints assignments of +colors to all vertices. Please note +that there may be more than one solutions, +this function prints one of the +feasible solutions.*/ +bool graphColoring(bool graph[V][V], int m) +{ + + // Initialize all color values as 0. + // This initialization is needed + // correct functioning of isSafe() + int color[V]; + for (int i = 0; i < V; i++) + color[i] = 0; + + // Call graphColoringUtil() for vertex 0 + if (graphColoringUtil(graph, m, color, 0) == false) + { + cout << "Solution does not exist"; + return false; + } + + // Print the solution + printSolution(color); + return true; +} + +/* A utility function to print solution */ +void printSolution(int color[]) +{ + cout << "Solution Exists:" + << " Following are the assigned colors" + << "\n"; + for (int i = 0; i < V; i++) + cout << " " << color[i] << " "; + + cout << "\n"; +} + +// Driver code +int main() +{ + + /* Create following graph and test + whether it is 3 colorable + (3)---(2) + | / | + | / | + | / | + (0)---(1) + */ + bool graph[V][V] = { { 0, 1, 1, 1 }, + { 1, 0, 1, 0 }, + { 1, 1, 0, 1 }, + { 1, 0, 1, 0 }, }; + + // Number of colors + int m = 3; + graphColoring(graph, m); + return 0; +} diff --git a/09_backtracking/7_print_all_palindromic_partitions_of_string.cpp b/09_backtracking/7_print_all_palindromic_partitions_of_string.cpp new file mode 100644 index 0000000..377a433 --- /dev/null +++ b/09_backtracking/7_print_all_palindromic_partitions_of_string.cpp @@ -0,0 +1,90 @@ +/* + link: https://www.geeksforgeeks.org/given-a-string-print-all-possible-palindromic-partition/ + + video: https://youtu.be/WBgsABoClE0 +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +bool isPalindrome(string s, int start, int end) { + while (start <= end) { + if (s[start++] != s[end--]) return false; + } + return true; +} + +void recur(int index, string s, vector& path, vector>& res) { + if (index == s.size()) { + res.push_back(path); + return; + } + + for (int i = index, i < s.size(); i++) { + if (isPalindrome(s, index, i)) { + path.push_back(s.substr(index, i - index + 1)); + recur(i + 1, s, path, res); + path.pop_back(); + } + } +} + +vector> partition(string s) { + vector> res; + vector path; + recur(0, s, path, res); + return res; +} + + + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + another solution +*/ + +vector vs; + +// function to check palindrom +bool isPalindrome(string s) { + int n = s.size(); + for (int i = 0; i < n / 2; i++) { + if (s[i] != s[n - 1 - i]) return false; + } + return true; +} + +// recuring func. +void recur(string s, string ans) { + // if there is nothing left to check in string + if (s.size() == 0) { + // substr is used just to remove extra space at the end + // also push the ans string as it contains the all the palindromic substr + vs.push_back(ans.substr(0, ans.size() - 1)); + return; + } + + // checking for every partition in our current string + for (int i = 0; i < s.size(); i++) { + string left = s.substr(0, i + 1); + + // if left substring is palindromic then and only then + if (isPalindrome(left)) { + string right = s.substr(i + 1); + // pass the right substring in s and add left to the ans + recur(right, ans + left + " ") + } + } +} + +vector backtracking(string s) { + vs.clear(); + int n = s.size(); + + recur(s, ""); + return vs; +} \ No newline at end of file diff --git a/09_backtracking/8_subset_sum_problem.cpp b/09_backtracking/8_subset_sum_problem.cpp new file mode 100644 index 0000000..b1a7a93 --- /dev/null +++ b/09_backtracking/8_subset_sum_problem.cpp @@ -0,0 +1,77 @@ +/* + link: https://practice.geeksforgeeks.org/problems/subset-sum-problem2014/1 +*/ + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + TC: O(N) +*/ +bool solve(int idx, int sum, vector& ans, int arr[], int N) { + // if sum is already less than 0 or index is out of bound + if (sum < 0 || idx >= N) return false; + + // if we get perfect sum ==0 means we got the combination + if (sum == 0) return true; + + // if try to push current elem. + ans.push_back(arr[idx]); + + // if current element worked + if (solve(idx + 1, sum - arr[idx], ans, arr, N)) return true; + + // if curr ele didn't work pop it + ans.pop_back(); + + + // basically ignoring the current ele and going for other combination + return solve(idx + 1, sum, ans, arr, N); +} + +int equalPartition(int N, int arr[]) +{ + int sum = 0; + for (int i = 0; i < N; i++) { + sum += arr[i]; + } + + // just in case to get partition + vector ans; + + // if sum is odd it is not possible to separate no.(s) + // eg. sum = 11, now there exist no two such group whose individual total would be same and + // overall total will be 11 + return sum % 2 == 0 && solve(0, sum / 2, ans, arr, N); +} + + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +/* + alternate solution +*/ +bool solve(int arr[], int curr, int sum, int idx, int N) { + if (curr > sum || idx >= N) return false; + if (curr == sum) return true; + + // taking the current element + if (solve(arr, curr + arr[idx], sum, idx + 1, N)) return true; + + // ignoring the current element + if (solve(arr, curr, sum, idx + 1, N)) return true; + + return false; +} + +int equalPartition(int N, int arr[]) +{ + int sum = 0; + for (int i = 0; i < N; i++) { + sum += arr[i]; + } + + return sum % 2 == 0 && solve(arr, 0, sum / 2, 0, N); +} \ No newline at end of file diff --git a/09_backtracking/9_knights_tour_problem.cpp b/09_backtracking/9_knights_tour_problem.cpp new file mode 100644 index 0000000..adddde8 --- /dev/null +++ b/09_backtracking/9_knights_tour_problem.cpp @@ -0,0 +1,109 @@ +/* + link: https://www.geeksforgeeks.org/the-knights-tour-problem-backtracking-1/ +*/ + + + + +// ----------------------------------------------------------------------------------------------------------------------- // +// C++ program for Knight Tour problem +#include +using namespace std; + +#define N 8 + +int solveKTUtil(int x, int y, int movei, int sol[N][N], + int xMove[], int yMove[]); + +/* A utility function to check if i,j are +valid indexes for N*N chessboard */ +int isSafe(int x, int y, int sol[N][N]) +{ + return (x >= 0 && x < N&& y >= 0 && y < N + && sol[x][y] == -1); +} + +/* A utility function to print +solution matrix sol[N][N] */ +void printSolution(int sol[N][N]) +{ + for (int x = 0; x < N; x++) { + for (int y = 0; y < N; y++) + cout << " " << setw(2) << sol[x][y] << " "; + cout << endl; + } +} + +/* This function solves the Knight Tour problem using +Backtracking. This function mainly uses solveKTUtil() +to solve the problem. It returns false if no complete +tour is possible, otherwise return true and prints the +tour. +Please note that there may be more than one solutions, +this function prints one of the feasible solutions. */ +int solveKT() +{ + int sol[N][N]; + + /* Initialization of solution matrix */ + for (int x = 0; x < N; x++) + for (int y = 0; y < N; y++) + sol[x][y] = -1; + + /* xMove[] and yMove[] define next move of Knight. + xMove[] is for next value of x coordinate + yMove[] is for next value of y coordinate */ + int xMove[8] = { 2, 1, -1, -2, -2, -1, 1, 2 }; + int yMove[8] = { 1, 2, 2, 1, -1, -2, -2, -1 }; + + // Since the Knight is initially at the first block + sol[0][0] = 0; + + /* Start from 0,0 and explore all tours using + solveKTUtil() */ + if (solveKTUtil(0, 0, 1, sol, xMove, yMove) == 0) { + cout << "Solution does not exist"; + return 0; + } + else + printSolution(sol); + + return 1; +} + +/* A recursive utility function to solve Knight Tour +problem */ +int solveKTUtil(int x, int y, int movei, int sol[N][N], + int xMove[N], int yMove[N]) +{ + int k, next_x, next_y; + if (movei == N * N) + return 1; + + /* Try all next moves from + the current coordinate x, y */ + for (k = 0; k < 8; k++) { + next_x = x + xMove[k]; + next_y = y + yMove[k]; + if (isSafe(next_x, next_y, sol)) { + sol[next_x][next_y] = movei; + if (solveKTUtil(next_x, next_y, movei + 1, sol, + xMove, yMove) + == 1) + return 1; + else + + // backtracking + sol[next_x][next_y] = -1; + } + } + return 0; +} + +// Driver Code +int main() +{ + // Function Call + solveKT(); + return 0; +}