Codiwan.com

The blog for Design Patterns, Linux, HA and Myself!

Arithemtic Slices Solution - Leetcode

Understand Arithmetic Slices(413 Leetcode) With Brute Force and Optimal Solution

This document presents the solution to the problem 413 - Arithmetic Slices - Leetcode.

Note: Make sure to go through the code comments as well. It’ll help you understand the concept better.

		
				
A sequence of numbers is called arithmetic if it consists of at least three elements and if the difference between any 
two consecutive elements is the same.

For example, these are arithmetic sequences:
    1, 3, 5, 7, 9
    7, 7, 7, 7
    3, -1, -5, -9

The following sequence is not arithmetic.
    1, 1, 2, 5, 7

A zero-indexed array A consisting of N numbers is given. A slice of that array is any pair of integers (P, Q) such that 
0 <= P < Q < N.

A slice (P, Q) of the array A is called arithmetic if the sequence:
A[P], A[P + 1], ..., A[Q - 1], A[Q] is arithmetic. In particular, this means that P + 1 < Q.
The function should return the number of arithmetic slices in the array A.
Example:
    A = [1, 2, 3, 4]

return: 3, for 3 arithmetic slices in A: [1, 2, 3], [2, 3, 4] and [1, 2, 3, 4] itself.

		
	

Let’s start with a brute force approach for the input

input =  []int{
		1, 2, 3, 4, 5, 9, 10, 12, 14, 16
	}

This animation shows the progress of the loop for a brute force solution. The number at the top shows the count of all the arithmetic slices that have been counted. The green areas show the found arithmetic slices.

Animated Brute Force

So, What are we doing in a brute force approach? We’re

  1. Starting with an element at index i.
  2. We check if the current element and the next 2 elements(i + 1 and i+2) can become an arithmetic slice.
  3. If yes then we increment the counter and check if the next element can be added in the arithmetic slice. For example, we increment the counter after finding 1, 2, 3, and then move to 4.
  4. We repeat the 3rd step until we find an element that cannot be added into our current arithmetic slice. For example, after finding the 1st arithmetic slice, 1, 2, 3, we add 4 and 5 to it. Then we find 9 that cannot be added into the current slice, so we stop there.
  5. If we find an element that cannot be added to the slice then we move to the i + 1 index and restart from the step 1.

Please do provide some comments if you find the explanation a bit lacking.

Now that we’ve discussed the brute force approaches, what optimizations can we bring in this brute force approach?

Animated Optimized

Here is the function to find the very first arithmetic slice starting from the index from:

// findNextArithmeticSlice return the starting index of the very encountered arithmetic slice.
// Along with that it also returns difference between the two elements.
func findNextArithmeticSlice(arr []int, from int) (int, int, bool) {
	for i := from; i < len(arr); i++ {
		curr := arr[i]
		next := curr
		next2 := curr
		if i+1 < len(arr) {
			next = arr[i+1]
		} else {
			return 0, 0, false
		}
		if i+2 < len(arr) {
			next2 = arr[i+2]
		} else {
			return 0, 0, false
		}

		if next-curr == next2-next {
			return i, next - curr, true
		}
	}
	return 0, 0, false
}

This function is used by the function numberOfArithmeticSlices to get the very next slice from the current position. Once found then it finds total width of the arithmetic slice starting from the current index and then performs the sum of natural numbers to get the results.

func numberOfArithmeticSlices(A []int) int {
	from := 0
	totalNumOfArithmeticSlices := 0
	for {
		intoLoop := false
		numOfArithmeticSlices := 0
		start, diff, ok := findNextArithmeticSlice(A, from)
		if !ok {
			return totalNumOfArithmeticSlices
		}
		numOfArithmeticSlices++
		for j := start + 3; j < len(A); j++ {
			intoLoop = true
			if A[j]-A[j-1] == diff {
				numOfArithmeticSlices++
			} else {
				from = j - 1
				break
			}
			if j == len(A)-1 {
				from = len(A) - 2
			}
		}
		if numOfArithmeticSlices > 1 {
			numOfArithmeticSlices += (numOfArithmeticSlices - 1) * (numOfArithmeticSlices) / 2
		}
		totalNumOfArithmeticSlices += numOfArithmeticSlices
		if !intoLoop {
			return totalNumOfArithmeticSlices
		}
	}
}

The entire program is available here on GitHub as well.

Loading Comments... Disqus Loader
comments powered by Disqus