House robber II

The houses sit in a circle, so the first and last are neighbours too. Run house robber twice and keep the better result.

Time O(n)Space O(n)Code C#
Watch it animatedStep through it, with the running line highlighted. Free with an account.

The idea

In a circle, robbing both the first and the last house breaks the no-two-neighbours rule. So either the last house is off limits, or the first house is. Running the ordinary straight-line house robber on each of those two shortened rows and keeping the larger answer covers every safe option.

Code

public static int RobCircle(int[] a) {
    if (a.Length == 1) return a[0];
    int excludeLast = RobLinear(a, 0, a.Length - 2);
    int excludeFirst = RobLinear(a, 1, a.Length - 1);
    return Math.Max(excludeLast, excludeFirst);
}
static int RobLinear(int[] a, int lo, int hi) {
    int prev = 0, cur = 0;
    for (int i = lo; i <= hi; i++) {
        int take = prev + a[i];
        prev = cur;
        cur = Math.Max(cur, take);
    }
    return cur;
}

Tips

In the .NET library

It is tempting to just skip "the smaller of the two ends", but that is not always correct: only trying both full ranges and comparing their best totals is guaranteed to find the true optimum.