diff --git a/go/Two Pointers/is_palindrome_valid.go b/go/Two Pointers/is_palindrome_valid.go new file mode 100644 index 0000000..fcf14ab --- /dev/null +++ b/go/Two Pointers/is_palindrome_valid.go @@ -0,0 +1,30 @@ +func isPalindromeValid(input string) bool { + s := []rune(input) + + left, right := 0, len(s)-1 + + for left < right { + // Skip non-alphanumeric characters from the left. + for left < right && !isAlnum(s[left]) { + left++ + } + // Skip non-alphanumeric characters from the right. + for left < right && !isAlnum(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 +} + +func isAlnum(r rune) bool { + return unicode.IsLetter(r) || unicode.IsDigit(r) +} diff --git a/go/Two Pointers/largest_container.go b/go/Two Pointers/largest_container.go new file mode 100644 index 0000000..0e34fcc --- /dev/null +++ b/go/Two Pointers/largest_container.go @@ -0,0 +1,24 @@ +func largestContainer(heights []int) int { + maxWater := 0 + left, right := 0, len(heights)-1 + + for left < right { + // Calculate the water contained between the current pair of + // lines. + water := min(heights[left], heights[right]) * (right - left) + maxWater = max(maxWater, 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 maxWater +} diff --git a/go/Two Pointers/next_lexicographical_sequence.go b/go/Two Pointers/next_lexicographical_sequence.go new file mode 100644 index 0000000..acad4a7 --- /dev/null +++ b/go/Two Pointers/next_lexicographical_sequence.go @@ -0,0 +1,35 @@ +func nextLexicographicalSequence(s string) string { + letters := []rune(s) + // Locate the pivot, which is the first character from the right that breaks + // non-increasing order. Start searching from the second-to-last position. + pivot := len(letters) - 2 + for 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 { + reverse(letters, 0) + return string(letters) + } + // Find the rightmost successor to the pivot. + rightmostSuccessor := len(letters) - 1 + for letters[rightmostSuccessor] <= letters[pivot] { + rightmostSuccessor-- + } + // Swap the rightmost successor with the pivot to increase the lexicographical + // order of the suffix. + letters[pivot], letters[rightmostSuccessor] = letters[rightmostSuccessor], letters[pivot] + // Reverse the suffix after the pivot to minimize its permutation. + reverse(letters, pivot+1) + return string(letters) +} + +func reverse(s []rune, start int) { + end := len(s) - 1 + for start < end { + s[start], s[end] = s[end], s[start] + start++ + end-- + } +} diff --git a/go/Two Pointers/pair_sum_sorted.go b/go/Two Pointers/pair_sum_sorted.go new file mode 100644 index 0000000..471ed56 --- /dev/null +++ b/go/Two Pointers/pair_sum_sorted.go @@ -0,0 +1,19 @@ +func pairSumSorted(nums []int, target int) []int { + left, right := 0, len(nums)-1 + for left < right { + 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++ + } else if sum > target { + // If the sum is larger, decrement the right pointer, aiming + // to decrease the sum toward the target value. + right-- + } else { + // If the target pair is found, return its indexes. + return []int{left, right} + } + } + return nil +} diff --git a/go/Two Pointers/shift_zeros_to_the_end.go b/go/Two Pointers/shift_zeros_to_the_end.go new file mode 100644 index 0000000..94e0047 --- /dev/null +++ b/go/Two Pointers/shift_zeros_to_the_end.go @@ -0,0 +1,14 @@ +func shiftZerosToTheEnd(nums []int) { + // The 'left' pointer is used to position non-zero elements. + left := 0 + // Iterate through the array using a 'right' pointer to locate non-zero + // elements. + for right := 0; right < len(nums); right++ { + if nums[right] != 0 { + nums[left], nums[right] = nums[right], nums[left] + // Increment 'left' since it now points to a position already occupied + // by a non-zero element. + left++ + } + } +} diff --git a/go/Two Pointers/triplet_sum.go b/go/Two Pointers/triplet_sum.go new file mode 100644 index 0000000..48d9f22 --- /dev/null +++ b/go/Two Pointers/triplet_sum.go @@ -0,0 +1,50 @@ +func tripletSum(nums []int) [][]int { + triplets := [][]int{} + sort.Ints(nums) + + for i := 0; i < len(nums); 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]). + pairs := pairSumSortedAllPairs(nums, i+1, -nums[i]) + for _, pair := range pairs { + triplets = append(triplets, []int{nums[i], pair[0], pair[1]}) + } + } + + return triplets +} + +func pairSumSortedAllPairs(nums []int, start int, target int) [][]int { + pairs := [][]int{} + left, right := start, len(nums)-1 + for left < right { + sum := nums[left] + nums[right] + if sum == target { + pairs = append(pairs, []int{nums[left], nums[right]}) + left++ + // To avoid duplicate '[b, c]' pairs, skip 'b' if it's the + // same as the previous number. + for left < right && nums[left] == nums[left-1] { + left++ + } + } else if sum < target { + left++ + } else { + right-- + } + } + + return pairs +}