From 43455d1b56fdbd35a291999f94303373c1c5ee59 Mon Sep 17 00:00:00 2001 From: Yogesh Vishwakarma Date: Tue, 4 Jun 2024 17:08:51 +0530 Subject: [PATCH 1/6] Added two-pointer-technique.md and updated index.md --- contrib/ds-algorithms/index.md | 1 + .../ds-algorithms/two-pointer-technique.md | 134 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 contrib/ds-algorithms/two-pointer-technique.md diff --git a/contrib/ds-algorithms/index.md b/contrib/ds-algorithms/index.md index 1d7293b..52293d9 100644 --- a/contrib/ds-algorithms/index.md +++ b/contrib/ds-algorithms/index.md @@ -13,3 +13,4 @@ - [Stacks in Python](stacks.md) - [Sliding Window Technique](sliding-window.md) - [Trie](trie.md) +- [Two Pointer Technique](two-pointer-technique.md) diff --git a/contrib/ds-algorithms/two-pointer-technique.md b/contrib/ds-algorithms/two-pointer-technique.md new file mode 100644 index 0000000..cec588f --- /dev/null +++ b/contrib/ds-algorithms/two-pointer-technique.md @@ -0,0 +1,134 @@ +# Two-Pointer Technique + +--- + +- The two-pointer technique is a popular algorithmic strategy used to solve various problems efficiently. This technique involves using two pointers (or indices) to traverse through data structures such as arrays or linked lists. +- The pointers can move in different directions, allowing for efficient processing of elements to achieve the desired results. + +## Common Use Cases + +1. **Finding pairs in a sorted array that sum to a target**: One pointer starts at the beginning and the other at the end. +2. **Reversing a linked list**: One pointer starts at the head, and the other at the next node, progressing through the list. +3. **Removing duplicates from a sorted array**: One pointer keeps track of the unique elements, and the other traverses the array. +4. **Merging two sorted arrays**: Two pointers are used to iterate through the arrays and merge them. + +## Example 1: Finding Pairs with a Given Sum + +### Problem Statement + +Given a sorted array of integers and a target sum, find all pairs in the array that sum up to the target. + +### Approach + +1. Initialize two pointers: one at the beginning (`left`) and one at the end (`right`) of the array. +2. Calculate the sum of the elements at the `left` and `right` pointers. +3. If the sum is equal to the target, record the pair and move both pointers inward. +4. If the sum is less than the target, move the `left` pointer to the right to increase the sum. +5. If the sum is greater than the target, move the `right` pointer to the left to decrease the sum. +6. Repeat the process until the `left` pointer is not less than the `right` pointer. + +### Example Code + +```python +def find_pairs_with_sum(arr, target): + left = 0 + right = len(arr) - 1 + pairs = [] + + while left < right: + current_sum = arr[left] + arr[right] + + if current_sum == target: + pairs.append((arr[left], arr[right])) + left += 1 + right -= 1 + elif current_sum < target: + left += 1 + else: + right -= 1 + + return pairs + +# Example usage +arr = [1, 2, 3, 4, 5, 6, 7, 8, 9] +target = 10 +result = find_pairs_with_sum(arr, target) +print("Pairs with sum", target, "are:", result) + ``` + +## Example 2: Removing Duplicates from a Sorted Array + +### Problem Statement +Given a sorted array, remove the duplicates in place such that each element appears only once and return the new length of the array. + +### Approach +1. If the array is empty, return 0. +2. Initialize a slow pointer at the beginning of the array. +3. Use a fast pointer to traverse through the array. +4. Whenever the element at the fast pointer is different from the element at the slow pointer, increment the slow pointer and update the element at the slow pointer with the element at the fast pointer. +5. Continue this process until the fast pointer reaches the end of the array. +6. The slow pointer will indicate the position of the last unique element. + +### Example Code + +```python +def remove_duplicates(arr): + if not arr: + return 0 + + slow = 0 + + for fast in range(1, len(arr)): + if arr[fast] != arr[slow]: + slow += 1 + arr[slow] = arr[fast] + + return slow + 1 + +# Example usage +arr = [1, 1, 2, 2, 3, 4, 4, 5] +new_length = remove_duplicates(arr) +print("Array after removing duplicates:", arr[:new_length]) +print("New length of array:", new_length) +``` +# Advantages of the Two-Pointer Technique + +Here are some key benefits of using the two-pointer technique: + +## 1. **Improved Time Complexity** + +It often reduces the time complexity from O(n^2) to O(n), making it significantly faster for many problems. + +### Example +- **Finding pairs with a given sum**: Efficiently finds pairs in O(n) time. + +## 2. **Simplicity** + +The implementation is straightforward, using basic operations like incrementing or decrementing pointers. + +### Example +- **Removing duplicates from a sorted array**: Easy to implement and understand. + +## 3. **In-Place Solutions** + +Many problems can be solved in place, requiring no extra space beyond the input data. + +### Example +- **Reversing a linked list**: Adjusts pointers within the existing nodes. + +## 4. **Versatility** + +Applicable to a wide range of problems, from arrays and strings to linked lists. + +### Example +- **Merging two sorted arrays**: Efficiently merges using two pointers. + +## 5. **Efficiency** + +Minimizes redundant operations and enhances performance, especially with large data sets. + +### Example +- **Partitioning problems**: Efficiently partitions elements with minimal operations. + + +These advantages make the two-pointer technique a valuable approach for many algorithmic challenges. From a4c93b95adbca63d75c05d5754ea81e540cba34c Mon Sep 17 00:00:00 2001 From: Yogesh Vishwakarma <103316955+Yogeshkarma@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:13:27 +0530 Subject: [PATCH 2/6] Update two-pointer-technique.md Removed the footer line --- contrib/ds-algorithms/two-pointer-technique.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/contrib/ds-algorithms/two-pointer-technique.md b/contrib/ds-algorithms/two-pointer-technique.md index cec588f..6b8720a 100644 --- a/contrib/ds-algorithms/two-pointer-technique.md +++ b/contrib/ds-algorithms/two-pointer-technique.md @@ -130,5 +130,3 @@ Minimizes redundant operations and enhances performance, especially with large d ### Example - **Partitioning problems**: Efficiently partitions elements with minimal operations. - -These advantages make the two-pointer technique a valuable approach for many algorithmic challenges. From b3c31ea9499b068a41c10d2a444edb3c439eae5c Mon Sep 17 00:00:00 2001 From: Yogesh Vishwakarma Date: Tue, 4 Jun 2024 19:57:15 +0530 Subject: [PATCH 3/6] added Universal-Functions.md and updated the index.md --- contrib/numpy/Universal-Functions.md | 130 +++++++++++++++++++++++++++ contrib/numpy/index.md | 1 + 2 files changed, 131 insertions(+) create mode 100644 contrib/numpy/Universal-Functions.md diff --git a/contrib/numpy/Universal-Functions.md b/contrib/numpy/Universal-Functions.md new file mode 100644 index 0000000..a06b0d1 --- /dev/null +++ b/contrib/numpy/Universal-Functions.md @@ -0,0 +1,130 @@ +# Universal functions (ufunc) + +--- + +A `ufunc`, short for "`universal function`," is a fundamental concept in NumPy, a powerful library for numerical computing in Python. Universal functions are highly optimized, element-wise functions designed to perform operations on data stored in NumPy arrays. + + + +## Uses of Ufuncs in NumPy + +Universal functions (ufuncs) in NumPy provide a wide range of functionalities for efficient and powerful numerical computations. Below is a detailed explanation of their uses: + +### 1. **Element-wise Operations** +Ufuncs perform operations on each element of the arrays independently. + +```python +import numpy as np + +A = np.array([1, 2, 3, 4]) +B = np.array([5, 6, 7, 8]) + +# Element-wise addition +np.add(A, B) # Output: array([ 6, 8, 10, 12]) +``` + +### 2. **Broadcasting** +Ufuncs support broadcasting, allowing operations on arrays with different shapes, making it possible to perform operations without explicitly reshaping arrays. + +```python +C = np.array([1, 2, 3]) +D = np.array([[1], [2], [3]]) + +# Broadcasting addition +np.add(C, D) # Output: array([[2, 3, 4], [3, 4, 5], [4, 5, 6]]) +``` + +### 3. **Vectorization** +Ufuncs are vectorized, meaning they are implemented in low-level C code, allowing for fast execution and avoiding the overhead of Python loops. + +```python +# Vectorized square root +np.sqrt(A) # Output: array([1., 1.41421356, 1.73205081, 2.]) +``` + +### 4. **Type Flexibility** +Ufuncs handle various data types and perform automatic type casting as needed. + +```python +E = np.array([1.0, 2.0, 3.0]) +F = np.array([4, 5, 6]) + +# Addition with type casting +np.add(E, F) # Output: array([5., 7., 9.]) +``` + +### 5. **Reduction Operations** +Ufuncs support reduction operations, such as summing all elements of an array or finding the product of all elements. + +```python +# Summing all elements +np.add.reduce(A) # Output: 10 + +# Product of all elements +np.multiply.reduce(A) # Output: 24 +``` + +### 6. **Accumulation Operations** +Ufuncs can perform accumulation operations, which keep a running tally of the computation. + +```python +# Cumulative sum +np.add.accumulate(A) # Output: array([ 1, 3, 6, 10]) +``` + +### 7. **Reduceat Operations** +Ufuncs can perform segmented reductions using the `reduceat` method, which applies the ufunc at specified intervals. + +```python +G = np.array([0, 1, 2, 3, 4, 5, 6, 7]) +indices = [0, 2, 5] +np.add.reduceat(G, indices) # Output: array([ 1, 9, 18]) +``` + +### 8. **Outer Product** +Ufuncs can compute the outer product of two arrays, producing a matrix where each element is the result of applying the ufunc to each pair of elements from the input arrays. + +```python +# Outer product +np.multiply.outer([1, 2, 3], [4, 5, 6]) +# Output: array([[ 4, 5, 6], +# [ 8, 10, 12], +# [12, 15, 18]]) +``` + +### 9. **Out Parameter** +Ufuncs can use the `out` parameter to store results in a pre-allocated array, saving memory and improving performance. + +```python +result = np.empty_like(A) +np.multiply(A, B, out=result) # Output: array([ 5, 12, 21, 32]) +``` + +# Create Your Own Ufunc + +You can create custom ufuncs for specific needs using np.frompyfunc or np.vectorize, allowing Python functions to behave like ufuncs. + +Here, we are using `frompyfunc()` which takes three argument: + +1. function - the name of the function. +2. inputs - the number of input (arrays). +3. outputs - the number of output arrays. + +```python +def my_add(x, y): + return x + y + +my_add_ufunc = np.frompyfunc(my_add, 2, 1) +my_add_ufunc(A, B) # Output: array([ 6, 8, 10, 12], dtype=object) +``` +# Some Common Ufunc are + +Here are some commonly used ufuncs in NumPy: + +- **Arithmetic**: `np.add`, `np.subtract`, `np.multiply`, `np.divide` +- **Trigonometric**: `np.sin`, `np.cos`, `np.tan` +- **Exponential and Logarithmic**: `np.exp`, `np.log`, `np.log10` +- **Comparison**: `np.maximum`, `np.minimum`, `np.greater`, `np.less` +- **Logical**: `np.logical_and`, `np.logical_or`, `np.logical_not` + +For more such Ufunc, address to [Universal functions (ufunc) — NumPy](https://numpy.org/doc/stable/reference/ufuncs.html) \ No newline at end of file diff --git a/contrib/numpy/index.md b/contrib/numpy/index.md index 50e8046..2b0c357 100644 --- a/contrib/numpy/index.md +++ b/contrib/numpy/index.md @@ -11,3 +11,4 @@ - [Sorting NumPy Arrays](sorting-array.md) - [NumPy Array Iteration](array-iteration.md) - [Concatenation of Arrays](concatenation-of-arrays.md) +- [Universal Functions (Ufunc)](Universal-Functions.md) From 0eefe006fadf5646c0be4c8283743ae6051ea5c0 Mon Sep 17 00:00:00 2001 From: Yogesh Vishwakarma <103316955+Yogeshkarma@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:07:56 +0530 Subject: [PATCH 4/6] Delete contrib/numpy/Universal-Functions.md for creating two PR separately --- contrib/numpy/Universal-Functions.md | 130 --------------------------- 1 file changed, 130 deletions(-) delete mode 100644 contrib/numpy/Universal-Functions.md diff --git a/contrib/numpy/Universal-Functions.md b/contrib/numpy/Universal-Functions.md deleted file mode 100644 index a06b0d1..0000000 --- a/contrib/numpy/Universal-Functions.md +++ /dev/null @@ -1,130 +0,0 @@ -# Universal functions (ufunc) - ---- - -A `ufunc`, short for "`universal function`," is a fundamental concept in NumPy, a powerful library for numerical computing in Python. Universal functions are highly optimized, element-wise functions designed to perform operations on data stored in NumPy arrays. - - - -## Uses of Ufuncs in NumPy - -Universal functions (ufuncs) in NumPy provide a wide range of functionalities for efficient and powerful numerical computations. Below is a detailed explanation of their uses: - -### 1. **Element-wise Operations** -Ufuncs perform operations on each element of the arrays independently. - -```python -import numpy as np - -A = np.array([1, 2, 3, 4]) -B = np.array([5, 6, 7, 8]) - -# Element-wise addition -np.add(A, B) # Output: array([ 6, 8, 10, 12]) -``` - -### 2. **Broadcasting** -Ufuncs support broadcasting, allowing operations on arrays with different shapes, making it possible to perform operations without explicitly reshaping arrays. - -```python -C = np.array([1, 2, 3]) -D = np.array([[1], [2], [3]]) - -# Broadcasting addition -np.add(C, D) # Output: array([[2, 3, 4], [3, 4, 5], [4, 5, 6]]) -``` - -### 3. **Vectorization** -Ufuncs are vectorized, meaning they are implemented in low-level C code, allowing for fast execution and avoiding the overhead of Python loops. - -```python -# Vectorized square root -np.sqrt(A) # Output: array([1., 1.41421356, 1.73205081, 2.]) -``` - -### 4. **Type Flexibility** -Ufuncs handle various data types and perform automatic type casting as needed. - -```python -E = np.array([1.0, 2.0, 3.0]) -F = np.array([4, 5, 6]) - -# Addition with type casting -np.add(E, F) # Output: array([5., 7., 9.]) -``` - -### 5. **Reduction Operations** -Ufuncs support reduction operations, such as summing all elements of an array or finding the product of all elements. - -```python -# Summing all elements -np.add.reduce(A) # Output: 10 - -# Product of all elements -np.multiply.reduce(A) # Output: 24 -``` - -### 6. **Accumulation Operations** -Ufuncs can perform accumulation operations, which keep a running tally of the computation. - -```python -# Cumulative sum -np.add.accumulate(A) # Output: array([ 1, 3, 6, 10]) -``` - -### 7. **Reduceat Operations** -Ufuncs can perform segmented reductions using the `reduceat` method, which applies the ufunc at specified intervals. - -```python -G = np.array([0, 1, 2, 3, 4, 5, 6, 7]) -indices = [0, 2, 5] -np.add.reduceat(G, indices) # Output: array([ 1, 9, 18]) -``` - -### 8. **Outer Product** -Ufuncs can compute the outer product of two arrays, producing a matrix where each element is the result of applying the ufunc to each pair of elements from the input arrays. - -```python -# Outer product -np.multiply.outer([1, 2, 3], [4, 5, 6]) -# Output: array([[ 4, 5, 6], -# [ 8, 10, 12], -# [12, 15, 18]]) -``` - -### 9. **Out Parameter** -Ufuncs can use the `out` parameter to store results in a pre-allocated array, saving memory and improving performance. - -```python -result = np.empty_like(A) -np.multiply(A, B, out=result) # Output: array([ 5, 12, 21, 32]) -``` - -# Create Your Own Ufunc - -You can create custom ufuncs for specific needs using np.frompyfunc or np.vectorize, allowing Python functions to behave like ufuncs. - -Here, we are using `frompyfunc()` which takes three argument: - -1. function - the name of the function. -2. inputs - the number of input (arrays). -3. outputs - the number of output arrays. - -```python -def my_add(x, y): - return x + y - -my_add_ufunc = np.frompyfunc(my_add, 2, 1) -my_add_ufunc(A, B) # Output: array([ 6, 8, 10, 12], dtype=object) -``` -# Some Common Ufunc are - -Here are some commonly used ufuncs in NumPy: - -- **Arithmetic**: `np.add`, `np.subtract`, `np.multiply`, `np.divide` -- **Trigonometric**: `np.sin`, `np.cos`, `np.tan` -- **Exponential and Logarithmic**: `np.exp`, `np.log`, `np.log10` -- **Comparison**: `np.maximum`, `np.minimum`, `np.greater`, `np.less` -- **Logical**: `np.logical_and`, `np.logical_or`, `np.logical_not` - -For more such Ufunc, address to [Universal functions (ufunc) — NumPy](https://numpy.org/doc/stable/reference/ufuncs.html) \ No newline at end of file From 6b35fb7a8ebcbd423f5e6d4a8f95c39c3550cdfa Mon Sep 17 00:00:00 2001 From: Yogesh Vishwakarma <103316955+Yogeshkarma@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:08:24 +0530 Subject: [PATCH 5/6] Update index.md for two different pRs --- contrib/numpy/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/numpy/index.md b/contrib/numpy/index.md index 2b0c357..3caac1d 100644 --- a/contrib/numpy/index.md +++ b/contrib/numpy/index.md @@ -11,4 +11,4 @@ - [Sorting NumPy Arrays](sorting-array.md) - [NumPy Array Iteration](array-iteration.md) - [Concatenation of Arrays](concatenation-of-arrays.md) -- [Universal Functions (Ufunc)](Universal-Functions.md) + From 4a9287f6f0f57a0f4490f41037e5c7489fe089ff Mon Sep 17 00:00:00 2001 From: Yogesh Vishwakarma <103316955+Yogeshkarma@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:10:18 +0530 Subject: [PATCH 6/6] Update index.md --- contrib/numpy/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/numpy/index.md b/contrib/numpy/index.md index 3caac1d..50e8046 100644 --- a/contrib/numpy/index.md +++ b/contrib/numpy/index.md @@ -11,4 +11,3 @@ - [Sorting NumPy Arrays](sorting-array.md) - [NumPy Array Iteration](array-iteration.md) - [Concatenation of Arrays](concatenation-of-arrays.md) -