chore: import upstream snapshot with attribution
Awesome CI Workflow / Code Formatter (push) Waiting to run
Awesome CI Workflow / Compile checks (macOS-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (windows-latest) (push) Blocked by required conditions
Awesome CI Workflow / Code Formatter (push) Waiting to run
Awesome CI Workflow / Compile checks (macOS-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (windows-latest) (push) Blocked by required conditions
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [0-1 Knapsack Problem]
|
||||
* (https://en.wikipedia.org/wiki/Knapsack_problem)
|
||||
*
|
||||
* @details
|
||||
* Given weights and values of n items, put these items in a knapsack of
|
||||
* capacity `W` to get the maximum total value in the knapsack. In other words,
|
||||
* given two integer arrays `val[0..n-1]` and `wt[0..n-1]` which represent
|
||||
* values and weights associated with n items respectively. Also given an
|
||||
* integer W which represents knapsack capacity, find out the maximum value
|
||||
* subset of `val[]` such that sum of the weights of this subset is smaller than
|
||||
* or equal to W. You cannot break an item, either pick the complete item or
|
||||
* don’t pick it (0-1 property)
|
||||
*
|
||||
* ### Algorithm
|
||||
* The idea is to consider all subsets of items and calculate the total weight
|
||||
* and value of all subsets. Consider the only subsets whose total weight is
|
||||
* smaller than `W`. From all such subsets, pick the maximum value subset.
|
||||
*
|
||||
* @author [Anmol](https://github.com/Anmol3299)
|
||||
* @author [Pardeep](https://github.com/Pardeep009)
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace Knapsack
|
||||
* @brief Implementation of 0-1 Knapsack problem
|
||||
*/
|
||||
namespace knapsack {
|
||||
/**
|
||||
* @brief Picking up all those items whose combined weight is below
|
||||
* the given capacity and calculating the value of those picked items. Trying all
|
||||
* possible combinations will yield the maximum knapsack value.
|
||||
* @tparam n size of the weight and value array
|
||||
* @param capacity capacity of the carrying bag
|
||||
* @param weight array representing the weight of items
|
||||
* @param value array representing the value of items
|
||||
* @return maximum value obtainable with a given capacity.
|
||||
*/
|
||||
template <size_t n>
|
||||
int maxKnapsackValue(const int capacity, const std::array<int, n> &weight,
|
||||
const std::array<int, n> &value) {
|
||||
std::vector<std::vector<int> > maxValue(n + 1,
|
||||
std::vector<int>(capacity + 1, 0));
|
||||
// outer loop will select no of items allowed
|
||||
// inner loop will select the capacity of the knapsack bag
|
||||
int items = sizeof(weight) / sizeof(weight[0]);
|
||||
for (size_t i = 0; i < items + 1; ++i) {
|
||||
for (size_t j = 0; j < capacity + 1; ++j) {
|
||||
if (i == 0 || j == 0) {
|
||||
// if no of items is zero or capacity is zero, then maxValue
|
||||
// will be zero
|
||||
maxValue[i][j] = 0;
|
||||
} else if (weight[i - 1] <= j) {
|
||||
// if the ith item's weight(in the actual array it will be at i-1)
|
||||
// is less than or equal to the allowed weight i.e. j then we
|
||||
// can pick that item for our knapsack. maxValue will be the
|
||||
// obtained either by picking the current item or by not picking
|
||||
// current item
|
||||
|
||||
// picking the current item
|
||||
int profit1 = value[i - 1] + maxValue[i - 1][j - weight[i - 1]];
|
||||
|
||||
// not picking the current item
|
||||
int profit2 = maxValue[i - 1][j];
|
||||
|
||||
maxValue[i][j] = std::max(profit1, profit2);
|
||||
} else {
|
||||
// as the weight of the current item is greater than the allowed weight, so
|
||||
// maxProfit will be profit obtained by excluding the current item.
|
||||
maxValue[i][j] = maxValue[i - 1][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returning maximum value
|
||||
return maxValue[items][capacity];
|
||||
}
|
||||
} // namespace knapsack
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Function to test the above algorithm
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
const int n1 = 3; // number of items
|
||||
std::array<int, n1> weight1 = {10, 20, 30}; // weight of each item
|
||||
std::array<int, n1> value1 = {60, 100, 120}; // value of each item
|
||||
const int capacity1 = 50; // capacity of carrying bag
|
||||
const int max_value1 = dynamic_programming::knapsack::maxKnapsackValue(
|
||||
capacity1, weight1, value1);
|
||||
const int expected_max_value1 = 220;
|
||||
assert(max_value1 == expected_max_value1);
|
||||
std::cout << "Maximum Knapsack value with " << n1 << " items is "
|
||||
<< max_value1 << std::endl;
|
||||
|
||||
// Test 2
|
||||
const int n2 = 4; // number of items
|
||||
std::array<int, n2> weight2 = {24, 10, 10, 7}; // weight of each item
|
||||
std::array<int, n2> value2 = {24, 18, 18, 10}; // value of each item
|
||||
const int capacity2 = 25; // capacity of carrying bag
|
||||
const int max_value2 = dynamic_programming::knapsack::maxKnapsackValue(
|
||||
capacity2, weight2, value2);
|
||||
const int expected_max_value2 = 36;
|
||||
assert(max_value2 == expected_max_value2);
|
||||
std::cout << "Maximum Knapsack value with " << n2 << " items is "
|
||||
<< max_value2 << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/dynamic_programming")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of
|
||||
* [Abbrievation](https://www.hackerrank.com/challenges/abbr/problem)
|
||||
*
|
||||
* @details
|
||||
* Given two strings, `a` and `b`, determine if it's possible to make `a` equal
|
||||
* to `b` You can perform the following operations on the string `a`:
|
||||
* 1. Capitalize zero or more of `a`'s lowercase letters.
|
||||
* 2. Delete all of the remaining lowercase letters in `a`.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The idea is in the problem statement itself: iterate through characters of
|
||||
* string `a` and `b` (for character indexes `i` and `j` respectively):
|
||||
* 1. If `a[i]` and `b[j]` are equal, then move to next position
|
||||
* 2. If `a[i]` is lowercase of `b[j]`, then explore two possibilities:
|
||||
* a. Capitalize `a[i]` or
|
||||
* b. Skip `a[i]`
|
||||
* 3. If the `a[i]` is not uppercase, just discard that character, else return
|
||||
* `false`
|
||||
*
|
||||
* Time Complexity: (O(|a|*|b|)) where `|a|` => length of string `a`
|
||||
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for `assert`
|
||||
#include <cstdint> /// for `std::uint32_t`
|
||||
#include <iostream> /// for IO operations
|
||||
#include <string> /// for `std::string` library
|
||||
#include <vector> /// for `std::vector` STL library
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming Algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace abbreviation
|
||||
* @brief Functions for
|
||||
* [Abbreviation](https://www.hackerrank.com/challenges/abbr/problem)
|
||||
* implementation
|
||||
*/
|
||||
namespace abbreviation {
|
||||
/**
|
||||
* @brief
|
||||
* Recursive Dynamic Programming function
|
||||
* @details
|
||||
* Returns whether `s` can be converted to `t` with following rules:
|
||||
* a. Capitalize zero or more of a's lowercase letters from string `s`
|
||||
* b. remove all other lowercase letters from string `s`
|
||||
* @param memo To store the result
|
||||
* @param visited boolean to check if the result is already computed
|
||||
* @param str given string, which might not be abbreivated
|
||||
* @param result resultant abbreivated string
|
||||
* @param str_idx index for string `str`, helpful for transitions
|
||||
* @param result_idx index for string `result`, helpful for transitions
|
||||
* @returns `false` if string `str` cannot be converted to `result`
|
||||
* @returns `true` if string `str` can be converted to `result`
|
||||
*/
|
||||
bool abbreviation_recursion(std::vector<std::vector<bool>> *memo,
|
||||
std::vector<std::vector<bool>> *visited,
|
||||
const std::string &str, const std::string &result,
|
||||
uint32_t str_idx = 0, uint32_t result_idx = 0) {
|
||||
bool ans = memo->at(str_idx).at(result_idx);
|
||||
if (str_idx == str.size() && result_idx == result.size()) {
|
||||
return true;
|
||||
} else if (str_idx == str.size() && result_idx != result.size()) {
|
||||
// result `t` is not converted, return false
|
||||
return false;
|
||||
} else if (!visited->at(str_idx).at(result_idx)) {
|
||||
/**
|
||||
* `(str[i] == result[j])`: if str char at position i is equal to
|
||||
* `result` char at position j, then s character is a capitalized one,
|
||||
* move on to next character `str[i] - 32 == result[j]`:
|
||||
* if `str[i]` character is lowercase of `result[j]` then explore two
|
||||
* possibilites:
|
||||
* 1. convert it to capitalized letter and move both to next pointer
|
||||
* `(i + 1, j + 1)`
|
||||
* 2. Discard the character `(str[i])` and move to next char `(i + 1,
|
||||
* j)`
|
||||
*/
|
||||
if (str[str_idx] == result[result_idx]) {
|
||||
ans = abbreviation_recursion(memo, visited, str, result,
|
||||
str_idx + 1, result_idx + 1);
|
||||
} else if (str[str_idx] - 32 == result[result_idx]) {
|
||||
ans = abbreviation_recursion(memo, visited, str, result,
|
||||
str_idx + 1, result_idx + 1) ||
|
||||
abbreviation_recursion(memo, visited, str, result,
|
||||
str_idx + 1, result_idx);
|
||||
} else {
|
||||
// if `str[i]` is uppercase, then cannot be converted, return
|
||||
// `false`
|
||||
// else `str[i]` is lowercase, only option is to discard this
|
||||
// character
|
||||
if (str[str_idx] >= 'A' && str[str_idx] <= 'Z') {
|
||||
ans = false;
|
||||
} else {
|
||||
ans = abbreviation_recursion(memo, visited, str, result,
|
||||
str_idx + 1, result_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
(*memo)[str_idx][result_idx] = ans;
|
||||
(*visited)[str_idx][result_idx] = true;
|
||||
return (*memo)[str_idx][result_idx];
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
* Iterative Dynamic Programming function
|
||||
* @details
|
||||
* Returns whether `s` can be converted to `t` with following rules:
|
||||
* a. Capitalize zero or more of s's lowercase letters from string `s`
|
||||
* b. remove all other lowercase letters from string `s`
|
||||
* Note: The transition states for iterative is similar to recursive as well
|
||||
* @param str given string, which might not be abbreivated
|
||||
* @param result resultant abbreivated string
|
||||
* @returns `false` if string `str` cannot be converted to `result`
|
||||
* @returns `true` if string `str` can be converted to `result`
|
||||
*/
|
||||
bool abbreviation(const std::string &str, const std::string &result) {
|
||||
std::vector<std::vector<bool>> memo(
|
||||
str.size() + 1, std::vector<bool>(result.size() + 1, false));
|
||||
|
||||
for (uint32_t i = 0; i <= str.size(); ++i) {
|
||||
memo[i][0] = true;
|
||||
}
|
||||
for (uint32_t i = 1; i <= result.size(); ++i) {
|
||||
memo[0][i] = false;
|
||||
}
|
||||
for (uint32_t i = 1; i <= str.size(); ++i) {
|
||||
for (uint32_t j = 1; j <= result.size(); ++j) {
|
||||
if (str[i - 1] == result[j - 1]) {
|
||||
memo[i][j] = memo[i - 1][j - 1];
|
||||
} else if (str[i - 1] - 32 == result[j - 1]) {
|
||||
memo[i][j] = (memo[i - 1][j - 1] || memo[i - 1][j]);
|
||||
} else {
|
||||
if (str[i - 1] >= 'A' && str[i - 1] <= 'Z') {
|
||||
memo[i][j] = false;
|
||||
} else {
|
||||
memo[i][j] = memo[i - 1][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return memo.back().back();
|
||||
}
|
||||
} // namespace abbreviation
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self test-implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::string s = "daBcd", t = "ABC";
|
||||
std::vector<std::vector<bool>> memo(s.size() + 1,
|
||||
std::vector<bool>(t.size() + 1, false)),
|
||||
visited(s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
||||
|
||||
assert(dynamic_programming::abbreviation::abbreviation_recursion(
|
||||
&memo, &visited, s, t) == true);
|
||||
assert(dynamic_programming::abbreviation::abbreviation(s, t) == true);
|
||||
s = "XXVVnDEFYgYeMXzWINQYHAQKKOZEYgSRCzLZAmUYGUGILjMDET";
|
||||
t = "XXVVDEFYYMXWINQYHAQKKOZEYSRCLZAUYGUGILMDETQVWU";
|
||||
memo = std::vector<std::vector<bool>>(
|
||||
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
||||
|
||||
visited = std::vector<std::vector<bool>>(
|
||||
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
||||
|
||||
assert(dynamic_programming::abbreviation::abbreviation_recursion(
|
||||
&memo, &visited, s, t) == false);
|
||||
assert(dynamic_programming::abbreviation::abbreviation(s, t) == false);
|
||||
|
||||
s = "DRFNLZZVHLPZWIupjwdmqafmgkg";
|
||||
t = "DRFNLZZVHLPZWI";
|
||||
|
||||
memo = std::vector<std::vector<bool>>(
|
||||
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
||||
|
||||
visited = std::vector<std::vector<bool>>(
|
||||
s.size() + 1, std::vector<bool>(t.size() + 1, false));
|
||||
|
||||
assert(dynamic_programming::abbreviation::abbreviation_recursion(
|
||||
&memo, &visited, s, t) == true);
|
||||
assert(dynamic_programming::abbreviation::abbreviation(s, t) == true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Checks whether a number is an [Armstrong
|
||||
* Number](https://en.wikipedia.org/wiki/Narcissistic_number) or not.
|
||||
*
|
||||
* @details
|
||||
* An Armstrong number is a number that is the sum of its own digits each raised
|
||||
* to the power of the number of digits. For example: 153 is an Armstrong number
|
||||
* since 153 = 1^3 + 5^3 + 3^3.
|
||||
*
|
||||
* A few examples of valid armstrong numbers:
|
||||
* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748,
|
||||
* 92727, 93084.
|
||||
*
|
||||
* Armstrong numbers are also known as Narcissistic Numbers, as stated in
|
||||
* Wikipedia.
|
||||
*
|
||||
* @author [Shivam Singhal](https://github.com/shivhek25)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cmath> /// for std::pow
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @brief Checks if the given number is armstrong or not.
|
||||
* @param number the number to check
|
||||
* @returns false if the given number is NOT armstrong
|
||||
* @returns true if the given number IS armstrong
|
||||
*/
|
||||
template <typename T>
|
||||
bool is_armstrong(const T &number) {
|
||||
int count = 0, temp = number, result = 0, rem = 0;
|
||||
|
||||
// Count the number of digits of the given number.
|
||||
// For example: 153 would be 3 digits.
|
||||
while (temp != 0) {
|
||||
temp /= 10;
|
||||
count++;
|
||||
}
|
||||
|
||||
// Calculation for checking of armstrongs number i.e.
|
||||
// in an n-digit number sum of the digits is raised to a power of `n` is
|
||||
// equal to the original number.
|
||||
temp = number;
|
||||
while (temp != 0) {
|
||||
rem = temp % 10;
|
||||
result += static_cast<T>(std::pow(rem, count));
|
||||
temp /= 10;
|
||||
}
|
||||
|
||||
if (result == number) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void tests() {
|
||||
assert(dynamic_programming::is_armstrong(153) == true);
|
||||
assert(dynamic_programming::is_armstrong(1) == true);
|
||||
assert(dynamic_programming::is_armstrong(0) == true);
|
||||
assert(dynamic_programming::is_armstrong(370) == true);
|
||||
assert(dynamic_programming::is_armstrong(1634) == true);
|
||||
assert(dynamic_programming::is_armstrong(580) == false);
|
||||
assert(dynamic_programming::is_armstrong(15) == false);
|
||||
assert(dynamic_programming::is_armstrong(1024) == false);
|
||||
assert(dynamic_programming::is_armstrong(989) == false);
|
||||
assert(dynamic_programming::is_armstrong(103) == false);
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Wrapper class for storing an edge
|
||||
class Edge {
|
||||
public:
|
||||
int src, dst, weight;
|
||||
};
|
||||
|
||||
// Wrapper class for storing a graph
|
||||
class Graph {
|
||||
public:
|
||||
int vertexNum, edgeNum;
|
||||
std::vector<Edge> edges;
|
||||
|
||||
// Constructs a graph with V vertices and E edges
|
||||
Graph(int V, int E) {
|
||||
this->vertexNum = V;
|
||||
this->edgeNum = E;
|
||||
this->edges.reserve(E);
|
||||
}
|
||||
|
||||
// Adds the given edge to the graph
|
||||
void addEdge(int src, int dst, int weight) {
|
||||
static int edgeInd = 0;
|
||||
if (edgeInd < this->edgeNum) {
|
||||
Edge newEdge;
|
||||
newEdge.src = src;
|
||||
newEdge.dst = dst;
|
||||
newEdge.weight = weight;
|
||||
this->edges[edgeInd++] = newEdge;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Utility function to print distances
|
||||
void print(const std::vector<int>& dist, int V) {
|
||||
cout << "\nVertex Distance" << endl;
|
||||
for (int i = 0; i < V; i++) {
|
||||
if (dist[i] != INT_MAX)
|
||||
cout << i << "\t" << dist[i] << endl;
|
||||
else
|
||||
cout << i << "\tINF" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// The main function that finds the shortest path from given source
|
||||
// to all other vertices using Bellman-Ford.It also detects negative
|
||||
// weight cycle
|
||||
void BellmanFord(Graph graph, int src) {
|
||||
int V = graph.vertexNum;
|
||||
int E = graph.edgeNum;
|
||||
std::vector<int> dist;
|
||||
dist.reserve(E);
|
||||
|
||||
// Initialize distances array as INF for all except source
|
||||
// Intialize source as zero
|
||||
for (int i = 0; i < V; i++) dist[i] = INT_MAX;
|
||||
dist[src] = 0;
|
||||
|
||||
// Calculate shortest path distance from source to all edges
|
||||
// A path can contain maximum (|V|-1) edges
|
||||
for (int i = 0; i <= V - 1; i++)
|
||||
for (int j = 0; j < E; j++) {
|
||||
int u = graph.edges[j].src;
|
||||
int v = graph.edges[j].dst;
|
||||
int w = graph.edges[j].weight;
|
||||
|
||||
if (dist[u] != INT_MAX && dist[u] + w < dist[v])
|
||||
dist[v] = dist[u] + w;
|
||||
}
|
||||
|
||||
// Iterate inner loop once more to check for negative cycle
|
||||
for (int j = 0; j < E; j++) {
|
||||
int u = graph.edges[j].src;
|
||||
int v = graph.edges[j].dst;
|
||||
int w = graph.edges[j].weight;
|
||||
|
||||
if (dist[u] != INT_MAX && dist[u] + w < dist[v]) {
|
||||
cout << "Graph contains negative weight cycle. Hence, shortest "
|
||||
"distance not guaranteed."
|
||||
<< endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
print(dist, V);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Driver Function
|
||||
int main() {
|
||||
int V, E, gsrc;
|
||||
int src, dst, weight;
|
||||
cout << "Enter number of vertices: ";
|
||||
cin >> V;
|
||||
cout << "Enter number of edges: ";
|
||||
cin >> E;
|
||||
Graph G(V, E);
|
||||
for (int i = 0; i < E; i++) {
|
||||
cout << "\nEdge " << i + 1 << "\nEnter source: ";
|
||||
cin >> src;
|
||||
cout << "Enter destination: ";
|
||||
cin >> dst;
|
||||
cout << "Enter weight: ";
|
||||
cin >> weight;
|
||||
G.addEdge(src, dst, weight);
|
||||
}
|
||||
cout << "\nEnter source: ";
|
||||
cin >> gsrc;
|
||||
BellmanFord(G, gsrc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Provides utilities to compute Catalan numbers using dynamic
|
||||
programming.
|
||||
* A Catalan numbers satisfy these recurrence relations:
|
||||
* C(0) = C(1) = 1; C(n) = sum(C(i).C(n-i-1)), for i = 0 to n-1
|
||||
* Read more about Catalan numbers here:
|
||||
https://en.wikipedia.org/wiki/Catalan_number
|
||||
https://oeis.org/A000108/
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for std::uint64_t
|
||||
#include <cstdlib> /// for std::size_t
|
||||
#include <functional> /// for std::plus & std::multiplies
|
||||
#include <numeric> /// for std::transform_reduce
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @brief computes and caches Catalan numbers
|
||||
*/
|
||||
class catalan_numbers {
|
||||
using value_type = std::uint64_t;
|
||||
std::vector<value_type> known{1, 1};
|
||||
|
||||
value_type compute_next() {
|
||||
return std::transform_reduce(known.begin(), known.end(), known.rbegin(),
|
||||
static_cast<value_type>(0), std::plus<>(),
|
||||
std::multiplies<>());
|
||||
}
|
||||
|
||||
void add() { known.push_back(this->compute_next()); }
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief computes the n-th Catalan number and updates the cache.
|
||||
* @return the n-th Catalan number
|
||||
*/
|
||||
value_type get(std::size_t n) {
|
||||
while (known.size() <= n) {
|
||||
this->add();
|
||||
}
|
||||
return known[n];
|
||||
}
|
||||
};
|
||||
|
||||
void test_catalan_numbers_up_to_20() {
|
||||
// data verified with https://oeis.org/A000108/
|
||||
catalan_numbers cn;
|
||||
assert(cn.get(0) == 1ULL);
|
||||
assert(cn.get(1) == 1ULL);
|
||||
assert(cn.get(2) == 2ULL);
|
||||
assert(cn.get(3) == 5ULL);
|
||||
assert(cn.get(4) == 14ULL);
|
||||
assert(cn.get(5) == 42ULL);
|
||||
assert(cn.get(6) == 132ULL);
|
||||
assert(cn.get(7) == 429ULL);
|
||||
assert(cn.get(8) == 1430ULL);
|
||||
assert(cn.get(9) == 4862ULL);
|
||||
assert(cn.get(10) == 16796ULL);
|
||||
assert(cn.get(11) == 58786ULL);
|
||||
assert(cn.get(12) == 208012ULL);
|
||||
assert(cn.get(13) == 742900ULL);
|
||||
assert(cn.get(14) == 2674440ULL);
|
||||
assert(cn.get(15) == 9694845ULL);
|
||||
assert(cn.get(16) == 35357670ULL);
|
||||
assert(cn.get(17) == 129644790ULL);
|
||||
assert(cn.get(18) == 477638700ULL);
|
||||
assert(cn.get(19) == 1767263190ULL);
|
||||
assert(cn.get(20) == 6564120420ULL);
|
||||
}
|
||||
|
||||
void test_catalan_numbers_25() {
|
||||
// data verified with https://oeis.org/A000108/
|
||||
catalan_numbers cn;
|
||||
assert(cn.get(25) == 4861946401452ULL);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_catalan_numbers_up_to_20();
|
||||
test_catalan_numbers_25();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
// Function to find the Minimum number of coins required to get Sum S
|
||||
int findMinCoins(int arr[], int n, int N) {
|
||||
// dp[i] = no of coins required to get a total of i
|
||||
std::vector<int> dp(N + 1);
|
||||
|
||||
// 0 coins are needed for 0 sum
|
||||
|
||||
dp[0] = 0;
|
||||
|
||||
for (int i = 1; i <= N; i++) {
|
||||
// initialize minimum number of coins needed to infinity
|
||||
dp[i] = INT_MAX;
|
||||
int res = INT_MAX;
|
||||
|
||||
// do for each coin
|
||||
for (int c = 0; c < n; c++) {
|
||||
if (i - arr[c] >=
|
||||
0) // check if coins doesn't become negative by including it
|
||||
res = dp[i - arr[c]];
|
||||
|
||||
// if total can be reached by including current coin c,
|
||||
// update minimum number of coins needed dp[i]
|
||||
if (res != INT_MAX)
|
||||
dp[i] = min(dp[i], res + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// The Minimum No of Coins Required for N = dp[N]
|
||||
return dp[N];
|
||||
}
|
||||
|
||||
int main() {
|
||||
// No of Coins We Have
|
||||
int arr[] = {1, 2, 3, 4};
|
||||
int n = sizeof(arr) / sizeof(arr[0]);
|
||||
|
||||
// Total Change Required
|
||||
int N = 15;
|
||||
|
||||
cout << "Minimum Number of Coins Required " << findMinCoins(arr, n, N)
|
||||
<< "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Minimum coins](https://leetcode.com/problems/coin-change/) change
|
||||
* problem is a problem used to find the minimum number of coins required to
|
||||
* completely reach a target amount.
|
||||
*
|
||||
* @details
|
||||
* This problem can be solved using 2 methods:
|
||||
* 1. Top down approach
|
||||
* 2. Bottom up appraoch
|
||||
* Top down approach involves a vector with all elements initialised to 0.
|
||||
* It is based on optimal substructure and overlapping subproblems.
|
||||
* Overall time complexity of coin change problem is O(n*t)
|
||||
* For example: example 1:-
|
||||
* Coins: {1,7,10}
|
||||
* Target:15
|
||||
* Therfore minimum number of coins required = 3 of denomination 1,7 and 7.
|
||||
* @author [Divyansh Kushwaha](https://github.com/webdesignbydivyansh)
|
||||
*/
|
||||
|
||||
#include <cassert> // for assert
|
||||
#include <climits> // for INT_MAX
|
||||
#include <iostream> // for io operations
|
||||
#include <vector> // for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithm
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace mincoins_topdown
|
||||
* @brief Functions for [minimum coin
|
||||
* exchange](https://leetcode.com/problems/coin-change/) problem
|
||||
*/
|
||||
namespace mincoins_topdown {
|
||||
/**
|
||||
* @brief This implementation is for finding minimum number of coins .
|
||||
* @param T template-type to use any kind of value
|
||||
* @param n amount to be reached
|
||||
* @param coins vector of coins
|
||||
* @param t deontes the number of coins
|
||||
* @param dp initilised to 0
|
||||
* @returns minimum number of coins
|
||||
*/
|
||||
template <typename T>
|
||||
int64_t mincoins(const T &n, const std::vector<T> &coins, const int16_t &t,
|
||||
std::vector<T> dp) {
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (dp[n] != 0) {
|
||||
return dp[n];
|
||||
}
|
||||
int ans = INT_MAX; // variable to store min coins
|
||||
for (int i = 0; i < t; i++) {
|
||||
if (n - coins[i] >= 0) { // if after subtracting the current
|
||||
// denomination is it greater than 0 or not
|
||||
int sub = mincoins(n - coins[i], coins, t, dp);
|
||||
ans = std::min(ans, sub + 1);
|
||||
}
|
||||
}
|
||||
dp[n] = ans;
|
||||
return dp[n]; // returns minimum number of coins
|
||||
}
|
||||
|
||||
} // namespace mincoins_topdown
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// example 1: number of coins=3 and minimum coins required=3(7,7,1)
|
||||
const int64_t n1 = 15;
|
||||
const int8_t t1 = 3, a1 = 0;
|
||||
std::cout << "\nTest 1...";
|
||||
std::vector<int64_t> arr1{1, 7, 10};
|
||||
std::vector<int64_t> dp1(n1 + 1);
|
||||
fill(dp1.begin(), dp1.end(), a1);
|
||||
assert(dynamic_programming::mincoins_topdown::mincoins(n1, arr1, t1, dp1) ==
|
||||
3);
|
||||
std::cout << "Passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the test
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of cutting a rod problem
|
||||
*
|
||||
* @details
|
||||
* Given a rod of length n inches and an array of prices that
|
||||
* contains prices of all pieces of size<=n. Determine
|
||||
* the maximum profit obtainable by cutting up the rod and selling
|
||||
* the pieces.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The idea is to break the given rod into every smaller piece as possible
|
||||
* and then check profit for each piece, by calculating maximum profit for
|
||||
* smaller pieces we will build the solution for larger pieces in bottom-up
|
||||
* manner.
|
||||
*
|
||||
* @author [Anmol](https://github.com/Anmol3299)
|
||||
* @author [Pardeep](https://github.com/Pardeep009)
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace cut_rod
|
||||
* @brief Implementation of cutting a rod problem
|
||||
*/
|
||||
namespace cut_rod {
|
||||
/**
|
||||
* @brief Cuts the rod in different pieces and
|
||||
* stores the maximum profit for each piece of the rod.
|
||||
* @tparam T size of the price array
|
||||
* @param n size of the rod in inches
|
||||
* @param price an array of prices that contains prices of all pieces of size<=n
|
||||
* @return maximum profit obtainable for @param n inch rod.
|
||||
*/
|
||||
template <size_t T>
|
||||
int maxProfitByCuttingRod(const std::array<int, T> &price, const uint64_t &n) {
|
||||
int *profit =
|
||||
new int[n + 1]; // profit[i] will hold maximum profit for i inch rod
|
||||
|
||||
profit[0] = 0; // if length of rod is zero, then no profit
|
||||
|
||||
// outer loop will select size of rod, starting from 1 inch to n inch rod.
|
||||
// inner loop will evaluate the maximum profit we can get for i inch rod by
|
||||
// making every possible cut on it and will store it in profit[i].
|
||||
for (size_t i = 1; i <= n; i++) {
|
||||
int q = INT_MIN;
|
||||
for (size_t j = 1; j <= i; j++) {
|
||||
q = std::max(q, price[j - 1] + profit[i - j]);
|
||||
}
|
||||
profit[i] = q;
|
||||
}
|
||||
const int16_t ans = profit[n];
|
||||
delete[] profit;
|
||||
return ans; // returning maximum profit
|
||||
}
|
||||
} // namespace cut_rod
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Function to test above algorithm
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
const int16_t n1 = 8; // size of rod
|
||||
std::array<int32_t, n1> price1 = {1, 2, 4, 6, 8, 45, 21, 9}; // price array
|
||||
const int64_t max_profit1 =
|
||||
dynamic_programming::cut_rod::maxProfitByCuttingRod(price1, n1);
|
||||
const int64_t expected_max_profit1 = 47;
|
||||
assert(max_profit1 == expected_max_profit1);
|
||||
std::cout << "Maximum profit with " << n1 << " inch road is " << max_profit1
|
||||
<< std::endl;
|
||||
|
||||
// Test 2
|
||||
const int16_t n2 = 30; // size of rod
|
||||
std::array<int32_t, n2> price2 = {
|
||||
1, 5, 8, 9, 10, 17, 17, 20, 24, 30, // price array
|
||||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50};
|
||||
|
||||
const int64_t max_profit2 =
|
||||
dynamic_programming::cut_rod::maxProfitByCuttingRod(price2, n2);
|
||||
const int32_t expected_max_profit2 = 90;
|
||||
assert(max_profit2 == expected_max_profit2);
|
||||
std::cout << "Maximum profit with " << n2 << " inch road is " << max_profit2
|
||||
<< std::endl;
|
||||
// Test 3
|
||||
const int16_t n3 = 5; // size of rod
|
||||
std::array<int32_t, n3> price3 = {2, 9, 17, 23, 45}; // price array
|
||||
const int64_t max_profit3 =
|
||||
dynamic_programming::cut_rod::maxProfitByCuttingRod(price3, n3);
|
||||
const int64_t expected_max_profit3 = 45;
|
||||
assert(max_profit3 == expected_max_profit3);
|
||||
std::cout << "Maximum profit with " << n3 << " inch road is " << max_profit3
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Given two strings str1 & str2
|
||||
* and below operations that can
|
||||
* be performed on str1. Find
|
||||
* minimum number of edits
|
||||
* (operations) required to convert
|
||||
* 'str1' into 'str2'/
|
||||
* a. Insert
|
||||
* b. Remove
|
||||
* c. Replace
|
||||
* All of the above operations are
|
||||
* of equal cost
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
int min(int x, int y, int z) { return min(min(x, y), z); }
|
||||
|
||||
/* A Naive recursive C++ program to find
|
||||
* minimum number of operations to convert
|
||||
* str1 to str2.
|
||||
* O(3^m)
|
||||
*/
|
||||
int editDist(string str1, string str2, int m, int n) {
|
||||
if (m == 0)
|
||||
return n;
|
||||
if (n == 0)
|
||||
return m;
|
||||
|
||||
// If last characters are same then continue
|
||||
// for the rest of them.
|
||||
if (str1[m - 1] == str2[n - 1])
|
||||
return editDist(str1, str2, m - 1, n - 1);
|
||||
|
||||
// If last not same, then 3 possibilities
|
||||
// a.Insert b.Remove c. Replace
|
||||
// Get min of three and continue for rest.
|
||||
return 1 + min(editDist(str1, str2, m, n - 1),
|
||||
editDist(str1, str2, m - 1, n),
|
||||
editDist(str1, str2, m - 1, n - 1));
|
||||
}
|
||||
|
||||
/* A DP based program
|
||||
* O(m x n)
|
||||
*/
|
||||
int editDistDP(string str1, string str2, int m, int n) {
|
||||
// Create Table for SubProblems
|
||||
std::vector<std::vector<int> > dp(m + 1, std::vector<int>(n + 1));
|
||||
|
||||
// Fill d[][] in bottom up manner
|
||||
for (int i = 0; i <= m; i++) {
|
||||
for (int j = 0; j <= n; j++) {
|
||||
// If str1 empty. Then add all of str2
|
||||
if (i == 0)
|
||||
dp[i][j] = j;
|
||||
|
||||
// If str2 empty. Then add all of str1
|
||||
else if (j == 0)
|
||||
dp[i][j] = i;
|
||||
|
||||
// If character same. Recur for remaining
|
||||
else if (str1[i - 1] == str2[j - 1])
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
|
||||
else
|
||||
dp[i][j] = 1 + min(dp[i][j - 1], // Insert
|
||||
dp[i - 1][j], // Remove
|
||||
dp[i - 1][j - 1] // Replace
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return dp[m][n];
|
||||
}
|
||||
|
||||
int main() {
|
||||
string str1 = "sunday";
|
||||
string str2 = "saturday";
|
||||
|
||||
cout << editDist(str1, str2, str1.length(), str2.length()) << endl;
|
||||
cout << editDistDP(str1, str2, str1.length(), str2.length()) << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Function to get minimun number of trials needed
|
||||
* in worst case with n eggs and k floors
|
||||
*/
|
||||
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int eggDrop(int n, int k) {
|
||||
std::vector<std::vector<int> > eggFloor(n + 1, std::vector<int>(k + 1));
|
||||
|
||||
int result;
|
||||
|
||||
for (int i = 1; i <= n; i++) {
|
||||
eggFloor[i][1] = 1; // n eggs..1 Floor
|
||||
eggFloor[i][0] = 0; // n eggs..0 Floor
|
||||
}
|
||||
|
||||
// Only one egg available
|
||||
for (int j = 1; j <= k; j++) {
|
||||
eggFloor[1][j] = j;
|
||||
}
|
||||
|
||||
for (int i = 2; i <= n; i++) {
|
||||
for (int j = 2; j <= k; j++) {
|
||||
eggFloor[i][j] = INT_MAX;
|
||||
for (int x = 1; x <= j; x++) {
|
||||
// 1+max(eggBreak[one less egg, lower floors],
|
||||
// eggDoesntBreak[same # of eggs, upper floors]);
|
||||
result = 1 + max(eggFloor[i - 1][x - 1], eggFloor[i][j - x]);
|
||||
if (result < eggFloor[i][j])
|
||||
eggFloor[i][j] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return eggFloor[n][k];
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n, k;
|
||||
cout << "Enter number of eggs and floors: ";
|
||||
cin >> n >> k;
|
||||
cout << "Minimum number of trials in worst case: " << eggDrop(n, k) << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
int fib(int n) {
|
||||
int res[3];
|
||||
res[0] = 0;
|
||||
res[1] = 1;
|
||||
for (int i = 2; i <= n; i++) {
|
||||
res[2] = res[1] + res[0];
|
||||
res[0] = res[1];
|
||||
res[1] = res[2];
|
||||
}
|
||||
return res[1];
|
||||
}
|
||||
int main() {
|
||||
int n;
|
||||
cout << "Enter n: ";
|
||||
cin >> n;
|
||||
cout << "Fibonacci number is ";
|
||||
cout << fib(n) << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
// Wrapper class for storing a graph
|
||||
class Graph {
|
||||
public:
|
||||
int vertexNum;
|
||||
int **edges;
|
||||
|
||||
// Constructs a graph with V vertices and E edges
|
||||
Graph(int V) {
|
||||
this->vertexNum = V;
|
||||
this->edges = new int *[V];
|
||||
for (int i = 0; i < V; i++) {
|
||||
this->edges[i] = new int[V];
|
||||
for (int j = 0; j < V; j++) this->edges[i][j] = INT_MAX;
|
||||
this->edges[i][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~Graph() {
|
||||
for (int i = 0; i < vertexNum; i++) {
|
||||
delete[] edges[i];
|
||||
}
|
||||
delete[] edges;
|
||||
}
|
||||
|
||||
// Adds the given edge to the graph
|
||||
void addEdge(int src, int dst, int weight) {
|
||||
this->edges[src][dst] = weight;
|
||||
}
|
||||
};
|
||||
|
||||
// Utility function to print distances
|
||||
void print(const std::vector<int>& dist, int V) {
|
||||
cout << "\nThe Distance matrix for Floyd - Warshall" << endl;
|
||||
for (int i = 0; i < V; i++) {
|
||||
for (int j = 0; j < V; j++) {
|
||||
if (dist[i * V + j] != INT_MAX)
|
||||
cout << dist[i * V + j] << "\t";
|
||||
else
|
||||
cout << "INF"
|
||||
<< "\t";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// The main function that finds the shortest path from a vertex
|
||||
// to all other vertices using Floyd-Warshall Algorithm.
|
||||
void FloydWarshall(Graph graph) {
|
||||
std::size_t V = graph.vertexNum;
|
||||
std::vector<std::vector<int> > dist(V, std::vector<int>(V));
|
||||
|
||||
// Initialise distance array
|
||||
for (int i = 0; i < V; i++)
|
||||
for (int j = 0; j < V; j++) dist[i][j] = graph.edges[i][j];
|
||||
|
||||
// Calculate distances
|
||||
for (int k = 0; k < V; k++)
|
||||
// Choose an intermediate vertex
|
||||
|
||||
for (int i = 0; i < V; i++)
|
||||
// Choose a source vertex for given intermediate
|
||||
|
||||
for (int j = 0; j < V; j++)
|
||||
// Choose a destination vertex for above source vertex
|
||||
|
||||
if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX &&
|
||||
dist[i][k] + dist[k][j] < dist[i][j])
|
||||
// If the distance through intermediate vertex is less than
|
||||
// direct edge then update value in distance array
|
||||
dist[i][j] = dist[i][k] + dist[k][j];
|
||||
|
||||
// Convert 2d array to 1d array for print
|
||||
std::vector<int> dist1d(V * V);
|
||||
for (int i = 0; i < V; i++)
|
||||
for (int j = 0; j < V; j++) dist1d[i * V + j] = dist[i][j];
|
||||
|
||||
print(dist1d, V);
|
||||
}
|
||||
|
||||
// Driver Function
|
||||
int main() {
|
||||
int V, E;
|
||||
int src, dst, weight;
|
||||
cout << "Enter number of vertices: ";
|
||||
cin >> V;
|
||||
cout << "Enter number of edges: ";
|
||||
cin >> E;
|
||||
Graph G(V);
|
||||
for (int i = 0; i < E; i++) {
|
||||
cout << "\nEdge " << i + 1 << "\nEnter source: ";
|
||||
cin >> src;
|
||||
cout << "Enter destination: ";
|
||||
cin >> dst;
|
||||
cout << "Enter weight: ";
|
||||
cin >> weight;
|
||||
G.addEdge(src, dst, weight);
|
||||
}
|
||||
FloydWarshall(G);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [House Robber
|
||||
* Problem](https://labuladong.gitbook.io/algo-en/i.-dynamic-programming/houserobber)
|
||||
* algorithm
|
||||
* @details
|
||||
* Solution of House robber problem uses a dynamic programming concept that
|
||||
* works in \f$O(n)\f$ time and works in \f$O(1)\f$ space.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <climits> /// for std::max
|
||||
#include <cstdint> /// for std::uint32_t
|
||||
#include <iostream> /// for io operations
|
||||
#include <vector> /// for std::vector
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace house_robber
|
||||
* @brief Functions for the [House
|
||||
* Robber](https://labuladong.gitbook.io/algo-en/i.-dynamic-programming/houserobber)
|
||||
* algorithm
|
||||
*/
|
||||
namespace house_robber {
|
||||
/**
|
||||
* @brief The main function that implements the House Robber algorithm using
|
||||
* dynamic programming
|
||||
* @param money array containing money in the ith house
|
||||
* @param n size of array
|
||||
* @returns maximum amount of money that can be robbed
|
||||
*/
|
||||
std::uint32_t houseRobber(const std::vector<uint32_t> &money,
|
||||
const uint32_t &n) {
|
||||
if (n == 0) { // if there is no house
|
||||
return 0;
|
||||
}
|
||||
if (n == 1) { // if there is only one house
|
||||
return money[0];
|
||||
}
|
||||
if (n == 2) { // if there are two houses, one with the maximum amount of
|
||||
// money will be robbed
|
||||
return std::max(money[0], money[1]);
|
||||
}
|
||||
uint32_t max_value = 0; // contains maximum stolen value at the end
|
||||
uint32_t value1 = money[0];
|
||||
uint32_t value2 = std::max(money[0], money[1]);
|
||||
for (uint32_t i = 2; i < n; i++) {
|
||||
max_value = std::max(money[i] + value1, value2);
|
||||
value1 = value2;
|
||||
value2 = max_value;
|
||||
}
|
||||
|
||||
return max_value;
|
||||
}
|
||||
} // namespace house_robber
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
// [1, 2, 3, 1] return 4
|
||||
std::vector<uint32_t> array1 = {1, 2, 3, 1};
|
||||
std::cout << "Test 1... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array1, array1.size()) ==
|
||||
4); // here the two non-adjacent houses that are robbed are first and
|
||||
// third with total sum money as 4
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 2
|
||||
// [6, 7, 1, 3, 8, 2, 4] return 19
|
||||
std::vector<uint32_t> array2 = {6, 7, 1, 3, 8, 2, 4};
|
||||
std::cout << "Test 2... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array2, array2.size()) ==
|
||||
19); // here the four non-adjacent houses that are robbed are first,
|
||||
// third, fifth and seventh with total sum money as 19
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 3
|
||||
// [] return 0
|
||||
std::vector<uint32_t> array3 = {};
|
||||
std::cout << "Test 3... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array3, array3.size()) ==
|
||||
0); // since there is no house no money can be robbed
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 4
|
||||
// [2,7,9,3,1] return 12
|
||||
std::vector<uint32_t> array4 = {2, 7, 9, 3, 1};
|
||||
std::cout << "Test 4... ";
|
||||
assert(
|
||||
dynamic_programming::house_robber::houseRobber(array4, array4.size()) ==
|
||||
12); // here the three non-adjacent houses that are robbed are first,
|
||||
// third and fifth with total sum money as 12
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Kadane
|
||||
* Algorithm](https://en.wikipedia.org/wiki/Kadane%27s_algorithm)
|
||||
*
|
||||
* @details
|
||||
* Kadane algorithm is used to find the maximum sum subarray in an array and
|
||||
* maximum sum subarray problem is the task of finding a contiguous subarray
|
||||
* with the largest sum
|
||||
*
|
||||
* ### Algorithm
|
||||
* The simple idea of the algorithm is to search for all positive
|
||||
* contiguous segments of the array and keep track of maximum sum contiguous
|
||||
* segment among all positive segments(curr_sum is used for this)
|
||||
* Each time we get a positive sum we compare it with max_sum and update max_sum
|
||||
* if it is greater than curr_sum
|
||||
*
|
||||
* @author [Ayush Singh](https://github.com/ayush523)
|
||||
*/
|
||||
#include <array>
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @namespace kadane
|
||||
* @brief Functions for
|
||||
* [Kadane](https://en.wikipedia.org/wiki/Kadane%27s_algorithm) algorithm.
|
||||
*/
|
||||
namespace kadane {
|
||||
/**
|
||||
* @brief maxSubArray function is used to calculate the maximum sum subarray
|
||||
* and returns the value of maximum sum which is stored in the variable max_sum
|
||||
* @tparam N number of array size
|
||||
* @param n array where numbers are saved
|
||||
* @returns the value of maximum subarray sum
|
||||
*/
|
||||
template <size_t N>
|
||||
int maxSubArray(const std::array<int, N> &n) {
|
||||
int curr_sum =
|
||||
0; // declaring a variable named as curr_sum and initialized it to 0
|
||||
int max_sum = INT_MIN; // Initialized max_sum to INT_MIN
|
||||
for (int i : n) { // for loop to iterate over the elements of the array
|
||||
curr_sum += n[i];
|
||||
max_sum = std::max(max_sum, curr_sum); // getting the maximum value
|
||||
curr_sum = std::max(curr_sum, 0); // updating the value of curr_sum
|
||||
}
|
||||
return max_sum; // returning the value of max_sum
|
||||
}
|
||||
} // namespace kadane
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
const int N = 5;
|
||||
std::array<int, N> n{}; // declaring array
|
||||
// taking values of elements from user
|
||||
for (int i = 0; i < n.size(); i++) {
|
||||
std::cout << "Enter value of n[" << i << "]"
|
||||
<< "\n";
|
||||
std::cin >> n[i];
|
||||
}
|
||||
int max_sum = dynamic_programming::kadane::maxSubArray<N>(
|
||||
n); // calling maxSubArray function
|
||||
std::cout << "Maximum subarray sum is " << max_sum; // Printing the answer
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief contains the definition of the function ::longest_common_string_length
|
||||
* @details
|
||||
* the function ::longest_common_string_length computes the length
|
||||
* of the longest common string which can be created of two input strings
|
||||
* by removing characters from them
|
||||
*
|
||||
* @author [Nikhil Arora](https://github.com/nikhilarora068)
|
||||
* @author [Piotr Idzik](https://github.com/vil02)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for std::cout
|
||||
#include <string> /// for std::string
|
||||
#include <utility> /// for std::move
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @brief computes the length of the longest common string created from input
|
||||
* strings
|
||||
* @details has O(str_a.size()*str_b.size()) time and memory complexity
|
||||
* @param string_a first input string
|
||||
* @param string_b second input string
|
||||
* @returns the length of the longest common string which can be strated from
|
||||
* str_a and str_b
|
||||
*/
|
||||
std::size_t longest_common_string_length(const std::string& string_a,
|
||||
const std::string& string_b) {
|
||||
const auto size_a = string_a.size();
|
||||
const auto size_b = string_b.size();
|
||||
std::vector<std::vector<std::size_t>> sub_sols(
|
||||
size_a + 1, std::vector<std::size_t>(size_b + 1, 0));
|
||||
|
||||
const auto limit = static_cast<std::size_t>(-1);
|
||||
for (std::size_t pos_a = size_a - 1; pos_a != limit; --pos_a) {
|
||||
for (std::size_t pos_b = size_b - 1; pos_b != limit; --pos_b) {
|
||||
if (string_a[pos_a] == string_b[pos_b]) {
|
||||
sub_sols[pos_a][pos_b] = 1 + sub_sols[pos_a + 1][pos_b + 1];
|
||||
} else {
|
||||
sub_sols[pos_a][pos_b] = std::max(sub_sols[pos_a + 1][pos_b],
|
||||
sub_sols[pos_a][pos_b + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sub_sols[0][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief represents single example inputs and expected output of the function
|
||||
* ::longest_common_string_length
|
||||
*/
|
||||
struct TestCase {
|
||||
const std::string string_a;
|
||||
const std::string string_b;
|
||||
const std::size_t common_string_len;
|
||||
|
||||
TestCase(std::string string_a, std::string string_b,
|
||||
const std::size_t in_common_string_len)
|
||||
: string_a(std::move(string_a)),
|
||||
string_b(std::move(string_b)),
|
||||
common_string_len(in_common_string_len) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return example data used in the tests of ::longest_common_string_length
|
||||
*/
|
||||
std::vector<TestCase> get_test_cases() {
|
||||
return {TestCase("", "", 0),
|
||||
TestCase("ab", "ab", 2),
|
||||
TestCase("ab", "ba", 1),
|
||||
TestCase("", "xyz", 0),
|
||||
TestCase("abcde", "ace", 3),
|
||||
TestCase("BADANA", "ANADA", 3),
|
||||
TestCase("BADANA", "CANADAS", 3),
|
||||
TestCase("a1a234a5aaaa6", "A1AAAA234AAA56AAAAA", 6),
|
||||
TestCase("123x", "123", 3),
|
||||
TestCase("12x3x", "123", 3),
|
||||
TestCase("1x2x3x", "123", 3),
|
||||
TestCase("x1x2x3x", "123", 3),
|
||||
TestCase("x12x3x", "123", 3)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checks the function ::longest_common_string_length agains example data
|
||||
* @param test_cases list of test cases
|
||||
* @tparam type representing a list of test cases
|
||||
*/
|
||||
template <typename TestCases>
|
||||
static void test_longest_common_string_length(const TestCases& test_cases) {
|
||||
for (const auto& cur_tc : test_cases) {
|
||||
assert(longest_common_string_length(cur_tc.string_a, cur_tc.string_b) ==
|
||||
cur_tc.common_string_len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checks if the function ::longest_common_string_length returns the same
|
||||
* result when its argument are flipped
|
||||
* @param test_cases list of test cases
|
||||
* @tparam type representing a list of test cases
|
||||
*/
|
||||
template <typename TestCases>
|
||||
static void test_longest_common_string_length_is_symmetric(
|
||||
const TestCases& test_cases) {
|
||||
for (const auto& cur_tc : test_cases) {
|
||||
assert(longest_common_string_length(cur_tc.string_b, cur_tc.string_a) ==
|
||||
cur_tc.common_string_len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief reverses a given string
|
||||
* @param in_str input string
|
||||
* @return the string in which the characters appear in the reversed order as in
|
||||
* in_str
|
||||
*/
|
||||
std::string reverse_str(const std::string& in_str) {
|
||||
return {in_str.rbegin(), in_str.rend()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief checks if the function ::longest_common_string_length returns the same
|
||||
* result when its inputs are reversed
|
||||
* @param test_cases list of test cases
|
||||
* @tparam type representing a list of test cases
|
||||
*/
|
||||
template <typename TestCases>
|
||||
static void test_longest_common_string_length_for_reversed_inputs(
|
||||
const TestCases& test_cases) {
|
||||
for (const auto& cur_tc : test_cases) {
|
||||
assert(longest_common_string_length(reverse_str(cur_tc.string_a),
|
||||
reverse_str(cur_tc.string_b)) ==
|
||||
cur_tc.common_string_len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief runs all tests for ::longest_common_string_length funcion
|
||||
*/
|
||||
static void tests() {
|
||||
const auto test_cases = get_test_cases();
|
||||
assert(test_cases.size() > 0);
|
||||
test_longest_common_string_length(test_cases);
|
||||
test_longest_common_string_length_is_symmetric(test_cases);
|
||||
test_longest_common_string_length_for_reversed_inputs(test_cases);
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Longest common subsequence - Dynamic Programming
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
void Print(int trace[20][20], int m, int n, string a) {
|
||||
if (m == 0 || n == 0) {
|
||||
return;
|
||||
}
|
||||
if (trace[m][n] == 1) {
|
||||
Print(trace, m - 1, n - 1, a);
|
||||
cout << a[m - 1];
|
||||
} else if (trace[m][n] == 2) {
|
||||
Print(trace, m - 1, n, a);
|
||||
} else if (trace[m][n] == 3) {
|
||||
Print(trace, m, n - 1, a);
|
||||
}
|
||||
}
|
||||
|
||||
int lcs(string a, string b) {
|
||||
int m = a.length(), n = b.length();
|
||||
std::vector<std::vector<int> > res(m + 1, std::vector<int>(n + 1));
|
||||
int trace[20][20];
|
||||
|
||||
// fills up the arrays with zeros.
|
||||
for (int i = 0; i < m + 1; i++) {
|
||||
for (int j = 0; j < n + 1; j++) {
|
||||
res[i][j] = 0;
|
||||
trace[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m + 1; ++i) {
|
||||
for (int j = 0; j < n + 1; ++j) {
|
||||
if (i == 0 || j == 0) {
|
||||
res[i][j] = 0;
|
||||
trace[i][j] = 0;
|
||||
}
|
||||
|
||||
else if (a[i - 1] == b[j - 1]) {
|
||||
res[i][j] = 1 + res[i - 1][j - 1];
|
||||
trace[i][j] = 1; // 1 means trace the matrix in upper left
|
||||
// diagonal direction.
|
||||
} else {
|
||||
if (res[i - 1][j] > res[i][j - 1]) {
|
||||
res[i][j] = res[i - 1][j];
|
||||
trace[i][j] =
|
||||
2; // 2 means trace the matrix in upwards direction.
|
||||
} else {
|
||||
res[i][j] = res[i][j - 1];
|
||||
trace[i][j] =
|
||||
3; // means trace the matrix in left direction.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Print(trace, m, n, a);
|
||||
return res[m][n];
|
||||
}
|
||||
|
||||
int main() {
|
||||
string a, b;
|
||||
cin >> a >> b;
|
||||
cout << lcs(a, b);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Calculate the length of the [longest increasing
|
||||
* subsequence](https://en.wikipedia.org/wiki/Longest_increasing_subsequence) in
|
||||
* an array
|
||||
*
|
||||
* @details
|
||||
* In computer science, the longest increasing subsequence problem is to find a
|
||||
* subsequence of a given sequence in which the subsequence's elements are in
|
||||
* sorted order, lowest to highest, and in which the subsequence is as long as
|
||||
* possible. This subsequence is not necessarily contiguous, or unique. Longest
|
||||
* increasing subsequences are studied in the context of various disciplines
|
||||
* related to mathematics, including algorithmics, random matrix theory,
|
||||
* representation theory, and physics. The longest increasing subsequence
|
||||
* problem is solvable in time O(n log n), where n denotes the length of the
|
||||
* input sequence.
|
||||
*
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <climits> /// for std::max
|
||||
#include <cstdint> /// for std::uint64_t
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief Calculate the longest increasing subsequence for the specified numbers
|
||||
* @param a the array used to calculate the longest increasing subsequence
|
||||
* @param n the size used for the arrays
|
||||
* @returns the length of the longest increasing
|
||||
* subsequence in the `a` array of size `n`
|
||||
*/
|
||||
uint64_t LIS(const std::vector<uint64_t> &a, const uint32_t &n) {
|
||||
std::vector<int> lis(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
lis[i] = 1;
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
for (int j = 0; j < i; ++j) {
|
||||
if (a[i] > a[j] && lis[i] < lis[j] + 1) {
|
||||
lis[i] = lis[j] + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
int res = 0;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
res = std::max(res, lis[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<uint64_t> a = {15, 21, 2, 3, 4, 5, 8, 4, 1, 1};
|
||||
uint32_t n = a.size();
|
||||
|
||||
uint32_t result = dynamic_programming::LIS(a, n);
|
||||
assert(result ==
|
||||
5); ///< The longest increasing subsequence is `{2,3,4,5,8}`
|
||||
|
||||
std::cout << "Self-test implementations passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
uint32_t n = 0;
|
||||
|
||||
std::cout << "Enter size of array: ";
|
||||
std::cin >> n;
|
||||
|
||||
std::vector<uint64_t> a(n);
|
||||
|
||||
std::cout << "Enter array elements: ";
|
||||
for (int i = 0; i < n; ++i) {
|
||||
std::cin >> a[i];
|
||||
}
|
||||
|
||||
std::cout << "\nThe result is: " << dynamic_programming::LIS(a, n)
|
||||
<< std::endl;
|
||||
test(); // run self-test implementations
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Program to calculate length of longest increasing subsequence in an array
|
||||
// in O(n log n)
|
||||
// tested on : https://cses.fi/problemset/task/1145/
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
int LIS(const std::vector<int>& arr, int n) {
|
||||
set<int> active; // The current built LIS.
|
||||
active.insert(arr[0]);
|
||||
// Loop through every element.
|
||||
for (int i = 1; i < n; ++i) {
|
||||
auto get = active.lower_bound(arr[i]);
|
||||
if (get == active.end()) {
|
||||
active.insert(arr[i]);
|
||||
} // current element is the greatest so LIS increases by 1.
|
||||
else {
|
||||
int val = *get; // we find the position where arr[i] will be in the
|
||||
// LIS. If it is in the LIS already we do nothing
|
||||
if (val > arr[i]) {
|
||||
// else we remove the bigger element and add a smaller element
|
||||
// (which is arr[i]) and continue;
|
||||
active.erase(get);
|
||||
active.insert(arr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return active.size(); // size of the LIS.
|
||||
}
|
||||
int main() {
|
||||
int n;
|
||||
cout << "Enter size of array: ";
|
||||
cin >> n;
|
||||
std::vector<int> a(n);
|
||||
cout << "Enter array elements: ";
|
||||
for (int i = 0; i < n; ++i) {
|
||||
cin >> a[i];
|
||||
}
|
||||
cout << LIS(a, n) << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Program to find the [Longest Palindormic
|
||||
* Subsequence](https://www.geeksforgeeks.org/longest-palindromic-subsequence-dp-12/) of a string
|
||||
*
|
||||
* @details
|
||||
* [Palindrome](https://en.wikipedia.org/wiki/Palindrome) string sequence of
|
||||
* characters which reads the same backward as forward
|
||||
* [Subsequence](https://en.wikipedia.org/wiki/Subsequence) is a sequence that
|
||||
* can be derived from another sequence by deleting some or no elements without
|
||||
* changing the order of the remaining elements.
|
||||
|
||||
* @author [Anjali Jha](https://github.com/anjali1903)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <string> /// for std::string
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief Function that returns the longest palindromic
|
||||
* subsequence of a string
|
||||
* @param a string whose longest palindromic subsequence is to be found
|
||||
* @returns longest palindromic subsequence of the string
|
||||
*/
|
||||
std::string lps(const std::string& a) {
|
||||
const auto b = std::string(a.rbegin(), a.rend());
|
||||
const auto m = a.length();
|
||||
using ind_type = std::string::size_type;
|
||||
std::vector<std::vector<ind_type> > res(m + 1,
|
||||
std::vector<ind_type>(m + 1));
|
||||
|
||||
// Finding the length of the longest
|
||||
// palindromic subsequence and storing
|
||||
// in a 2D array in bottoms-up manner
|
||||
for (ind_type i = 0; i <= m; i++) {
|
||||
for (ind_type j = 0; j <= m; j++) {
|
||||
if (i == 0 || j == 0) {
|
||||
res[i][j] = 0;
|
||||
} else if (a[i - 1] == b[j - 1]) {
|
||||
res[i][j] = res[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
res[i][j] = std::max(res[i - 1][j], res[i][j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Length of longest palindromic subsequence
|
||||
auto idx = res[m][m];
|
||||
// Creating string of index+1 length
|
||||
std::string ans(idx, '\0');
|
||||
ind_type i = m, j = m;
|
||||
|
||||
// starting from right-most bottom-most corner
|
||||
// and storing them one by one in ans
|
||||
while (i > 0 && j > 0) {
|
||||
// if current characters in a and b are same
|
||||
// then it is a part of the ans
|
||||
if (a[i - 1] == b[j - 1]) {
|
||||
ans[idx - 1] = a[i - 1];
|
||||
i--;
|
||||
j--;
|
||||
idx--;
|
||||
}
|
||||
// If they are not same, find the larger of the
|
||||
// two and move in that direction
|
||||
else if (res[i - 1][j] > res[i][j - 1]) {
|
||||
i--;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
return ans;
|
||||
}
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
assert(dynamic_programming::lps("radar") == "radar");
|
||||
assert(dynamic_programming::lps("abbcbaa") == "abcba");
|
||||
assert(dynamic_programming::lps("bbbab") == "bbbb");
|
||||
assert(dynamic_programming::lps("") == "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main Function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the tests
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#define MAX 10
|
||||
|
||||
// dp table to store the solution for already computed sub problems
|
||||
int dp[MAX][MAX];
|
||||
|
||||
// Function to find the most efficient way to multiply the given sequence of
|
||||
// matrices
|
||||
int MatrixChainMultiplication(int dim[], int i, int j) {
|
||||
// base case: one matrix
|
||||
if (j <= i + 1)
|
||||
return 0;
|
||||
|
||||
// stores minimum number of scalar multiplications (i.e., cost)
|
||||
// needed to compute the matrix M[i+1]...M[j] = M[i..j]
|
||||
int min = INT_MAX;
|
||||
|
||||
// if dp[i][j] is not calculated (calculate it!!)
|
||||
|
||||
if (dp[i][j] == 0) {
|
||||
// take the minimum over each possible position at which the
|
||||
// sequence of matrices can be split
|
||||
|
||||
for (int k = i + 1; k <= j - 1; k++) {
|
||||
// recur for M[i+1]..M[k] to get a i x k matrix
|
||||
int cost = MatrixChainMultiplication(dim, i, k);
|
||||
|
||||
// recur for M[k+1]..M[j] to get a k x j matrix
|
||||
cost += MatrixChainMultiplication(dim, k, j);
|
||||
|
||||
// cost to multiply two (i x k) and (k x j) matrix
|
||||
cost += dim[i] * dim[k] * dim[j];
|
||||
|
||||
if (cost < min)
|
||||
min = cost; // store the minimum cost
|
||||
}
|
||||
dp[i][j] = min;
|
||||
}
|
||||
|
||||
// return min cost to multiply M[j+1]..M[j]
|
||||
return dp[i][j];
|
||||
}
|
||||
|
||||
// main function
|
||||
int main() {
|
||||
// Matrix i has Dimensions dim[i-1] & dim[i] for i=1..n
|
||||
// input is 10 x 30 matrix, 30 x 5 matrix, 5 x 60 matrix
|
||||
int dim[] = {10, 30, 5, 60};
|
||||
int n = sizeof(dim) / sizeof(dim[0]);
|
||||
|
||||
// Function Calling: MatrixChainMultiplications(dimensions_array, starting,
|
||||
// ending);
|
||||
|
||||
cout << "Minimum cost is " << MatrixChainMultiplication(dim, 0, n - 1)
|
||||
<< "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief C++ program for maximum contiguous circular sum problem using [Kadane's Algorithm](https://en.wikipedia.org/wiki/Maximum_subarray_problem)
|
||||
* @details
|
||||
* The idea is to modify Kadane’s algorithm to find a minimum contiguous subarray sum and the maximum contiguous subarray sum,
|
||||
* then check for the maximum value between the max_value and the value left after subtracting min_value from the total sum.
|
||||
* For more information, check [Geeks For Geeks](https://www.geeksforgeeks.org/maximum-contiguous-circular-sum/) explanation page.
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief returns the maximum contiguous circular sum of an array
|
||||
*
|
||||
* @param arr is the array/vector
|
||||
* @return int which is the maximum sum
|
||||
*/
|
||||
int maxCircularSum(std::vector<int>& arr)
|
||||
{
|
||||
// Edge Case
|
||||
if (arr.size() == 1)
|
||||
return arr[0];
|
||||
|
||||
// Sum variable which stores total sum of the array.
|
||||
int sum = 0;
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
sum += arr[i];
|
||||
}
|
||||
|
||||
// Every variable stores first value of the array.
|
||||
int current_max = arr[0], max_so_far = arr[0], current_min = arr[0], min_so_far = arr[0];
|
||||
|
||||
// Concept of Kadane's Algorithm
|
||||
for (int i = 1; i < arr.size(); i++) {
|
||||
// Kadane's Algorithm to find Maximum subarray sum.
|
||||
current_max = std::max(current_max + arr[i], arr[i]);
|
||||
max_so_far = std::max(max_so_far, current_max);
|
||||
|
||||
// Kadane's Algorithm to find Minimum subarray sum.
|
||||
current_min = std::min(current_min + arr[i], arr[i]);
|
||||
min_so_far = std::min(min_so_far, current_min);
|
||||
}
|
||||
|
||||
if (min_so_far == sum)
|
||||
return max_so_far;
|
||||
|
||||
// Return the maximum value
|
||||
return std::max(max_so_far, sum - min_so_far);
|
||||
}
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementation
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Description of the test
|
||||
// Input: arr[] = {8, -8, 9, -9, 10, -11, 12}
|
||||
// Output: 22
|
||||
// Explanation: Subarray 12, 8, -8, 9, -9, 10 gives the maximum sum, that is 22.
|
||||
|
||||
std::vector<int> arr = {8, -8, 9, -9, 10, -11, 12};
|
||||
assert(dynamic_programming::maxCircularSum(arr) == 22); // this ensures that the algorithm works as expected
|
||||
|
||||
arr = {8, -8, 10, -9, 10, -11, 12};
|
||||
assert(dynamic_programming::maxCircularSum(arr) == 23);
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Minimum Edit
|
||||
* Distance](https://en.wikipedia.org/wiki/Edit_distance) using Dynamic
|
||||
* Programing
|
||||
*
|
||||
* @details
|
||||
*
|
||||
* Given two strings str1 & str2 and we have to calculate the minimum
|
||||
* number of operations (Insert, Remove, Replace) required to convert
|
||||
* str1 to str2.
|
||||
*
|
||||
* ### Algorithm
|
||||
*
|
||||
* We will solve this problem using Naive recursion. But as we are
|
||||
* approaching with a DP solution. So, we will take a DP array to
|
||||
* store the solution of all sub-problems so that we don't have to
|
||||
* perform recursion again and again. Now to solve the problem, We
|
||||
* can traverse all characters from either right side of the strings
|
||||
* or left side. Suppose we will do it from the right side. So, there
|
||||
* are two possibilities for every pair of characters being traversed.
|
||||
* 1. If the last characters of two strings are the same, Ignore
|
||||
* the characters and get the count for the remaining string.
|
||||
* So, we get the solution for lengths m-1 and n-1 in a DP array.
|
||||
*
|
||||
* 2. Else, (If last characters are not the same), we will consider all
|
||||
* three operations (Insert, Remove, Replace) on the last character of
|
||||
* the first string and compute the minimum cost for all three operations
|
||||
* and take the minimum of three values in the DP array.
|
||||
* For Insert: Recur for m and n-1
|
||||
* For Remove: Recur for for m-1 and n
|
||||
* For Replace: Recur for for m-1 and n-1
|
||||
*
|
||||
* @author [Nirjas Jakilim](github.com/nirzak)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for std::uint64_t
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @namespace Minimum Edit Distance
|
||||
* @brief Implementation of [Minimum Edit
|
||||
* Distance](https://en.wikipedia.org/wiki/Edit_distance) algorithm
|
||||
*/
|
||||
|
||||
namespace minimum_edit_distance {
|
||||
|
||||
/**
|
||||
* @brief Takes input of the cost of
|
||||
* three operations: Insert, Replace and Delete
|
||||
* and return the minimum cost among them.
|
||||
* @param x used to pass minimum cost of Insert operations
|
||||
* @param y used to pass minimum cost of Replace operations
|
||||
* @param z used to pass minimum cost of Delete operations
|
||||
* @returns x if `x` is the minimum value
|
||||
* @returns y if `y` is the minimum value
|
||||
* @returns z if `z` is the minimum value
|
||||
*/
|
||||
uint64_t min(uint64_t x, uint64_t y, uint64_t z) {
|
||||
if (x <= y && x <= z) {
|
||||
return x; /// returns x, if x is the minimum value
|
||||
}
|
||||
if (y <= x && y <= z) {
|
||||
return y; /// returns y, if y is the minimum value
|
||||
} else {
|
||||
return z; /// returns z if z is the minimum value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and stores the result
|
||||
* of all the sub-problems, so that we don't have to recur to compute
|
||||
* the minimum cost of a particular operation if it is already
|
||||
* computed and stored in the `dp` vector.
|
||||
* @param dp vector to store the computed minimum costs
|
||||
* @param str1 to pass the 1st string
|
||||
* @param str2 to pass the 2nd string
|
||||
* @param m the length of str1
|
||||
* @param n the length of str2
|
||||
* @returns dp[m][n] the minimum cost of operations
|
||||
* needed to convert str1 to str2
|
||||
*/
|
||||
uint64_t editDistDP(std::string str1, std::string str2, uint64_t m,
|
||||
uint64_t n) {
|
||||
/// Create a table to store results of subproblems
|
||||
std::vector<std::vector<uint64_t>> dp(
|
||||
m + 1,
|
||||
std::vector<uint64_t>(
|
||||
n +
|
||||
1)); /// creasting 2D vector dp to store the results of subproblems
|
||||
|
||||
/// Fill d[][] in bottom up manner
|
||||
for (uint64_t i = 0; i <= m; i++) {
|
||||
for (uint64_t j = 0; j <= n; j++) {
|
||||
/// If first string is empty, only option is to
|
||||
/// insert all characters of second string
|
||||
if (i == 0) {
|
||||
dp[i][j] = j; /// Minimum operations = j
|
||||
}
|
||||
|
||||
/// If second string is empty, only option is to
|
||||
/// remove all characters of second string
|
||||
else if (j == 0) {
|
||||
dp[i][j] = i; /// Minimum operations = i
|
||||
}
|
||||
|
||||
/// If last characters are same, ignore last char
|
||||
/// and recur for remaining string
|
||||
else if (str1[i - 1] == str2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
}
|
||||
|
||||
/// If the last character is different, consider all
|
||||
/// possibilities and find the minimum
|
||||
else {
|
||||
dp[i][j] = 1 + min(dp[i][j - 1], // Insert
|
||||
dp[i - 1][j], // Remove
|
||||
dp[i - 1][j - 1]); // Replace
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[m][n]; /// returning the minimum cost of operations needed to
|
||||
/// convert str1 to str2
|
||||
}
|
||||
} // namespace minimum_edit_distance
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::string str1 = "INTENTION"; // Sample input of 1st string
|
||||
std::string str2 = "EXECUTION"; // Sample input of 2nd string
|
||||
uint64_t expected_output1 = 5; // Expected minimum cost
|
||||
uint64_t output1 = dynamic_programming::minimum_edit_distance::editDistDP(
|
||||
str1, str2, str1.length(),
|
||||
str2.length()); // calling the editDistDP function and storing the
|
||||
// result on output1
|
||||
assert(output1 ==
|
||||
expected_output1); // comparing the output with the expected output
|
||||
std::cout << "Minimum Number of Operations Required: " << output1
|
||||
<< std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::string str3 = "SATURDAY";
|
||||
std::string str4 = "SUNDAY";
|
||||
uint64_t expected_output2 = 3;
|
||||
uint64_t output2 = dynamic_programming::minimum_edit_distance::editDistDP(
|
||||
str3, str4, str3.length(), str4.length());
|
||||
assert(output2 == expected_output2);
|
||||
std::cout << "Minimum Number of Operations Required: " << output2
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implements [Palindrome
|
||||
* Partitioning](https://leetcode.com/problems/palindrome-partitioning-ii/)
|
||||
* algorithm, giving you the minimum number of partitions you need to make
|
||||
*
|
||||
* @details
|
||||
* palindrome partitioning uses dynamic programming and goes to all the possible
|
||||
* partitions to find the minimum you are given a string and you need to give
|
||||
* minimum number of partitions needed to divide it into a number of palindromes
|
||||
* [Palindrome Partitioning]
|
||||
* (https://www.geeksforgeeks.org/palindrome-partitioning-dp-17/) overall time
|
||||
* complexity O(n^2) For example: example 1:- String : "nitik" Output : 2 => "n
|
||||
* | iti | k" For example: example 2:- String : "ababbbabbababa" Output : 3 =>
|
||||
* "aba | b | bbabb | ababa"
|
||||
* @author [Sujay Kaushik] (https://github.com/sujaykaushik008)
|
||||
*/
|
||||
|
||||
#include <algorithm> // for std::min
|
||||
#include <cassert> // for std::assert
|
||||
#include <climits> // for INT_MAX
|
||||
#include <iostream> // for io operations
|
||||
#include <vector> // for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @namespace palindrome_partitioning
|
||||
* @brief Functions for [Palindrome
|
||||
* Partitioning](https://leetcode.com/problems/palindrome-partitioning-ii/)
|
||||
* algorithm
|
||||
*/
|
||||
namespace palindrome_partitioning {
|
||||
|
||||
/**
|
||||
* Function implementing palindrome partitioning algorithm using lookup table
|
||||
* method.
|
||||
* @param str input string
|
||||
* @returns minimum number of partitions
|
||||
*/
|
||||
int pal_part(const std::string &str) {
|
||||
int n = str.size();
|
||||
|
||||
// creating lookup table for minimum number of cuts
|
||||
std::vector<std::vector<int> > cuts(n, std::vector<int>(n, 0));
|
||||
|
||||
// creating lookup table for palindrome checking
|
||||
std::vector<std::vector<bool> > is_palindrome(n,
|
||||
std::vector<bool>(n, false));
|
||||
|
||||
// initialization
|
||||
for (int i = 0; i < n; i++) {
|
||||
is_palindrome[i][i] = true;
|
||||
cuts[i][i] = 0;
|
||||
}
|
||||
|
||||
for (int len = 2; len <= n; len++) {
|
||||
for (int start_index = 0; start_index < n - len + 1; start_index++) {
|
||||
int end_index = start_index + len - 1;
|
||||
|
||||
if (len == 2) {
|
||||
is_palindrome[start_index][end_index] =
|
||||
(str[start_index] == str[end_index]);
|
||||
} else {
|
||||
is_palindrome[start_index][end_index] =
|
||||
(str[start_index] == str[end_index]) &&
|
||||
is_palindrome[start_index + 1][end_index - 1];
|
||||
}
|
||||
|
||||
if (is_palindrome[start_index][end_index]) {
|
||||
cuts[start_index][end_index] = 0;
|
||||
} else {
|
||||
cuts[start_index][end_index] = INT_MAX;
|
||||
for (int partition = start_index; partition <= end_index - 1;
|
||||
partition++) {
|
||||
cuts[start_index][end_index] =
|
||||
std::min(cuts[start_index][end_index],
|
||||
cuts[start_index][partition] +
|
||||
cuts[partition + 1][end_index] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cuts[0][n - 1];
|
||||
}
|
||||
} // namespace palindrome_partitioning
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Test Function
|
||||
* @return void
|
||||
*/
|
||||
static void test() {
|
||||
// custom input vector
|
||||
std::vector<std::string> custom_input{"nitik", "ababbbabbababa", "abdc"};
|
||||
|
||||
// calculated output vector by pal_part Function
|
||||
std::vector<int> calculated_output(3);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
calculated_output[i] =
|
||||
dynamic_programming::palindrome_partitioning::pal_part(
|
||||
custom_input[i]);
|
||||
}
|
||||
|
||||
// expected output vector
|
||||
std::vector<int> expected_output{2, 3, 3};
|
||||
|
||||
// Testing implementation via assert function
|
||||
// It will throw error if any of the expected test fails
|
||||
// Else it will give nothing
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assert(expected_output[i] == calculated_output[i]);
|
||||
}
|
||||
|
||||
std::cout << "All tests passed successfully!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the test
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/******************************************************************************
|
||||
* @file
|
||||
* @brief Implementation of the [Partition
|
||||
* Problem](https://en.wikipedia.org/wiki/Partition_problem )
|
||||
* @details
|
||||
* The partition problem, or number partitioning, is the task of deciding
|
||||
* whether a given multiset S of positive integers can be partitioned into two
|
||||
* subsets S1 and S2 such that the sum of the numbers in S1 equals the sum of
|
||||
* the numbers in S2. Although the partition problem is NP-complete, there is a
|
||||
* pseudo-polynomial time dynamic programming solution, and there are heuristics
|
||||
* that solve the problem in many instances, either optimally or approximately.
|
||||
* For this reason, it has been called "the easiest hard problem".
|
||||
*
|
||||
* The worst case time complexity of Jarvis’s Algorithm is O(n^2). Using
|
||||
* Graham’s scan algorithm, we can find Convex Hull in O(nLogn) time.
|
||||
*
|
||||
* ### Implementation
|
||||
*
|
||||
* Step 1
|
||||
* Calculate sum of the array. If sum is odd, there can not be two subsets with
|
||||
* equal sum, so return false.
|
||||
*
|
||||
* Step 2
|
||||
* If sum of array elements is even, calculate sum/2 and find a subset of array
|
||||
* with sum equal to sum/2.
|
||||
*
|
||||
* @author [Lajat Manekar](https://github.com/Lazeeez)
|
||||
*
|
||||
*******************************************************************************/
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for std::uint64_t
|
||||
#include <iostream> /// for IO Operations
|
||||
#include <numeric> /// for std::accumulate
|
||||
#include <vector> /// for std::vector
|
||||
/******************************************************************************
|
||||
* @namespace dp
|
||||
* @brief Dynamic programming algorithms
|
||||
*******************************************************************************/
|
||||
namespace dp {
|
||||
|
||||
/******************************************************************************
|
||||
* @namespace partitionProblem
|
||||
* @brief Partition problem algorithm
|
||||
*******************************************************************************/
|
||||
namespace partitionProblem {
|
||||
|
||||
/******************************************************************************
|
||||
* @brief Returns true if arr can be partitioned in two subsets of equal sum,
|
||||
* otherwise false
|
||||
* @param arr vector containing elements
|
||||
* @param size Size of the vector.
|
||||
* @returns @param bool whether the vector can be partitioned or not.
|
||||
*******************************************************************************/
|
||||
bool findPartiion(const std::vector<uint64_t> &arr, uint64_t size) {
|
||||
uint64_t sum = std::accumulate(arr.begin(), arr.end(),
|
||||
0); // Calculate sum of all elements
|
||||
|
||||
if (sum % 2 != 0) {
|
||||
return false; // if sum is odd, it cannot be divided into two equal sum
|
||||
}
|
||||
std::vector<bool> part;
|
||||
// bool part[sum / 2 + 1];
|
||||
|
||||
// Initialize the part array as 0
|
||||
for (uint64_t it = 0; it <= sum / 2; ++it) {
|
||||
part.push_back(false);
|
||||
}
|
||||
|
||||
// Fill the partition table in bottom up manner
|
||||
for (uint64_t it = 0; it < size; ++it) {
|
||||
// The element to be included in the sum cannot be greater than the sum
|
||||
for (uint64_t it2 = sum / 2; it2 >= arr[it];
|
||||
--it2) { // Check if sum - arr[i]
|
||||
// ould be formed from a subset using elements before index i
|
||||
if (part[it2 - arr[it]] == 1 || it2 == arr[it]) {
|
||||
part[it2] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return part[sum / 2];
|
||||
}
|
||||
} // namespace partitionProblem
|
||||
} // namespace dp
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*******************************************************************************/
|
||||
static void test() {
|
||||
std::vector<uint64_t> arr = {{1, 3, 3, 2, 3, 2}};
|
||||
uint64_t n = arr.size();
|
||||
bool expected_result = true;
|
||||
bool derived_result = dp::partitionProblem::findPartiion(arr, n);
|
||||
std::cout << "1st test: ";
|
||||
assert(expected_result == derived_result);
|
||||
std::cout << "Passed!" << std::endl;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*******************************************************************************/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
*this program is use to find any elemet in any row with variable array size
|
||||
*aplication of pointer is use in it
|
||||
*important point start from here to:
|
||||
*the index value of array can be go to 1 to 100000
|
||||
*check till array[1000]
|
||||
*end here
|
||||
*how to work example:
|
||||
**Question:
|
||||
***number of array 2
|
||||
***quarry 3
|
||||
***array 1 is {1 2 3 4 5}
|
||||
***array 2 is {6 7}
|
||||
****i) what is 2nd element in 1st array
|
||||
****ii) what is 1st element in 2nd array
|
||||
****iii) what is 5th element in 1st array
|
||||
*****output:
|
||||
*****Enter Number of array you want to Store : 2
|
||||
*****Enter Number of Question or Quary you want to do Related to Array : 3
|
||||
*****Enter number of element in 1 rows : 5
|
||||
*****Enter the element of Array 1 2 3 4 5
|
||||
*****Enter number of element in 2 rows : 2
|
||||
*****Enter the element of Array 6 7
|
||||
*****enter the number of row which element You want to find : 1
|
||||
*****enter the position of element which You want to find : 2
|
||||
*****The element is 2
|
||||
*****enter the number of row which element You want to find : 2
|
||||
*****enter the position of element which You want to find : 1
|
||||
*****The element is 6
|
||||
*****enter the number of row which element You want to find : 1
|
||||
*****enter the position of element which You want to find : 5
|
||||
*****The element is 5
|
||||
*/
|
||||
#include <iostream>
|
||||
|
||||
// this is main fuction
|
||||
// ***
|
||||
int main() {
|
||||
int64_t r, mr = 0, x, q, i, z;
|
||||
std::cout << "Enter Number of array you want to Store :";
|
||||
std::cin >> x;
|
||||
std::cout << "Enter Number of ";
|
||||
std::cout << "Question or Quary you ";
|
||||
std::cout << "want to do Related to Array :";
|
||||
std::cin >> q;
|
||||
// create a Array in run time because use can
|
||||
// change the size of each array which he/she is going to store
|
||||
// create a 2D array
|
||||
int** ar = new int*[x]();
|
||||
// this for loop is use for entering different variable size array
|
||||
// ***
|
||||
for (r = 0; r < x; r++) {
|
||||
std::cout << "Enter number of element in " << r + 1 << " rows :";
|
||||
std::cin >> mr;
|
||||
// creating a 1D array
|
||||
int* ac = new int[mr]();
|
||||
std::cout << "Enter the element of Array ";
|
||||
// this for loop is use for storing values in array
|
||||
// ***
|
||||
for (i = 0; i < mr; i++) {
|
||||
// entering the value of rows in array in Horizontal
|
||||
std::cin >> ac[i];
|
||||
}
|
||||
// Change the position of Array so that new arrays entery will be done
|
||||
ar[r] = ac;
|
||||
}
|
||||
// this for loop is use for display result of querry
|
||||
// ***
|
||||
for (z = 0; z < q; z++) {
|
||||
int64_t r1 = 0, q1 = 0;
|
||||
std::cout << "enter the number of row which element you want to find :";
|
||||
std::cin >> r1;
|
||||
r1 = r1 - 1;
|
||||
std::cout << "enter the position of element which you want to find :";
|
||||
std::cin >> q1;
|
||||
q1 = q1 - 1;
|
||||
// use this to find desire position of element in desire array
|
||||
std::cout << "The element is " << ar[r1][q1] << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief SCS is a string Z which is the shortest supersequence of strings X and Y (may not be continuous in Z, but order is maintained).
|
||||
*
|
||||
* @details
|
||||
* The idea is to use lookup table method as used in LCS.
|
||||
* For example: example 1:-
|
||||
* X: 'ABCXYZ', Y: 'ABZ' then Z will be 'ABCXYZ' (y is not continuous but in order)
|
||||
*
|
||||
* For example: example 2:-
|
||||
* X: 'AGGTAB', Y: 'GXTXAYB' then Z will be 'AGGXTXAYB'
|
||||
* @author [Ridhish Jain](https://github.com/ridhishjain)
|
||||
* @see more on [SCS](https://en.wikipedia.org/wiki/Shortest_common_supersequence_problem)
|
||||
* @see related problem [Leetcode](https://leetcode.com/problems/shortest-common-supersequence/)
|
||||
*/
|
||||
|
||||
// header files
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @namespace shortest_common_supersequence
|
||||
* @brief Shortest Common Super Sequence algorithm
|
||||
*/
|
||||
namespace shortest_common_supersequence {
|
||||
|
||||
/**
|
||||
* Function implementing Shortest Common Super-Sequence algorithm using look-up table method.
|
||||
* @param str1 first string 'X'
|
||||
* @param str2 second string 'Y'
|
||||
* @returns string 'Z', superSequence of X and Y
|
||||
*/
|
||||
std::string scs(const std::string &str1, const std::string &str2) {
|
||||
|
||||
// Edge cases
|
||||
// If either str1 or str2 or both are empty
|
||||
if(str1.empty() && str2.empty()) {
|
||||
return "";
|
||||
}
|
||||
else if(str1.empty()) {
|
||||
return str2;
|
||||
}
|
||||
else if(str2.empty()) {
|
||||
return str1;
|
||||
}
|
||||
|
||||
// creating lookup table
|
||||
std::vector <std::vector <int>> lookup(str1.length() + 1, std::vector <int> (str2.length() + 1, 0));
|
||||
|
||||
for(int i=1; i <= str1.length(); i++) {
|
||||
for(int j=1; j <= str2.length(); j++) {
|
||||
if(str1[i-1] == str2[j-1]) {
|
||||
lookup[i][j] = lookup[i-1][j-1] + 1;
|
||||
}
|
||||
else {
|
||||
lookup[i][j] = std::max(lookup[i-1][j], lookup[i][j-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// making supersequence
|
||||
// i and j are initially pointed towards end of strings
|
||||
// Super-sequence will be constructed backwards
|
||||
int i=str1.length();
|
||||
int j=str2.length();
|
||||
std::string s;
|
||||
|
||||
while(i>0 && j>0) {
|
||||
|
||||
// If the characters at i and j of both strings are same
|
||||
// We only need to add them once in s
|
||||
if(str1[i-1] == str2[j-1]) {
|
||||
s.push_back(str1[i-1]);
|
||||
i--;
|
||||
j--;
|
||||
}
|
||||
// otherwise we check lookup table for recurrences of characters
|
||||
else {
|
||||
if(lookup[i-1][j] > lookup[i][j-1]) {
|
||||
s.push_back(str1[i-1]);
|
||||
i--;
|
||||
}
|
||||
else {
|
||||
s.push_back(str2[j-1]);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copying remaining elements
|
||||
// if j becomes 0 before i
|
||||
while(i > 0) {
|
||||
s.push_back(str1[i-1]);
|
||||
i--;
|
||||
}
|
||||
|
||||
// if i becomes 0 before j
|
||||
while(j > 0) {
|
||||
s.push_back(str2[j-1]);
|
||||
j--;
|
||||
}
|
||||
|
||||
// As the super sequence is constructd backwards
|
||||
// reversing the string before returning gives us the correct output
|
||||
reverse(s.begin(), s.end());
|
||||
return s;
|
||||
}
|
||||
} // namespace shortest_common_supersequence
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* Test Function
|
||||
* @return void
|
||||
*/
|
||||
static void test() {
|
||||
// custom input vector
|
||||
std::vector <std::vector <std::string>> scsStrings {
|
||||
{"ABCXYZ", "ABZ"},
|
||||
{"ABZ", "ABCXYZ"},
|
||||
{"AGGTAB", "GXTXAYB"},
|
||||
{"X", "Y"},
|
||||
};
|
||||
|
||||
// calculated output vector by scs function
|
||||
std::vector <std::string> calculatedOutput(4, "");
|
||||
int i=0;
|
||||
for(auto & scsString : scsStrings) {
|
||||
|
||||
calculatedOutput[i] = dynamic_programming::shortest_common_supersequence::scs(
|
||||
scsString[0], scsString[1]
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
// expected output vector acc to problem statement
|
||||
std::vector <std::string> expectedOutput {
|
||||
"ABCXYZ",
|
||||
"ABCXYZ",
|
||||
"AGGXTXAYB",
|
||||
"XY"
|
||||
};
|
||||
|
||||
// Testing implementation via assert function
|
||||
// It will throw error if any of the expected test fails
|
||||
// Else it will give nothing
|
||||
for(int i=0; i < scsStrings.size(); i++) {
|
||||
assert(expectedOutput[i] == calculatedOutput[i]);
|
||||
}
|
||||
|
||||
std::cout << "All tests passed successfully!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
/** Main function (driver code)*/
|
||||
int main() {
|
||||
// test for implementation
|
||||
test();
|
||||
|
||||
// user input
|
||||
std::string s1, s2;
|
||||
std::cin >> s1;
|
||||
std::cin >> s2;
|
||||
|
||||
std::string ans;
|
||||
|
||||
// user output
|
||||
ans = dynamic_programming::shortest_common_supersequence::scs(s1, s2);
|
||||
std::cout << ans;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implements [Sub-set sum problem]
|
||||
* (https://en.wikipedia.org/wiki/Subset_sum_problem) algorithm, which tells
|
||||
* whether a subset with target sum exists or not.
|
||||
*
|
||||
* @details
|
||||
* In this problem, we use dynamic programming to find if we can pull out a
|
||||
* subset from an array whose sum is equal to a given target sum. The overall
|
||||
* time complexity of the problem is O(n * targetSum) where n is the size of
|
||||
* the array. For example, array = [1, -10, 2, 31, -6], targetSum = -14.
|
||||
* Output: true => We can pick subset [-10, 2, -6] with sum as
|
||||
* (-10) + 2 + (-6) = -14.
|
||||
* @author [KillerAV](https://github.com/KillerAV)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for std::assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <unordered_map> /// for unordered map
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic Programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @namespace subset_sum
|
||||
* @brief Functions for [Sub-set sum problem]
|
||||
* (https://en.wikipedia.org/wiki/Subset_sum_problem) algorithm
|
||||
*/
|
||||
namespace subset_sum {
|
||||
|
||||
/**
|
||||
* Recursive function using dynamic programming to find if the required sum
|
||||
* subset exists or not.
|
||||
* @param arr input array
|
||||
* @param targetSum the target sum of the subset
|
||||
* @param dp the map storing the results
|
||||
* @returns true/false based on if the target sum subset exists or not.
|
||||
*/
|
||||
bool subset_sum_recursion(const std::vector<int> &arr, int targetSum,
|
||||
std::vector<std::unordered_map<int, bool>> *dp,
|
||||
int index = 0) {
|
||||
if (targetSum == 0) { // Found a valid subset with required sum.
|
||||
return true;
|
||||
}
|
||||
if (index == arr.size()) { // End of array
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((*dp)[index].count(targetSum)) { // Answer already present in map
|
||||
return (*dp)[index][targetSum];
|
||||
}
|
||||
|
||||
bool ans =
|
||||
subset_sum_recursion(arr, targetSum - arr[index], dp, index + 1) ||
|
||||
subset_sum_recursion(arr, targetSum, dp, index + 1);
|
||||
(*dp)[index][targetSum] = ans; // Save ans in dp map.
|
||||
return ans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function implementing subset sum algorithm using top-down approach
|
||||
* @param arr input array
|
||||
* @param targetSum the target sum of the subset
|
||||
* @returns true/false based on if the target sum subset exists or not.
|
||||
*/
|
||||
bool subset_sum_problem(const std::vector<int> &arr, const int targetSum) {
|
||||
size_t n = arr.size();
|
||||
std::vector<std::unordered_map<int, bool>> dp(n);
|
||||
return subset_sum_recursion(arr, targetSum, &dp);
|
||||
}
|
||||
} // namespace subset_sum
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Test Function
|
||||
* @return void
|
||||
*/
|
||||
static void test() {
|
||||
// custom input vector
|
||||
std::vector<std::vector<int>> custom_input_arr(3);
|
||||
custom_input_arr[0] = std::vector<int>{1, -10, 2, 31, -6};
|
||||
custom_input_arr[1] = std::vector<int>{2, 3, 4};
|
||||
custom_input_arr[2] = std::vector<int>{0, 1, 0, 1, 0};
|
||||
|
||||
std::vector<int> custom_input_target_sum(3);
|
||||
custom_input_target_sum[0] = -14;
|
||||
custom_input_target_sum[1] = 10;
|
||||
custom_input_target_sum[2] = 2;
|
||||
|
||||
// calculated output vector by pal_part Function
|
||||
std::vector<int> calculated_output(3);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
calculated_output[i] =
|
||||
dynamic_programming::subset_sum::subset_sum_problem(
|
||||
custom_input_arr[i], custom_input_target_sum[i]);
|
||||
}
|
||||
|
||||
// expected output vector
|
||||
std::vector<bool> expected_output{true, false, true};
|
||||
|
||||
// Testing implementation via assert function
|
||||
// It will throw error if any of the expected test fails
|
||||
// Else it will give nothing
|
||||
for (int i = 0; i < 3; i++) {
|
||||
assert(expected_output[i] == calculated_output[i]);
|
||||
}
|
||||
|
||||
std::cout << "All tests passed successfully!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the test
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Trapped Rainwater
|
||||
* Problem](https://www.geeksforgeeks.org/trapping-rain-water/)
|
||||
* @details
|
||||
* This implementation calculates the amount of rainwater that can be trapped
|
||||
* between walls represented by an array of heights.
|
||||
* @author [SOZEL](https://github.com/TruongNhanNguyen)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// For std::min and std::max
|
||||
#include <cassert> /// For assert
|
||||
#include <cstddef> /// For std::size_t
|
||||
#include <cstdint>
|
||||
#include <vector> /// For std::vector
|
||||
|
||||
/*
|
||||
* @namespace
|
||||
* @brief Dynamic Programming Algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief Function to calculate the trapped rainwater
|
||||
* @param heights Array representing the heights of walls
|
||||
* @return The amount of trapped rainwater
|
||||
*/
|
||||
uint32_t trappedRainwater(const std::vector<uint32_t>& heights) {
|
||||
std::size_t n = heights.size();
|
||||
if (n <= 2)
|
||||
return 0; // No water can be trapped with less than 3 walls
|
||||
|
||||
std::vector<uint32_t> leftMax(n), rightMax(n);
|
||||
|
||||
// Calculate the maximum height of wall to the left of each wall
|
||||
leftMax[0] = heights[0];
|
||||
for (std::size_t i = 1; i < n; ++i) {
|
||||
leftMax[i] = std::max(leftMax[i - 1], heights[i]);
|
||||
}
|
||||
|
||||
// Calculate the maximum height of wall to the right of each wall
|
||||
rightMax[n - 1] = heights[n - 1];
|
||||
for (std::size_t i = n - 2; i < n; --i) {
|
||||
rightMax[i] = std::max(rightMax[i + 1], heights[i]);
|
||||
}
|
||||
|
||||
// Calculate the trapped rainwater between walls
|
||||
uint32_t trappedWater = 0;
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
trappedWater +=
|
||||
std::max(0u, std::min(leftMax[i], rightMax[i]) - heights[i]);
|
||||
}
|
||||
|
||||
return trappedWater;
|
||||
}
|
||||
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<uint32_t> test_basic = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
|
||||
assert(dynamic_programming::trappedRainwater(test_basic) == 6);
|
||||
|
||||
std::vector<uint32_t> test_peak_under_water = {3, 0, 2, 0, 4};
|
||||
assert(dynamic_programming::trappedRainwater(test_peak_under_water) == 7);
|
||||
|
||||
std::vector<uint32_t> test_bucket = {5, 1, 5};
|
||||
assert(dynamic_programming::trappedRainwater(test_bucket) == 4);
|
||||
|
||||
std::vector<uint32_t> test_skewed_bucket = {4, 1, 5};
|
||||
assert(dynamic_programming::trappedRainwater(test_skewed_bucket) == 3);
|
||||
|
||||
std::vector<uint32_t> test_empty = {};
|
||||
assert(dynamic_programming::trappedRainwater(test_empty) == 0);
|
||||
|
||||
std::vector<uint32_t> test_flat = {0, 0, 0, 0, 0};
|
||||
assert(dynamic_programming::trappedRainwater(test_flat) == 0);
|
||||
|
||||
std::vector<uint32_t> test_no_trapped_water = {1, 1, 2, 4, 0, 0, 0};
|
||||
assert(dynamic_programming::trappedRainwater(test_no_trapped_water) == 0);
|
||||
|
||||
std::vector<uint32_t> test_single_elevation = {5};
|
||||
assert(dynamic_programming::trappedRainwater(test_single_elevation) == 0);
|
||||
|
||||
std::vector<uint32_t> test_two_point_elevation = {5, 1};
|
||||
assert(dynamic_programming::trappedRainwater(test_two_point_elevation) ==
|
||||
0);
|
||||
|
||||
std::vector<uint32_t> test_large_elevation_map_difference = {5, 1, 6, 1,
|
||||
7, 1, 8};
|
||||
assert(dynamic_programming::trappedRainwater(
|
||||
test_large_elevation_map_difference) == 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Trapped Rainwater
|
||||
* Problem](https://www.geeksforgeeks.org/trapping-rain-water/)
|
||||
* @details
|
||||
* This implementation calculates the total trapped rainwater using a
|
||||
* two-pointer approach. It maintains two pointers (`left` and `right`) and
|
||||
* tracks the maximum height seen so far from both ends (`leftMax` and
|
||||
* `rightMax`). At each step, the algorithm decides which side to process based
|
||||
* on which boundary is smaller, ensuring O(n) time and O(1) space complexity.
|
||||
* @author [kanavgoyal898](https://github.com/kanavgoyal898)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// For std::min and std::max
|
||||
#include <cassert> /// For assert
|
||||
#include <cstddef> /// For std::size_t
|
||||
#include <cstdint> /// For std::uint32_t
|
||||
#include <vector> /// For std::vector
|
||||
|
||||
/*
|
||||
* @namespace
|
||||
* @brief Dynamic Programming Algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
/**
|
||||
* @brief Function to calculate the trapped rainwater
|
||||
* @param heights Array representing the heights of walls
|
||||
* @return The amount of trapped rainwater
|
||||
*/
|
||||
uint32_t trappedRainwater(const std::vector<uint32_t>& heights) {
|
||||
std::size_t n = heights.size();
|
||||
if (n <= 2)
|
||||
return 0; // Not enough walls to trap water
|
||||
|
||||
std::size_t left = 0, right = n - 1;
|
||||
uint32_t leftMax = 0, rightMax = 0, trappedWater = 0;
|
||||
|
||||
// Traverse from both ends towards the center
|
||||
while (left < right) {
|
||||
if (heights[left] < heights[right]) {
|
||||
// Water trapped depends on the tallest wall to the left
|
||||
if (heights[left] >= leftMax)
|
||||
leftMax = heights[left]; // Update left max
|
||||
else
|
||||
trappedWater +=
|
||||
leftMax - heights[left]; // Water trapped at current left
|
||||
++left;
|
||||
} else {
|
||||
// Water trapped depends on the tallest wall to the right
|
||||
if (heights[right] >= rightMax)
|
||||
rightMax = heights[right]; // Update right max
|
||||
else
|
||||
trappedWater +=
|
||||
rightMax -
|
||||
heights[right]; // Water trapped at current right
|
||||
--right;
|
||||
}
|
||||
}
|
||||
|
||||
return trappedWater;
|
||||
}
|
||||
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<uint32_t> test_basic = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1};
|
||||
assert(dynamic_programming::trappedRainwater(test_basic) == 6);
|
||||
|
||||
std::vector<uint32_t> test_peak_under_water = {3, 0, 2, 0, 4};
|
||||
assert(dynamic_programming::trappedRainwater(test_peak_under_water) == 7);
|
||||
|
||||
std::vector<uint32_t> test_bucket = {5, 1, 5};
|
||||
assert(dynamic_programming::trappedRainwater(test_bucket) == 4);
|
||||
|
||||
std::vector<uint32_t> test_skewed_bucket = {4, 1, 5};
|
||||
assert(dynamic_programming::trappedRainwater(test_skewed_bucket) == 3);
|
||||
|
||||
std::vector<uint32_t> test_empty = {};
|
||||
assert(dynamic_programming::trappedRainwater(test_empty) == 0);
|
||||
|
||||
std::vector<uint32_t> test_flat = {0, 0, 0, 0, 0};
|
||||
assert(dynamic_programming::trappedRainwater(test_flat) == 0);
|
||||
|
||||
std::vector<uint32_t> test_no_trapped_water = {1, 1, 2, 4, 0, 0, 0};
|
||||
assert(dynamic_programming::trappedRainwater(test_no_trapped_water) == 0);
|
||||
|
||||
std::vector<uint32_t> test_single_elevation = {5};
|
||||
assert(dynamic_programming::trappedRainwater(test_single_elevation) == 0);
|
||||
|
||||
std::vector<uint32_t> test_two_point_elevation = {5, 1};
|
||||
assert(dynamic_programming::trappedRainwater(test_two_point_elevation) ==
|
||||
0);
|
||||
|
||||
std::vector<uint32_t> test_large_elevation_map_difference = {5, 1, 6, 1,
|
||||
7, 1, 8};
|
||||
assert(dynamic_programming::trappedRainwater(
|
||||
test_large_elevation_map_difference) == 15);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// C++ Program to find height of the tree using bottom-up dynamic programming.
|
||||
|
||||
/*
|
||||
* Given a rooted tree with node 1.
|
||||
* Task is to find the height of the tree.
|
||||
* Example: -
|
||||
* 4
|
||||
* 1 2
|
||||
* 1 3
|
||||
* 2 4
|
||||
* which can be represented as
|
||||
* 1
|
||||
* / \
|
||||
* 2 3
|
||||
* |
|
||||
* 4
|
||||
*
|
||||
* Height of the tree : - 2
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// global declarations
|
||||
// no of nodes max limit.
|
||||
const int MAX = 1e5;
|
||||
// adjacency list
|
||||
std::vector<int> adj[MAX];
|
||||
std::vector<bool> visited;
|
||||
std::vector<int> dp;
|
||||
|
||||
void depth_first_search(int u) {
|
||||
visited[u] = true;
|
||||
int child_height = 1;
|
||||
for (int v : adj[u]) {
|
||||
if (!visited[v]) {
|
||||
depth_first_search(v);
|
||||
|
||||
// select maximum sub-tree height from all children.
|
||||
child_height = std::max(child_height, dp[v] + 1);
|
||||
}
|
||||
}
|
||||
// assigned the max child height to current visited node.
|
||||
dp[u] = child_height;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// number of nodes
|
||||
int number_of_nodes;
|
||||
std::cout << "Enter number of nodes of the tree : " << std::endl;
|
||||
std::cin >> number_of_nodes;
|
||||
|
||||
// u, v denotes an undirected edge of tree.
|
||||
int u, v;
|
||||
// Tree contains exactly n-1 edges where n denotes the number of nodes.
|
||||
std::cout << "Enter edges of the tree : " << std::endl;
|
||||
for (int i = 0; i < number_of_nodes - 1; i++) {
|
||||
std::cin >> u >> v;
|
||||
// undirected tree u -> v and v -> u.
|
||||
adj[u].push_back(v);
|
||||
adj[v].push_back(u);
|
||||
}
|
||||
// initialize all nodes as unvisited.
|
||||
visited.assign(number_of_nodes + 1, false);
|
||||
// initialize depth of all nodes to 0.
|
||||
dp.assign(number_of_nodes + 1, 0);
|
||||
// function call which will initialize the height of all nodes.
|
||||
depth_first_search(1);
|
||||
std::cout << "Height of the Tree : " << dp[1] << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the Unbounded 0/1 Knapsack Problem
|
||||
*
|
||||
* @details
|
||||
* The Unbounded 0/1 Knapsack problem allows taking unlimited quantities of each
|
||||
* item. The goal is to maximize the total value without exceeding the given
|
||||
* knapsack capacity. Unlike the 0/1 knapsack, where each item can be taken only
|
||||
* once, in this variation, any item can be picked any number of times as long
|
||||
* as the total weight stays within the knapsack's capacity.
|
||||
*
|
||||
* Given a set of N items, each with a weight and a value, represented by the
|
||||
* arrays `wt` and `val` respectively, and a knapsack with a weight limit W, the
|
||||
* task is to fill the knapsack to maximize the total value.
|
||||
*
|
||||
* @note weight and value of items is greater than zero
|
||||
*
|
||||
* ### Algorithm
|
||||
* The approach uses dynamic programming to build a solution iteratively.
|
||||
* A 2D array is used for memoization to store intermediate results, allowing
|
||||
* the function to avoid redundant calculations.
|
||||
*
|
||||
* @author [Sanskruti Yeole](https://github.com/yeolesanskruti)
|
||||
* @see dynamic_programming/0_1_knapsack.cpp
|
||||
*/
|
||||
|
||||
#include <cassert> // For using assert function to validate test cases
|
||||
#include <cstdint> // For fixed-width integer types like std::uint16_t
|
||||
#include <iostream> // Standard input-output stream
|
||||
#include <vector> // Standard library for using dynamic arrays (vectors)
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Namespace for dynamic programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @namespace Knapsack
|
||||
* @brief Implementation of unbounded 0-1 knapsack problem
|
||||
*/
|
||||
namespace unbounded_knapsack {
|
||||
|
||||
/**
|
||||
* @brief Recursive function to calculate the maximum value obtainable using
|
||||
* an unbounded knapsack approach.
|
||||
*
|
||||
* @param i Current index in the value and weight vectors.
|
||||
* @param W Remaining capacity of the knapsack.
|
||||
* @param val Vector of values corresponding to the items.
|
||||
* @note "val" data type can be changed according to the size of the input.
|
||||
* @param wt Vector of weights corresponding to the items.
|
||||
* @note "wt" data type can be changed according to the size of the input.
|
||||
* @param dp 2D vector for memoization to avoid redundant calculations.
|
||||
* @return The maximum value that can be obtained for the given index and
|
||||
* capacity.
|
||||
*/
|
||||
std::uint16_t KnapSackFilling(std::uint16_t i, std::uint16_t W,
|
||||
const std::vector<std::uint16_t>& val,
|
||||
const std::vector<std::uint16_t>& wt,
|
||||
std::vector<std::vector<int>>& dp) {
|
||||
if (i == 0) {
|
||||
if (wt[0] <= W) {
|
||||
return (W / wt[0]) *
|
||||
val[0]; // Take as many of the first item as possible
|
||||
} else {
|
||||
return 0; // Can't take the first item
|
||||
}
|
||||
}
|
||||
if (dp[i][W] != -1)
|
||||
return dp[i][W]; // Return result if available
|
||||
|
||||
int nottake =
|
||||
KnapSackFilling(i - 1, W, val, wt, dp); // Value without taking item i
|
||||
int take = 0;
|
||||
if (W >= wt[i]) {
|
||||
take = val[i] + KnapSackFilling(i, W - wt[i], val, wt,
|
||||
dp); // Value taking item i
|
||||
}
|
||||
return dp[i][W] =
|
||||
std::max(take, nottake); // Store and return the maximum value
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wrapper function to initiate the unbounded knapsack calculation.
|
||||
*
|
||||
* @param N Number of items.
|
||||
* @param W Maximum weight capacity of the knapsack.
|
||||
* @param val Vector of values corresponding to the items.
|
||||
* @param wt Vector of weights corresponding to the items.
|
||||
* @return The maximum value that can be obtained for the given capacity.
|
||||
*/
|
||||
std::uint16_t unboundedKnapsack(std::uint16_t N, std::uint16_t W,
|
||||
const std::vector<std::uint16_t>& val,
|
||||
const std::vector<std::uint16_t>& wt) {
|
||||
if (N == 0)
|
||||
return 0; // Expect 0 since no items
|
||||
std::vector<std::vector<int>> dp(
|
||||
N, std::vector<int>(W + 1, -1)); // Initialize memoization table
|
||||
return KnapSackFilling(N - 1, W, val, wt, dp); // Start the calculation
|
||||
}
|
||||
|
||||
} // namespace unbounded_knapsack
|
||||
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief self test implementation
|
||||
* @return void
|
||||
*/
|
||||
static void tests() {
|
||||
// Test Case 1
|
||||
std::uint16_t N1 = 4; // Number of items
|
||||
std::vector<std::uint16_t> wt1 = {1, 3, 4, 5}; // Weights of the items
|
||||
std::vector<std::uint16_t> val1 = {6, 1, 7, 7}; // Values of the items
|
||||
std::uint16_t W1 = 8; // Maximum capacity of the knapsack
|
||||
// Test the function and assert the expected output
|
||||
assert(dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N1, W1, val1, wt1) == 48);
|
||||
std::cout << "Maximum Knapsack value "
|
||||
<< dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N1, W1, val1, wt1)
|
||||
<< std::endl;
|
||||
|
||||
// Test Case 2
|
||||
std::uint16_t N2 = 3; // Number of items
|
||||
std::vector<std::uint16_t> wt2 = {10, 20, 30}; // Weights of the items
|
||||
std::vector<std::uint16_t> val2 = {60, 100, 120}; // Values of the items
|
||||
std::uint16_t W2 = 5; // Maximum capacity of the knapsack
|
||||
// Test the function and assert the expected output
|
||||
assert(dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N2, W2, val2, wt2) == 0);
|
||||
std::cout << "Maximum Knapsack value "
|
||||
<< dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N2, W2, val2, wt2)
|
||||
<< std::endl;
|
||||
|
||||
// Test Case 3
|
||||
std::uint16_t N3 = 3; // Number of items
|
||||
std::vector<std::uint16_t> wt3 = {2, 4, 6}; // Weights of the items
|
||||
std::vector<std::uint16_t> val3 = {5, 11, 13}; // Values of the items
|
||||
std::uint16_t W3 = 27; // Maximum capacity of the knapsack
|
||||
// Test the function and assert the expected output
|
||||
assert(dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N3, W3, val3, wt3) == 27);
|
||||
std::cout << "Maximum Knapsack value "
|
||||
<< dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N3, W3, val3, wt3)
|
||||
<< std::endl;
|
||||
|
||||
// Test Case 4
|
||||
std::uint16_t N4 = 0; // Number of items
|
||||
std::vector<std::uint16_t> wt4 = {}; // Weights of the items
|
||||
std::vector<std::uint16_t> val4 = {}; // Values of the items
|
||||
std::uint16_t W4 = 10; // Maximum capacity of the knapsack
|
||||
assert(dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N4, W4, val4, wt4) == 0);
|
||||
std::cout << "Maximum Knapsack value for empty arrays: "
|
||||
<< dynamic_programming::unbounded_knapsack::unboundedKnapsack(
|
||||
N4, W4, val4, wt4)
|
||||
<< std::endl;
|
||||
|
||||
std::cout << "All test cases passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @return 0 on successful exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // Run self test implementation
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Word Break Problem](https://leetcode.com/problems/word-break/)
|
||||
* @details
|
||||
* Given a non-empty string s and a dictionary wordDict containing a list of
|
||||
* non-empty words, determine if s can be segmented into a space-separated
|
||||
* sequence of one or more dictionary words.
|
||||
*
|
||||
* Note:
|
||||
* The same word in the dictionary may be reused multiple times in the
|
||||
* segmentation. You may assume the dictionary does not contain duplicate words.
|
||||
*
|
||||
* Example 1:
|
||||
* Input: s = "leetcode", wordDict = ["leet", "code"]
|
||||
* Output: true
|
||||
* Explanation: Return true because "leetcode" can be segmented as "leet code".
|
||||
*
|
||||
* Example 2:
|
||||
* Input: s = "applepenapple", wordDict = ["apple", "pen"]
|
||||
* Output: true
|
||||
* Explanation: Return true because "applepenapple" can be segmented as "apple
|
||||
* pen apple". Note that you are allowed to reuse a dictionary word.
|
||||
*
|
||||
* Example 3:
|
||||
* Input: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
|
||||
* Output: false
|
||||
*
|
||||
* @author [Akshay Anand] (https://github.com/axayjha)
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @namespace dynamic_programming
|
||||
* @brief Dynamic programming algorithms
|
||||
*/
|
||||
namespace dynamic_programming {
|
||||
|
||||
/**
|
||||
* @namespace word_break
|
||||
* @brief Functions for [Word Break](https://leetcode.com/problems/word-break/)
|
||||
* problem
|
||||
*/
|
||||
namespace word_break {
|
||||
|
||||
/**
|
||||
* @brief Function that checks if the string passed in param is present in
|
||||
* the the unordered_set passed
|
||||
*
|
||||
* @param str the string to be searched
|
||||
* @param strSet unordered set of string, that is to be looked into
|
||||
* @returns `true` if str is present in strSet
|
||||
* @returns `false` if str is not present in strSet
|
||||
*/
|
||||
bool exists(const std::string &str,
|
||||
const std::unordered_set<std::string> &strSet) {
|
||||
return strSet.find(str) != strSet.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function that checks if the string passed in param can be
|
||||
* segmented from position 'pos', and then correctly go on to segment the
|
||||
* rest of the string correctly as well to reach a solution
|
||||
*
|
||||
* @param s the complete string to be segmented
|
||||
* @param strSet unordered set of string, that is to be used as the
|
||||
* reference dictionary
|
||||
* @param pos the index value at which we will segment string and test
|
||||
* further if it is correctly segmented at pos
|
||||
* @param dp the vector to memoize solution for each position
|
||||
* @returns `true` if a valid solution/segmentation is possible by segmenting at
|
||||
* index pos
|
||||
* @returns `false` otherwise
|
||||
*/
|
||||
bool check(const std::string &s, const std::unordered_set<std::string> &strSet,
|
||||
int pos, std::vector<int> *dp) {
|
||||
if (pos == s.length()) {
|
||||
// if we have reached till the end of the string, means we have
|
||||
// segmented throughout correctly hence we have a solution, thus
|
||||
// returning true
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dp->at(pos) != INT_MAX) {
|
||||
// if dp[pos] is not INT_MAX, means we must have saved a solution
|
||||
// for the position pos; then return if the solution at pos is true
|
||||
// or not
|
||||
return dp->at(pos) == 1;
|
||||
}
|
||||
|
||||
std::string wordTillNow =
|
||||
""; // string to save the prefixes of word till different positons
|
||||
|
||||
for (int i = pos; i < s.length(); i++) {
|
||||
// Loop starting from pos to end, to check valid set of
|
||||
// segmentations if any
|
||||
wordTillNow +=
|
||||
std::string(1, s[i]); // storing the prefix till the position i
|
||||
|
||||
// if the prefix till current position is present in the dictionary
|
||||
// and the remaining substring can also be segmented legally, then
|
||||
// set solution at position pos in the memo, and return true
|
||||
if (exists(wordTillNow, strSet) && check(s, strSet, i + 1, dp)) {
|
||||
dp->at(pos) = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// if function has still not returned, then there must be no legal
|
||||
// segmentation possible after segmenting at pos
|
||||
dp->at(pos) = 0; // so set solution at pos as false
|
||||
return false; // and return no solution at position pos
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function that checks if the string passed in param can be
|
||||
* segmented into the strings present in the vector.
|
||||
* In others words, it checks if any permutation of strings in
|
||||
* the vector can be concatenated to form the final string.
|
||||
*
|
||||
* @param s the complete string to be segmented
|
||||
* @param wordDict a vector of words to be used as dictionary to look into
|
||||
* @returns `true` if s can be formed by a combination of strings present in
|
||||
* wordDict
|
||||
* @return `false` otherwise
|
||||
*/
|
||||
bool wordBreak(const std::string &s, const std::vector<std::string> &wordDict) {
|
||||
// unordered set to store words in the dictionary for constant time
|
||||
// search
|
||||
std::unordered_set<std::string> strSet;
|
||||
for (const auto &s : wordDict) {
|
||||
strSet.insert(s);
|
||||
}
|
||||
// a vector to be used for memoization, whose value at index i will
|
||||
// tell if the string s can be segmented (correctly) at position i.
|
||||
// initializing it with INT_MAX (which will denote no solution)
|
||||
std::vector<int> dp(s.length(), INT_MAX);
|
||||
|
||||
// calling check method with position = 0, to check from left
|
||||
// from where can be start segmenting the complete string in correct
|
||||
// manner
|
||||
return check(s, strSet, 0, &dp);
|
||||
}
|
||||
|
||||
} // namespace word_break
|
||||
} // namespace dynamic_programming
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// the complete string
|
||||
const std::string s = "applepenapple";
|
||||
// the dictionary to be used
|
||||
const std::vector<std::string> wordDict = {"apple", "pen"};
|
||||
|
||||
assert(dynamic_programming::word_break::wordBreak(s, wordDict));
|
||||
|
||||
// should return true, as applepenapple can be segmented as apple + pen +
|
||||
// apple
|
||||
std::cout << dynamic_programming::word_break::wordBreak(s, wordDict)
|
||||
<< std::endl;
|
||||
std::cout << "Test implementation passed!\n";
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // call the test function :)
|
||||
|
||||
// the complete string
|
||||
const std::string s = "applepenapple";
|
||||
// the dictionary to be used
|
||||
const std::vector<std::string> wordDict = {"apple", "pen"};
|
||||
|
||||
// should return true, as applepenapple can be segmented as apple + pen +
|
||||
// apple
|
||||
std::cout << dynamic_programming::word_break::wordBreak(s, wordDict)
|
||||
<< std::endl;
|
||||
}
|
||||
Reference in New Issue
Block a user