diff --git a/csharp/Two Pointers/IsPalindromeValid.cs b/csharp/Two Pointers/IsPalindromeValid.cs new file mode 100644 index 0000000..1c1ab3a --- /dev/null +++ b/csharp/Two Pointers/IsPalindromeValid.cs @@ -0,0 +1,33 @@ +public class Solution +{ + public bool IsPalindromeValid(string s) + { + int left = 0, right = s.Length - 1; + while (left < right) + { + // Skip non-alphanumeric characters from the left. + while (left < right && !char.IsLetterOrDigit(s[left])) + { + left++; + } + + // Skip non-alphanumeric characters from the right. + while (left < right && !char.IsLetterOrDigit(s[right])) + { + right--; + } + + // If the characters at the left and right pointers don't + // match, the string is not a palindrome. + if (s[left] != s[right]) + { + return false; + } + + left++; + right--; + } + + return true; + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/LargestContainer.cs b/csharp/Two Pointers/LargestContainer.cs new file mode 100644 index 0000000..e9a6824 --- /dev/null +++ b/csharp/Two Pointers/LargestContainer.cs @@ -0,0 +1,33 @@ +public class Solution +{ + public int LargestContainer(int[] heights) + { + int max_water = 0; + int left = 0, right = heights.Length - 1; + while (left < right) + { + // Calculate the water contained between the current pair of + // lines. + int water = Math.Min(heights[left], heights[right]) * (right - left); + max_water = Math.Max(max_water, water); + // Move the pointers inward, always moving the pointer at the + // shorter line. If both lines have the same height, move both + // pointers inward. + if (heights[left] < heights[right]) + { + left++; + } + else if (heights[left] > heights[right]) + { + right--; + } + else + { + left++; + right--; + } + } + + return max_water; + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/LargestContainerBruteForce.cs b/csharp/Two Pointers/LargestContainerBruteForce.cs new file mode 100644 index 0000000..227f766 --- /dev/null +++ b/csharp/Two Pointers/LargestContainerBruteForce.cs @@ -0,0 +1,20 @@ +public class Solution +{ + public int LargestContainerBruteForce(int[] heights) + { + int n = heights.Length; + int max_water = 0; + // Find the maximum amount of water stored between all pairs of + // lines. + for (int i = 0; i < n; i++) + { + for (int j = i + 1; j < n; j++) + { + int water = Math.Min(heights[i], heights[j]) * (j - i); + max_water = Math.Max(max_water, water); + } + } + + return max_water; + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/NextLexicographicalSequence.cs b/csharp/Two Pointers/NextLexicographicalSequence.cs new file mode 100644 index 0000000..bad8b5c --- /dev/null +++ b/csharp/Two Pointers/NextLexicographicalSequence.cs @@ -0,0 +1,45 @@ +public class Solution +{ + public string NextLexicographicalSequence(string s) + { + char[] letters = s.ToCharArray(); + // Locate the pivot, which is the first character from the right that breaks + // non-increasing order. Start searching from the second-to-last position, + // since the last character is neither increasing nor decreasing. + int pivot = letters.Length - 2; + while (pivot >= 0 && letters[pivot] >= letters[pivot + 1]) + { + pivot--; + } + // If pivot is not found, the string is already in its largest permutation. In + // this case, reverse the string to obtain the smallest permutation. + if (pivot == -1) + { + ReverseString(letters, 0, letters.Length - 1); + return string.Join("", letters); + } + // Find the rightmost successor to the pivot. + int rightmost_successor = letters.Length - 1; + while (letters[rightmost_successor] <= letters[pivot]) + { + rightmost_successor--; + } + // Swap the rightmost successor with the pivot to increase the lexicographical + // order of the suffix. + (letters[pivot], letters[rightmost_successor]) = (letters[rightmost_successor], letters[pivot]); + // Reverse the suffix after the pivot to minimize its permutation. + ReverseString(letters, pivot + 1, letters.Length - 1); + return string.Join("", letters); + } + + public void ReverseString(char[] s, int start, int end) + { + while (start < end) + { + (s[start], s[end]) = (s[end], s[start]); + + start++; + end--; + } + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/PairSumSorted.cs b/csharp/Two Pointers/PairSumSorted.cs new file mode 100644 index 0000000..d257269 --- /dev/null +++ b/csharp/Two Pointers/PairSumSorted.cs @@ -0,0 +1,30 @@ +public class Solution +{ + public int[] PairSumSorted(int[] nums, int target) + { + int left = 0, right = nums.Length - 1; + while (left < right) + { + int sum = nums[left] + nums[right]; + // If the sum is smaller, increment the left pointer, aiming + // to increase the sum toward the target value. + if (sum < target) + { + left++; + } + // If the sum is larger, decrement the right pointer, aiming + // to decrease the sum toward the target value. + else if (sum > target) + { + right--; + } + // If the target pair is found, return its indexes. + else + { + return [left, right]; + } + } + + return []; + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/PairSumSortedBruteForce.cs b/csharp/Two Pointers/PairSumSortedBruteForce.cs new file mode 100644 index 0000000..82f1948 --- /dev/null +++ b/csharp/Two Pointers/PairSumSortedBruteForce.cs @@ -0,0 +1,19 @@ +public class Solution +{ + public int[] PairSumSortedBruteForce(int[] nums, int target) + { + int n = nums.Length; + for (int i = 0; i < n; i++) + { + for (int j = i + 1; j < n; j++) + { + if (nums[i] + nums[j] == target) + { + return [i, j]; + } + } + } + + return []; + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/ShiftZerosToTheEnd.cs b/csharp/Two Pointers/ShiftZerosToTheEnd.cs new file mode 100644 index 0000000..8cf5727 --- /dev/null +++ b/csharp/Two Pointers/ShiftZerosToTheEnd.cs @@ -0,0 +1,20 @@ +public class Solution +{ + public void ShiftZerosToTheEnd(int[] nums) + { + // The 'left' pointer is used to position non-zero elements. + int left = 0; + // Iterate through the array using a 'right' pointer to locate non-zero + // elements. + for (int right = 0; right < nums.Length; right++) + { + if (nums[right] != 0) + { + (nums[right], nums[left]) = (nums[left], nums[right]); + // Increment 'left' since it now points to a position already occupied + // by a non-zero element. + left++; + } + } + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/ShiftZerosToTheEndNaive.cs b/csharp/Two Pointers/ShiftZerosToTheEndNaive.cs new file mode 100644 index 0000000..6710eea --- /dev/null +++ b/csharp/Two Pointers/ShiftZerosToTheEndNaive.cs @@ -0,0 +1,23 @@ +public class Solution +{ + public void ShiftZerosToTheEndNaive(int[] nums) + { + int[] temp = new int[nums.Length]; + int i = 0; + // Add all non-zero elements to the left of 'temp'. + foreach (int num in nums) + { + if (num != 0) + { + temp[i] = num; + i++; + } + } + + // Set 'nums' to 'temp'. + for (int j = 0; j < nums.Length; j++) + { + nums[j] = temp[j]; + } + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/TripletSum.cs b/csharp/Two Pointers/TripletSum.cs new file mode 100644 index 0000000..9595b66 --- /dev/null +++ b/csharp/Two Pointers/TripletSum.cs @@ -0,0 +1,64 @@ +public class Solution +{ + public IList> TripletSum(int[] nums) + { + IList> triplets = []; + Array.Sort(nums); + for (int i = 0; i < nums.Length; i++) + { + // Optimization: triplets consisting of only positive numbers + // will never sum to 0. + if (nums[i] > 0) + { + break; + } + + // To avoid duplicate triplets, skip 'a' if it's the same as + // the previous number. + if (i > 0 && nums[i] == nums[i - 1]) + { + continue; + } + + // Find all pairs that sum to a target of '-a' (-nums[i]). + IList> pairs = PairSumSortedAllPairs(nums, i + 1, -nums[i]); + foreach (var pair in pairs) + { + triplets.Add([nums[i], pair[0], pair[1]]); + } + } + + return triplets; + } + + public IList> PairSumSortedAllPairs(int[] nums, int start, int target) + { + IList> pairs = []; + int left = start, right = nums.Length - 1; + while (left < right) + { + int sum = nums[left] + nums[right]; + if (sum == target) + { + pairs.Add([nums[left], nums[right]]); + left++; + // To avoid duplicate '[b, c]' pairs, skip 'b' if it's the + // same as the previous number. + while (left < right && nums[left] == nums[left - 1]) + { + left++; + } + } + else if (sum < target) + { + left++; + } + else + { + right--; + } + } + + return pairs; + } +} \ No newline at end of file diff --git a/csharp/Two Pointers/TripletSumBruteForce.cs b/csharp/Two Pointers/TripletSumBruteForce.cs new file mode 100644 index 0000000..2610d82 --- /dev/null +++ b/csharp/Two Pointers/TripletSumBruteForce.cs @@ -0,0 +1,35 @@ +public class Solution +{ + public IList> TripletSumBruteForce(int[] nums) + { + int n = nums.Length; + // Use a hash set to ensure we don't add duplicate triplets. + HashSet> triplets = []; + // Iterate through the indexes of all triplets. + for (int i = 0; i < n; i++) + { + for (int j = i + 1; j < n; j++) + { + for (int k = j + 1; k < n; k++) + { + if (nums[i] + nums[j] + nums[k] == 0) + { + // Sort the triplet before including it in the + // hash set. + int[] triplet = [nums[i], nums[j], nums[k]]; + Array.Sort(triplet); + triplets.Add(new Tuple(triplet[0], triplet[1], triplet[2])); + } + } + } + } + + IList> result = []; + foreach (var triplet in triplets) + { + result.Add([triplet.Item1, triplet.Item2, triplet.Item3]); + } + + return result; + } +} \ No newline at end of file