-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
498 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
others/longest_substring_without_repeating_characters.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/** | ||
* @file | ||
* @brief Solution for Longest Substring Without Repeating Characters problem. | ||
* @details | ||
* Problem link: https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ | ||
* | ||
* Intuition: | ||
* 1) The intuition is straightforward and simple. We track the frequency of characters. | ||
* 2) Since we can't use a string to track the longest substring without repeating characters efficiently (as removing a character from the front of a string isn't O(1)), we optimize the solution using a deque approach. | ||
* | ||
* Approach: | ||
* 1) Initialize an unordered_map to track the frequency of characters. | ||
* 2) Use a deque for pushing characters, and update the result deque (`res`) with the current deque (`temp`) | ||
* whenever we find a longer substring. | ||
* 3) Use a while loop to reduce the frequency from the front, incrementing `i`, | ||
* and removing characters from the `temp` deque as we no longer need them. | ||
* 4) Return `res.size()` as we are interested in the length of the longest substring. | ||
* | ||
* Time Complexity: O(N) | ||
* Space Complexity: O(N) | ||
* | ||
* I hope this helps to understand. | ||
* Thank you! | ||
* @author [Ashish Kumar Sahoo](github.com/ashish5kmax) | ||
**/ | ||
|
||
#include <iostream> // for IO Operations | ||
#include <unordered_map> // for std::unordered_map | ||
#include <deque> // for std::deque | ||
#include <string> // for string class/string datatype which is taken as input | ||
#include <cassert> // for assert | ||
|
||
/** | ||
* @class Longest_Substring | ||
* @brief Class that solves the Longest Substring Without Repeating Characters problem. | ||
*/ | ||
class Longest_Substring { | ||
public: | ||
/** | ||
* @brief Function to find the length of the longest substring without repeating characters. | ||
* @param s Input string. | ||
* @return Length of the longest substring. | ||
*/ | ||
int lengthOfLongestSubstring(std::string s) { | ||
// If the size of string is 1, then it will be the answer. | ||
if (s.size() == 1) return 1; | ||
|
||
// Map used to store the character frequency. | ||
std::unordered_map<char, int> m; | ||
int n = s.length(); | ||
|
||
// Deque to remove from back if repeating characters are present. | ||
std::deque<char> temp; | ||
std::deque<char> res; | ||
int i, j; | ||
|
||
// Sliding window approach using two pointers. | ||
for (i = 0, j = 0; i < n && j < n;) { | ||
m[s[j]]++; | ||
|
||
// If repeating character found, update result and remove from the front. | ||
if (m[s[j]] > 1) { | ||
if (temp.size() > res.size()) { | ||
res = temp; | ||
} | ||
|
||
while (m[s[j]] > 1) { | ||
temp.pop_front(); | ||
m[s[i]]--; | ||
i++; | ||
} | ||
} | ||
|
||
// Add the current character to the deque. | ||
temp.push_back(s[j]); | ||
j++; | ||
} | ||
|
||
// Final check to update result. | ||
if (temp.size() > res.size()) { | ||
res = temp; | ||
} | ||
|
||
return res.size(); // Return the length of the longest substring. | ||
} | ||
}; | ||
|
||
/** | ||
* @brief Self-test implementations | ||
* @returns void | ||
*/ | ||
static void tests() { | ||
Longest_Substring soln; | ||
assert(soln.lengthOfLongestSubstring("abcabcbb") == 3); | ||
assert(soln.lengthOfLongestSubstring("bbbbb") == 1); | ||
assert(soln.lengthOfLongestSubstring("pwwkew") == 3); | ||
assert(soln.lengthOfLongestSubstring("") == 0); // Test case for empty string | ||
assert(soln.lengthOfLongestSubstring("abcdef") == 6); // Test case for all unique characters | ||
assert(soln.lengthOfLongestSubstring("a") == 1); // Single character | ||
std::cout << "All test cases passed!" << std::endl; | ||
} | ||
|
||
/** | ||
* @brief Main function. | ||
* @return 0 on successful execution. | ||
*/ | ||
int main() { | ||
tests(); // run self-test implementations | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/** | ||
* @file | ||
* @brief [Exponential | ||
* Distribution](https://en.wikipedia.org/wiki/Exponential_distribution) | ||
* | ||
* The exponential distribution is used to model | ||
* events occuring between a Poisson process like radioactive decay. | ||
* | ||
* \f[P(x, \lambda) = \lambda e^{-\lambda x}\f] | ||
* | ||
* Summary of variables used: | ||
* \f$\lambda\f$ : rate parameter | ||
*/ | ||
|
||
#include <cassert> // For assert | ||
#include <cmath> // For std::pow | ||
#include <iostream> // For I/O operation | ||
#include <stdexcept> // For std::invalid_argument | ||
#include <string> // For std::string | ||
|
||
/** | ||
* @namespace probability | ||
* @brief Probability algorithms | ||
*/ | ||
namespace probability { | ||
/** | ||
* @namespace exponential_dist | ||
* @brief Functions for the [Exponential | ||
* Distribution](https://en.wikipedia.org/wiki/Exponential_distribution) | ||
* algorithm implementation | ||
*/ | ||
namespace geometric_dist { | ||
/** | ||
* @brief the expected value of the exponential distribution | ||
* @returns \f[\mu = \frac{1}{\lambda}\f] | ||
*/ | ||
double exponential_expected(double lambda) { | ||
if (lambda <= 0) { | ||
throw std::invalid_argument("lambda must be greater than 0"); | ||
} | ||
return 1 / lambda; | ||
} | ||
|
||
/** | ||
* @brief the variance of the exponential distribution | ||
* @returns \f[\sigma^2 = \frac{1}{\lambda^2}\f] | ||
*/ | ||
double exponential_var(double lambda) { | ||
if (lambda <= 0) { | ||
throw std::invalid_argument("lambda must be greater than 0"); | ||
} | ||
return 1 / pow(lambda, 2); | ||
} | ||
|
||
/** | ||
* @brief the standard deviation of the exponential distribution | ||
* @returns \f[\sigma = \frac{1}{\lambda}\f] | ||
*/ | ||
double exponential_std(double lambda) { | ||
if (lambda <= 0) { | ||
throw std::invalid_argument("lambda must be greater than 0"); | ||
} | ||
return 1 / lambda; | ||
} | ||
} // namespace geometric_dist | ||
} // namespace probability | ||
|
||
/** | ||
* @brief Self-test implementations | ||
* @returns void | ||
*/ | ||
static void test() { | ||
double lambda_1 = 1; | ||
double expected_1 = 1; | ||
double var_1 = 1; | ||
double std_1 = 1; | ||
|
||
double lambda_2 = 2; | ||
double expected_2 = 0.5; | ||
double var_2 = 0.25; | ||
double std_2 = 0.5; | ||
|
||
double lambda_3 = 3; | ||
double expected_3 = 0.333333; | ||
double var_3 = 0.111111; | ||
double std_3 = 0.333333; | ||
|
||
double lambda_4 = 0; // Test 0 | ||
double lambda_5 = -2.3; // Test negative value | ||
|
||
const float threshold = 1e-3f; | ||
|
||
std::cout << "Test for lambda = 1 \n"; | ||
assert( | ||
std::abs(expected_1 - probability::geometric_dist::exponential_expected( | ||
lambda_1)) < threshold); | ||
assert(std::abs(var_1 - probability::geometric_dist::exponential_var( | ||
lambda_1)) < threshold); | ||
assert(std::abs(std_1 - probability::geometric_dist::exponential_std( | ||
lambda_1)) < threshold); | ||
std::cout << "ALL TEST PASSED\n\n"; | ||
|
||
std::cout << "Test for lambda = 2 \n"; | ||
assert( | ||
std::abs(expected_2 - probability::geometric_dist::exponential_expected( | ||
lambda_2)) < threshold); | ||
assert(std::abs(var_2 - probability::geometric_dist::exponential_var( | ||
lambda_2)) < threshold); | ||
assert(std::abs(std_2 - probability::geometric_dist::exponential_std( | ||
lambda_2)) < threshold); | ||
std::cout << "ALL TEST PASSED\n\n"; | ||
|
||
std::cout << "Test for lambda = 3 \n"; | ||
assert( | ||
std::abs(expected_3 - probability::geometric_dist::exponential_expected( | ||
lambda_3)) < threshold); | ||
assert(std::abs(var_3 - probability::geometric_dist::exponential_var( | ||
lambda_3)) < threshold); | ||
assert(std::abs(std_3 - probability::geometric_dist::exponential_std( | ||
lambda_3)) < threshold); | ||
std::cout << "ALL TEST PASSED\n\n"; | ||
|
||
std::cout << "Test for lambda = 0 \n"; | ||
try { | ||
probability::geometric_dist::exponential_expected(lambda_4); | ||
probability::geometric_dist::exponential_var(lambda_4); | ||
probability::geometric_dist::exponential_std(lambda_4); | ||
} catch (std::invalid_argument& err) { | ||
assert(std::string(err.what()) == "lambda must be greater than 0"); | ||
} | ||
std::cout << "ALL TEST PASSED\n\n"; | ||
|
||
std::cout << "Test for lambda = -2.3 \n"; | ||
try { | ||
probability::geometric_dist::exponential_expected(lambda_5); | ||
probability::geometric_dist::exponential_var(lambda_5); | ||
probability::geometric_dist::exponential_std(lambda_5); | ||
} catch (std::invalid_argument& err) { | ||
assert(std::string(err.what()) == "lambda must be greater than 0"); | ||
} | ||
std::cout << "ALL TEST PASSED\n\n"; | ||
} | ||
|
||
/** | ||
* @brief Main function | ||
* @return 0 on exit | ||
*/ | ||
int main() { | ||
test(); // Self test implementation | ||
return 0; | ||
} |
Oops, something went wrong.