diff --git a/dynamic/climbingstairs.go b/dynamic/climbingstairs.go new file mode 100644 index 000000000..52a487590 --- /dev/null +++ b/dynamic/climbingstairs.go @@ -0,0 +1,34 @@ +package dynamic + +// ClimbingStairs calculates the number of distinct ways to climb +// n stairs when each step can be either 1 or 2 stairs. +// +// It uses dynamic programming with two variables to optimize +// space complexity. +// +// Time complexity: O(n) +// Space complexity: O(1) +// +// Returns 1 for n = 0 and 0 for negative values of n. +// +// Note: The result may overflow int for sufficiently large n. +func ClimbingStairs(n int) int { + if n < 0 { + return 0 + } + + if n <= 1 { + return 1 + } + + prevTwo := 1 + prevOne := 1 + + for i := 2; i <= n; i++ { + current := prevOne + prevTwo + prevTwo = prevOne + prevOne = current + } + + return prevOne +} diff --git a/dynamic/climbingstairs_test.go b/dynamic/climbingstairs_test.go new file mode 100644 index 000000000..5b7b0d3c3 --- /dev/null +++ b/dynamic/climbingstairs_test.go @@ -0,0 +1,51 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func TestClimbingStairs(t *testing.T) { + td := []struct { + n int + expected int + }{ + {0, 1}, + {1, 1}, + {2, 2}, + {3, 3}, + {4, 5}, + {5, 8}, + {6, 13}, + {7, 21}, + {10, 89}, + {15, 987}, + {20, 10946}, + {-1, 0}, + {-5, 0}, + } + + for _, tc := range td { + name := fmt.Sprintf("ClimbingStairs(%d)", tc.n) + + t.Run(name, func(t *testing.T) { + actual := dynamic.ClimbingStairs(tc.n) + + if actual != tc.expected { + t.Errorf( + "ClimbingStairs(%d) = %d, expected %d", + tc.n, + actual, + tc.expected, + ) + } + }) + } +} + +func ExampleClimbingStairs() { + fmt.Print(dynamic.ClimbingStairs(4)) + // Output: 5 +} diff --git a/dynamic/maxnonadjacentsum.go b/dynamic/maxnonadjacentsum.go new file mode 100644 index 000000000..c67e8a942 --- /dev/null +++ b/dynamic/maxnonadjacentsum.go @@ -0,0 +1,33 @@ +package dynamic + +// MaxNonAdjacentSum finds the maximum sum of non-adjacent elements +// in a given slice of integers. +// +// The algorithm uses dynamic programming with two variables to +// optimize space complexity. +// +// Time complexity: O(n) +// Space complexity: O(1) +// +// The empty subset is allowed, so the function returns 0 for +// an empty slice or a slice containing only negative numbers. +func MaxNonAdjacentSum(nums []int) int { + if len(nums) == 0 { + return 0 + } + + prevTwo := 0 + prevOne := 0 + + for _, num := range nums { + current := prevOne + if prevTwo+num > current { + current = prevTwo + num + } + + prevTwo = prevOne + prevOne = current + } + + return prevOne +} diff --git a/dynamic/maxnonadjacentsum_test.go b/dynamic/maxnonadjacentsum_test.go new file mode 100644 index 000000000..1d770acd8 --- /dev/null +++ b/dynamic/maxnonadjacentsum_test.go @@ -0,0 +1,53 @@ +package dynamic_test + +import ( + "fmt" + "testing" + + "github.com/TheAlgorithms/Go/dynamic" +) + +func TestMaxNonAdjacentSum(t *testing.T) { + td := []struct { + input []int + expected int + }{ + {[]int{}, 0}, + {[]int{5}, 5}, + {[]int{-5}, 0}, + {[]int{2, 7, 9, 3, 1}, 12}, + {[]int{1, 2, 3, 4, 5}, 9}, + {[]int{2, 1, 4, 9}, 11}, + {[]int{10, 20}, 20}, + {[]int{-2, -7, -3}, 0}, + {[]int{4, -1, 5, -2, 6}, 15}, + {[]int{5, 5, 10, 100, 10, 5}, 110}, + {[]int{0, 0, 0, 0}, 0}, + {[]int{100, 1, 1, 100}, 200}, + } + + for _, tc := range td { + name := fmt.Sprintf( + "MaxNonAdjacentSum(%v)", + tc.input, + ) + + t.Run(name, func(t *testing.T) { + actual := dynamic.MaxNonAdjacentSum(tc.input) + + if actual != tc.expected { + t.Errorf( + "MaxNonAdjacentSum(%v) = %d, expected %d", + tc.input, + actual, + tc.expected, + ) + } + }) + } +} + +func ExampleMaxNonAdjacentSum() { + fmt.Print(dynamic.MaxNonAdjacentSum([]int{2, 7, 9, 3, 1})) + // Output: 12 +}