Repository: vaskoz/dailycodingproblem-go (go)

Issue:
Day 311
Good morning! Here's your coding interview problem for today.

This problem was asked by Sumo Logic.

Given an unsorted array, in which all elements are distinct, find a "peak" element in `O(log N)` time.

An element is considered a peak if it is greater than both its left and right neighbors. It is guaranteed that the first and last elements are lower than all others.

Pull request description:
Day311
Resolves #635.

Patch:
diff --git a/README.md b/README.md
index a4eef03..a160d15 100644
--- a/README.md
+++ b/README.md
@@ -318,3 +318,4 @@ problems from
 * [Day 307](https://github.com/vaskoz/dailycodingproblem-go/issues/628)
 * [Day 309](https://github.com/vaskoz/dailycodingproblem-go/issues/631)
 * [Day 310](https://github.com/vaskoz/dailycodingproblem-go/issues/633)
+* [Day 311](https://github.com/vaskoz/dailycodingproblem-go/issues/635)
diff --git a/day311/problem.go b/day311/problem.go
new file mode 100644
index 0000000..80f357d
--- /dev/null
+++ b/day311/problem.go
@@ -0,0 +1,73 @@
+package day311
+
+// PeakIndexNR returns the index of a peak without
+// using recursion.
+// Runs in O(log N).
+func PeakIndexNR(nums []int) int {
+	if len(nums) == 0 {
+		return -1
+	} else if len(nums) == 1 {
+		return 0
+	}
+	low, high := 0, len(nums)-1
+	for low < high {
+		mid := (low + high) / 2
+		switch {
+		case (mid == 0 || nums[mid-1] <= nums[mid]) &&
+			(mid == len(nums)-1 || nums[mid+1] <= nums[mid]):
+			return mid
+		case mid > 0 && nums[mid-1] > nums[mid]:
+			high = mid - 1
+		default:
+			low = mid + 1
+		}
+	}
+	return low
+}
+
+// PeakIndex returns the index of a peak.
+// Runs in O(log N).
+func PeakIndex(nums []int) int {
+	if len(nums) == 0 {
+		return -1
+	} else if len(nums) == 1 {
+		return 0
+	}
+	return peakIndex(nums, 0, len(nums)-1)
+}
+
+func peakIndex(nums []int, low, high int) int {
+	mid := (low + high) / 2
+	if (mid == 0 || nums[mid-1] <= nums[mid]) &&
+		(mid == len(nums)-1 || nums[mid+1] <= nums[mid]) {
+		return mid
+	} else if mid > 0 && nums[mid-1] > nums[mid] {
+		return peakIndex(nums, low, mid-1)
+	}
+	return peakIndex(nums, mid+1, high)
+}
+
+// PeakIndexBrute returns the index of a peak.
+// Runs in O(N).
+func PeakIndexBrute(nums []int) int {
+	if len(nums) == 1 {
+		return 0
+	}
+	for i := range nums {
+		switch i {
+		case 0:
+			if nums[i] > nums[i+1] {
+				return i
+			}
+		case len(nums) - 1:
+			if nums[i] > nums[i-1] {
+				return i
+			}
+		default:
+			if nums[i] > nums[i-1] && nums[i] > nums[i+1] {
+				return i
+			}
+		}
+	}
+	return -1
+}


Test patch:
diff --git a/day311/problem_test.go b/day311/problem_test.go
new file mode 100644
index 0000000..dbb799c
--- /dev/null
+++ b/day311/problem_test.go
@@ -0,0 +1,66 @@
+package day311
+
+import "testing"
+
+// nolint
+var testcases = []struct {
+	nums      []int
+	peakIndex int
+}{
+	{[]int{1, 3, 20, 4, 1, 0}, 2},
+	{nil, -1},
+	{[]int{100}, 0},
+	{[]int{5, 3, 2, 1, 0}, 0},
+	{[]int{1, 3, 5, 8, 10, 100}, 5},
+}
+
+func TestPeakIndexNR(t *testing.T) {
+	t.Parallel()
+	for _, tc := range testcases {
+		if peak := PeakIndexNR(tc.nums); peak != tc.peakIndex {
+			t.Errorf("Expected %v, got %v", tc.peakIndex, peak)
+		}
+	}
+}
+
+func BenchmarkPeakIndexNR(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			PeakIndex(tc.nums)
+		}
+	}
+}
+
+func TestPeakIndex(t *testing.T) {
+	t.Parallel()
+	for _, tc := range testcases {
+		if peak := PeakIndex(tc.nums); peak != tc.peakIndex {
+			t.Errorf("Expected %v, got %v", tc.peakIndex, peak)
+		}
+	}
+}
+
+func BenchmarkPeakIndex(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			PeakIndex(tc.nums)
+		}
+	}
+}
+
+func TestPeakIndexBrute(t *testing.T) {
+	t.Parallel()
+	for _, tc := range testcases {
+		if peak := PeakIndexBrute(tc.nums); peak != tc.peakIndex {
+			t.Errorf("Expected %v, got %v", tc.peakIndex, peak)
+		}
+	}
+}
+
+func BenchmarkPeakIndexBrute(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, tc := range testcases {
+			PeakIndexBrute(tc.nums)
+		}
+	}
+}