From ab8713fbebbb844530531c12518f4a23adb15766 Mon Sep 17 00:00:00 2001 From: sjain1909 Date: Fri, 19 Jul 2024 12:57:32 +0530 Subject: [PATCH 1/2] Adding solution ok KMP algorithm ## Fixing Issue #3543 ## Description This pull request adds the implementation of the Knuth-Morris-Pratt (KMP) algorithm in C++ to the DSA folder. The KMP algorithm is used for pattern matching and is efficient in finding occurrences of a pattern within a text. It preprocesses the pattern to create a partial match table, which allows the algorithm to skip unnecessary comparisons, improving the overall search time. ## Type of PR - [ ] Bug fix - [x] Feature enhancement - [ ] Documentation update - [ ] Security enhancement - [ ] Other (specify): _______________ ## Checklist - [x] I have performed a self-review of my code. - [x] I have read and followed the Contribution Guidelines. - [x] I have tested the changes thoroughly before submitting this pull request. - [x] I have provided relevant issue numbers, screenshots, and videos after making the changes. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have followed the code style guidelines of this project. - [x] I have checked for any existing open issues that my pull request may address. - [x] I have ensured that my changes do not break any existing functionality. - [x] Each contributor is allowed to create a maximum of 4 issues per day. This helps us manage and address issues efficiently. - [x] I have read the resources for guidance listed below. - [x] I have followed security best practices in my code changes. ## Additional Context The Knuth-Morris-Pratt (KMP) algorithm implementation includes the following features: - Preprocessing of the pattern to create a partial match (or "failure") table. - Efficient pattern searching within a text using the preprocessed table. - Skipping of unnecessary comparisons, resulting in improved search time compared to naive string matching algorithms. ## Resources for Guidance Please read the following resources before submitting your contribution: - [x] [Code Harbor Hub Community Features](https://www.codeharborhub.live/community/features) - [x] [Markdown Guide](https://www.markdownguide.org/) --- .../0400-0499/0493-reverse-pairs.md | 496 ++++++++++++------ dsa/Advance/knuth-morris-pratt.md | 137 +++++ 2 files changed, 461 insertions(+), 172 deletions(-) create mode 100644 dsa/Advance/knuth-morris-pratt.md diff --git a/dsa-solutions/lc-solutions/0400-0499/0493-reverse-pairs.md b/dsa-solutions/lc-solutions/0400-0499/0493-reverse-pairs.md index ab99d358c..861effb08 100644 --- a/dsa-solutions/lc-solutions/0400-0499/0493-reverse-pairs.md +++ b/dsa-solutions/lc-solutions/0400-0499/0493-reverse-pairs.md @@ -1,172 +1,324 @@ ---- -id: reverse-pairs -title: Reverse Pairs -sidebar_label: 0493 - Reverse Pairs -tags: - - Leetcode - - Merge Sort ---- - -## Problem Statement - -Given an integer array `nums`, return the number of reverse pairs in the array. - -A reverse pair is defined as a pair `(i, j)` where: - -- $0 <= i < j < nums.length and$ -- $nums[i] > 2 * nums[j].$ - -## Examples - -### Example 1 - -- Input: `nums = [1,3,2,3,1]` -- Output: `2` -- Explanation: The reverse pairs are: - - `(1, 4)` -> `nums[1] = 3`, `nums[4] = 1`, `3 > 2 * 1` - - `(3, 4)` -> `nums[3] = 3`, `nums[4] = 1`, `3 > 2 * 1` - -### Example 2 - -- Input: `nums = [2,4,3,5,1]` -- Output: `3` -- Explanation: The reverse pairs are: - - `(1, 4)` -> `nums[1] = 4`, `nums[4] = 1`, `4 > 2 * 1` - - `(2, 4)` -> `nums[2] = 3`, `nums[4] = 1`, `3 > 2 * 1` - - `(3, 4)` -> `nums[3] = 5`, `nums[4] = 1`, `5 > 2 * 1` - -## Constraints - -- $1 <= nums.length <= 5 * 104$ -- $-231 <= nums[i] <= 231 - 1$ - -## Algorithm - -To solve this problem efficiently, we can use a modified merge sort algorithm, which not only sorts the array but also counts the number of reverse pairs during the merging process. The idea is to leverage the divide-and-conquer approach to count pairs in `O(n log n)` time complexity. - -### Steps: - -1. **Divide**: Split the array into two halves. -2. **Count**: Count the reverse pairs in each half recursively. -3. **Merge and Count**: While merging the two halves, count the reverse pairs where one element is from the left half and the other is from the right half. - -## Code - -### Python - -```python -class Solution: - def reversePairs(self, nums: List[int]) -> int: - def merge_sort(nums, l, r): - if l >= r: - return 0 - - mid = (l + r) // 2 - count = merge_sort(nums, l, mid) + merge_sort(nums, mid + 1, r) - - j = mid + 1 - for i in range(l, mid + 1): - while j <= r and nums[i] > 2 * nums[j]: - j += 1 - count += j - (mid + 1) - - nums[l:r + 1] = sorted(nums[l:r + 1]) - return count - - return merge_sort(nums, 0, len(nums) - 1) -``` - -### C++ - -```cpp -#include -using namespace std; - -class Solution { -public: - int reversePairs(vector& nums) { - return reversePairsSub(nums, 0, nums.size() - 1); - } - -private: - int reversePairsSub(vector& nums, int l, int r) { - if (l >= r) return 0; - - int m = l + ((r - l) >> 1); - int res = reversePairsSub(nums, l, m) + reversePairsSub(nums, m + 1, r); - - int i = l, j = m + 1, k = 0, p = m + 1; - vector merge(r - l + 1); - - while (i <= m) { - while (p <= r && nums[i] > 2L * nums[p]) p++; - res += p - (m + 1); - - while (j <= r && nums[i] >= nums[j]) merge[k++] = nums[j++]; - merge[k++] = nums[i++]; - } - - while (j <= r) merge[k++] = nums[j++]; - - copy(merge.begin(), merge.end(), nums.begin() + l); - - return res; - } -}; -``` - -### Java - -```java -import java.util.Arrays; - -class Solution { - public int reversePairs(int[] nums) { - return mergeSort(nums, 0, nums.length - 1); - } - - private int mergeSort(int[] nums, int left, int right) { - if (left >= right) return 0; - - int mid = left + (right - left) / 2; - int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); - - int j = mid + 1; - for (int i = left; i <= mid; i++) { - while (j <= right && nums[i] > 2L * nums[j]) j++; - count += j - (mid + 1); - } - - Arrays.sort(nums, left, right + 1); - return count; - } -} -``` - -### JavaScript - -```javascript -var reversePairs = function (nums) { - function mergeSort(nums, left, right) { - if (left >= right) return 0; - - let mid = left + Math.floor((right - left) / 2); - let count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); - - let j = mid + 1; - for (let i = left; i <= mid; i++) { - while (j <= right && nums[i] > 2 * nums[j]) j++; - count += j - (mid + 1); - } - - nums.splice( - left, - right - left + 1, - ...nums.slice(left, right + 1).sort((a, b) => a - b) - ); - return count; - } - - return mergeSort(nums, 0, nums.length - 1); -}; -``` +--- +id: reverse-pairs +title: Reverse Pairs +sidebar_label: 493-Reverse-Pairs +tags: + - Array + - Binary Search + - Divide and conquer + - Binary Indexed Tree + - Segment Tree + - Merge Sort + - Ordered Set +description: The problem is to reverse the pairs. +sidebar_position: 2667 +--- + +## Problem Statement + +### Problem Description + +Given an integer array `nums`, return the number of reverse pairs in the array. + +A reverse pair is a pair `(i, j)` where: + +`0 <= i < j < nums.length` and +`nums[i] > 2 * nums[j]`. + +### Examples + +**Example 1:** + +``` +Input: nums = [1,3,2,3,1] +Output: 2 +Explanation: The reverse pairs are: +(1, 4) --> nums[1] = 3, nums[4] = 1, 3 > 2 * 1 +(3, 4) --> nums[3] = 3, nums[4] = 1, 3 > 2 * 1 +``` + +**Example 2:** + +``` +Input: nums = [2,4,3,5,1] +Output: 3 +Explanation: The reverse pairs are: +(1, 4) --> nums[1] = 4, nums[4] = 1, 4 > 2 * 1 +(2, 4) --> nums[2] = 3, nums[4] = 1, 3 > 2 * 1 +(3, 4) --> nums[3] = 5, nums[4] = 1, 5 > 2 * 1 +``` + +### Constraints + +- `1 <= nums.length <= 5 * 10^4` + +## Solution of Given Problem + +### Intuition and Approach + +The intuition behind this solution is to use a modified Merge Sort algorithm to count the number of reverse pairs in the array. + + +### Approaches + +- Divide the array into smaller subarrays until each subarray has only one element. +- Merge the subarrays back together, counting the number of reverse pairs between each pair of subarrays. +- The merge step is done in a way that ensures the count of reverse pairs is accurate. + + +#### Codes in Different Languages + + + + + ```javascript + function mergeSortedArrays(nums, left, mid, right, temp) { + let i = left, j = mid + 1, k = 0; + while (i <= mid && j <= right) { + if (nums[i] <= nums[j]) temp[k++] = nums[i++]; + else temp[k++] = nums[j++]; + } + while (i <= mid) temp[k++] = nums[i++]; + while (j <= right) temp[k++] = nums[j++]; +} + +function merge(nums, left, mid, right) { + let count = 0; + let j = mid + 1; + for (let i = left; i <= mid; i++) { + while (j <= right && nums[i] > 2 * nums[j]) j++; + count += j - mid - 1; + } + let temp = new Array(right - left + 1); + mergeSortedArrays(nums, left, mid, right, temp); + for (let i = left; i <= right; i++) nums[i] = temp[i - left]; + return count; +} +function mergeSort(nums, left, right) { + if (left >= right) return 0; + let mid = left + (right - left) / 2; + let count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + count += merge(nums, left, mid, right); + return count; +} + +class Solution { + reversePairs(nums) { + return mergeSort(nums, 0, nums.length - 1); + } +} + + + ``` + + + + + ```typescript + function mergeSortedArrays(nums: number[], left: number, mid: number, right: number, temp: number[]) { + let i = left, j = mid + 1, k = 0; + while (i <= mid && j <= right) { + if (nums[i] <= nums[j]) temp[k++] = nums[i++]; + else temp[k++] = nums[j++]; + } + while (i <= mid) temp[k++] = nums[i++]; + while (j <= right) temp[k++] = nums[j++]; +} + +function merge(nums: number[], left: number, mid: number, right: number) { + let count = 0; + let j = mid + 1; + for (let i = left; i <= mid; i++) { + while (j <= right && nums[i] > 2 * nums[j]) j++; + count += j - mid - 1; + } + let temp = new Array(right - left + 1); + mergeSortedArrays(nums, left, mid, right, temp); + for (let i = left; i <= right; i++) nums[i] = temp[i - left]; + return count; +} +function mergeSort(nums: number[], left: number, right: number) { + if (left >= right) return 0; + let mid = left + (right - left) / 2; + let count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + count += merge(nums, left, mid, right); + return count; +} + +class Solution { + reversePairs(nums: number[]) { + return mergeSort(nums, 0, nums.length - 1); + } +} + + ``` + + + + + ```python + def merge_sorted_arrays(nums, left, mid, right, temp): + i, j, k = left, mid + 1, 0 + while i <= mid and j <= right: + if nums[i] <= nums[j]: + temp[k] = nums[i] + i += 1 + else: + temp[k] = nums[j] + j += 1 + k += 1 + while i <= mid: + temp[k] = nums[i] + i += 1 + k += 1 + while j <= right: + temp[k] = nums[j] + j += 1 + k += 1 + +def merge(nums, left, mid, right): + count = 0 + j = mid + 1 + for i in range(left, mid + 1): + while j <= right and nums[i] > 2 * nums[j]: + j += 1 + count += j - mid - 1 + temp = [0] * (right - left + 1) + merge_sorted_arrays(nums, left, mid, right, temp) + for i in range(left, right + 1): + nums[i] = temp[i - left] + return count + +def merge_sort(nums, left, right): + if left >= right: + return 0 + mid = left + (right - left) // 2 + count = merge_sort(nums, left, mid) + merge_sort(nums, mid + 1, right) + count += merge(nums, left, mid, right) + return count + +class Solution: + def reversePairs(self, nums): + return merge_sort(nums, 0, len(nums) - 1) + + ``` + + + + + ```java + public class Solution { + public int reversePairs(int[] nums) { + return mergeSort(nums, 0, nums.length - 1); + } + + public int mergeSort(int[] nums, int left, int right) { + if (left >= right) { + return 0; + } + int mid = left + (right - left) / 2; + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + count += merge(nums, left, mid, right); + return count; + } + public int merge(int[] nums, int left, int mid, int right) { + int count = 0; + int j = mid + 1; + for (int i = left; i <= mid; i++) { + while (j <= right && nums[i] > 2 * nums[j]) { + j++; + } + count += j - mid - 1; + } + int[] temp = new int[right - left + 1]; + mergeSortedArrays(nums, left, mid, right, temp); + for (int i = left; i <= right; i++) { + nums[i] = temp[i - left]; + } + return count; + } + + public void + mergeSortedArrays(int[] nums, int left, int mid, int right, int[] temp) { + int i = left, j = mid + 1, k = 0; + while (i <= mid && j <= right) { + if (nums[i] <= nums[j]) { + temp[k++] = nums[i++]; + } else { + temp[k++] = nums[j++]; + } + } + while (i <= mid) { + temp[k++] = nums[i++]; + } + while (j <= right) { + temp[k++] = nums[j++]; + } + } +} + + ``` + + + + ```cpp + void mergeSortedArrays(vector& nums, int left, int mid, int right, vector& temp) { + int i = left, j = mid + 1, k = 0; + while (i <= mid && j <= right) { + if (nums[i] <= nums[j]) temp[k++] = nums[i++]; + else temp[k++] = nums[j++]; + } + while (i <= mid) temp[k++] = nums[i++]; + while (j <= right) temp[k++] = nums[j++]; +} +int merge(vector& nums, int left, int mid, int right) { + int count = 0; + int j = mid + 1; + for (int i = left; i <= mid; i++) { + while (j <= right && nums[i] > 2 * nums[j]) j++; + count += j - mid - 1; + } + vector temp(right - left + 1); + mergeSortedArrays(nums, left, mid, right, temp); + for (int i = left; i <= right; i++) nums[i] = temp[i - left]; + return count; +} +int mergeSort(vector& nums, int left, int right) { + if (left >= right) return 0; + int mid = left + (right - left) / 2; + int count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right); + count += merge(nums, left, mid, right); + return count; +} + + +class Solution { +public: + int reversePairs(vector& nums) { + return mergeSort(nums, 0, nums.size() - 1); + + + } +}; + ``` + + + +### Complexity Analysis + +- **Time Complexity**: $$O(n*log(n))$$, where n is the length of the input array. This is because the solution uses a modified Merge Sort algorithm, which has a time complexity of O(n log n). + + +- **Space Complexity**: $$O(n)$$, where n is the length of the input array. This is because the solution uses a temporary array to store the merged sorted arrays. + + + +--- + +

Authors:

+ +
+{['Ishitamukherjee2004', 'ImmidiSivani'].map(username => ( + +))} +
diff --git a/dsa/Advance/knuth-morris-pratt.md b/dsa/Advance/knuth-morris-pratt.md new file mode 100644 index 000000000..788119187 --- /dev/null +++ b/dsa/Advance/knuth-morris-pratt.md @@ -0,0 +1,137 @@ +--- +id: knuth-morris-pratt +title: Knuth-Morris-Pratt (KMP) Algorithm +sidebar_label: 0006 - Knuth-Morris-Pratt Algorithm +tags: [KMP, String Matching, Algorithm, C++, Problem Solving] +description: This is a solution for implementing the Knuth-Morris-Pratt (KMP) algorithm for efficient substring searching and pattern matching. +--- + +## Problem Statement + +### Problem Description + +The Knuth-Morris-Pratt (KMP) algorithm is an efficient string searching algorithm that improves the performance of substring searches within a main string. The algorithm preprocesses the pattern to create a partial match table (also known as the "lps" array), which is used to skip unnecessary comparisons during the search process. + +### Examples + +**Example 1:** + +```plaintext +Input: +Text: "abxabcabcaby" +Pattern: "abcaby" +Output: +Pattern found at index 6 +``` + +### Constraints + +- The length of the text and the pattern can be up to 10^5. + +## Solution of Given Problem + +### Intuition and Approach + +The KMP algorithm follows these steps: + +1. Preprocessing the Pattern: Compute the longest proper prefix which is also a suffix (lps) array. +2. Searching the Text: Use the lps array to skip characters in the text while matching the pattern. + +### Approaches + +#### Codes in Different Languages + + + + + ```cpp +#include +using namespace std; +void computeLPSArray(string& pat, int M, vector& lps) { + int length = 0; + lps[0] = 0; + int i = 1; + + while (i < M) { + if (pat[i] == pat[length]) { + length++; + lps[i] = length; + i++; + } else { + if (length != 0) { + length = lps[length - 1]; + } else { + lps[i] = 0; + i++; + } + } + } +} + +void KMPSearch(string& pat, string& txt) { + int M = pat.length(); + int N = txt.length(); + + vector lps(M); + + computeLPSArray(pat, M, lps); + + int i = 0; + int j = 0; + while (i < N) { + if (pat[j] == txt[i]) { + j++; + i++; + } + + if (j == M) { + cout << "Pattern found at index " << i - j << "\n"; + j = lps[j - 1]; + } else if (i < N && pat[j] != txt[i]) { + if (j != 0) { + j = lps[j - 1]; + } else { + i++; + } + } + } +} + +int main() { + string txt, pat; + cout << "Enter the text: "; + cin >> txt; + cout << "Enter the pattern: "; + cin >> pat; + + KMPSearch(pat, txt); + + return 0; +} + ``` + + + +### Complexity Analysis + +- **Time Complexity:** $O(N + M)$ where N is the length of the text and M is the length of the pattern. +- **Space Complexity:** $O(M)$ for the lps array. + +## Video Explanation of Given Problem + + +--- + +

Authors:

+ +
+{['sjain1909'].map(username => ( + +))} +
From 3eff0841d69d78718b94e183a7c2a642f54fafd5 Mon Sep 17 00:00:00 2001 From: Ajay Dhangar <99037494+Ajay-Dhangar@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:32:30 +0530 Subject: [PATCH 2/2] Update 0493-reverse-pairs.md