Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/build/

# Emacs
*~
230 changes: 230 additions & 0 deletions Problem_4_ArithmeticProgression/ArithmeticProgression.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
author: Tony Beaumont
summary: Problem Solving: Find the missing number
id: problem-04
categories: coding
environments: Web
status: Published
feedback link: mailto:a.j.beaumont@aston.ac.uk

# Problem Solving: Find the missing number

## Introduction

This series of problem solving exercises are based on problems found on Codewars [https://www.codewars.com/](https://www.codewars.com/) or Hackerank [https://www.hackerrank.com/dashboard](https://www.hackerrank.com/dashboard).

### What you should already know

You should have attended the previous two problem solving sessions. You will have learned the outline procedure for solving problems by:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You should have attended the previous two problem solving sessions. You will have learned the outline procedure for solving problems by:
You should have attended the previous three problem solving sessions. You will have learned the outline procedure for solving problems by:


<ol type="i">
<li>Understanding what the problem statement is asking you to do</li>
<li>Using abstraction to identify what is important</li>
<li>Using decomposition to break the problem down into smaller problems.</li>
<li>Solve the smaller problems, one at a time</li>
</ol>
You will get more practice on that today.

### What you'll learn

- How to use **abstraction**
- How to use **decomposition**
- How to use **repetition**
- How to use **arrays**

### What you'll need

No specific tools are required, although you will need to make notes so either pencil and paper or a text editor on your laptop.

### What you'll do

You will be presented with a problem. You will learn how to understand the problem and break the problem down into steps that help you work towards a solution.

## Problem Description

Todays problem can be found here: [https://www.codewars.com/kata/52de553ebb55d1fca3000371/train/javascript](https://www.codewars.com/kata/52de553ebb55d1fca3000371/train/javascript).

After the class finishes, you should submit a solution to the problem using the link above.

### Story

We want to find the missing number in a list generated by an arithmetic progression.

### Problem

An Arithmetic Progression (AP) is defined as one in which there is a constant difference between the consecutive terms of a given series of numbers. You are provided with consecutive elements of an Arithmetic Progression. There is however one hitch: exactly one term from the original series is missing from the set of numbers which have been given to you. The rest of the given series is the same as the original AP. Find the missing term.

You have to write a function that receives a list, the list size will always be at least 3 numbers. The missing term will never be the first or last one.

### Example:

```javascript
findMissing([1, 3, 5, 9, 11]) == 7;
```

## Understanding the problem

1. Make sure you understand the problem. Important terms in the problem specification are **Arithmetic Progression**, **constant difference**, and **consecutive terms**. Discuss your definitions of these term.
1. **Discuss any questions as a group** and resolve any differences before continuing.

## Understand the examples

The example was:

```javascript
findMissing([1, 3, 5, 9, 11]) == 7;
```

1. What is the arithmetic progression used to generate this list?
1. Why is 7 the missing number in this example?

The test page on codewars contains the following test:

```javascript
describe("Example tests", function () {
it("Testing with [1, 3, 4]", function () {
assert.strictEqual(findMissing([1, 3, 4]), 2);
});
});
```

This test says that for the list `[1, 3, 4]`, the expected answer is `2`.

1. What is the arithmetic progression used to generate this list?
1. Why is 2 the missing number in this example?
1. Create another example using a different arithmetic progression

## A larger set of tests

Here are the tests I am providing today:

```javascript
describe("Arithmetic progression", () => {
test("Testing with [1, 3, 4]", function () {
expect(findMissing([1, 3, 4])).toBe(2);
});

test("Testing with [1, 3, 5, 9, 11]", function () {
expect(findMissing([1, 3, 5, 9, 11])).toBe(7);
});

test("Testing with [1, 5, 9, 17]", function () {
expect(findMissing([1, 5, 9, 17])).toBe(13);
});

test("Testing with [7, 14, 28, 35]", function () {
expect(findMissing([7, 14, 28, 35])).toBe(21);
});

test("Testing with [1, 5, 7, 9]", function () {
expect(findMissing([1, 5, 7, 9])).toBe(3);
});

// and a challenge: does your solution also pass these tests
test("Testing with [[5, 0, -5, -15, -20]]", function () {
expect(findMissing([5, 0, -5, -15, -20])).toBe(-10);
});

test("Testing with [[-5, -15, -20]]", function () {
expect(findMissing([-5, -15, -20])).toBe(-10);
});
});
```

## Identify what is important

1. Make a list of all the features of the problem that look important. Ignore anything that you think is not essential to solving the problem.
1. **Discuss your solution to this step as a group**. Does everyone have the same list of important elements or are there differences? Resolve your differences so everyone agrees what is important.

## Use the important features to solve the problem

In an arithmetic progression we have:

<ol type='i'>
<li>A starting number</li>
<li>An ending number</li>
<li>The difference between consecutive numbers in the full sequence is constant</li>
<li>If we know the <em>difference</em> between consecutive numbers, we can <em>predict</em> the next number in the sequence</li>
</ol>

We can split our problem into TWO steps

- **Step 1**: we should find the **difference** between successive terms,
- **Step 2**: we use the difference to find an **unexpected** value in the sequence.

### Example One

Lets say we are given the list `[1, 5, 7, 9]`

#### Ex1, Step 1

In the full sequence `[1, 3, 5, 7, 9]`, the difference is `2` (easy for us to see but not easy for a computer).

#### Ex 1, Step 2

To find the missing number, we start with the first item in the list, which is `1`, add the difference (`1 + 2`) and **expect** the next value in the sequence to be `3`. The next value is **unexpectedly** `5`, so we know the **missing number** is `3`.

### Example Two

Lets say we are given the list `[1, 3, 5, 9]`

#### Ex 2, Step 1

In the full sequence `[1, 3, 5, 7, 9]`, the difference is `2` (again, easy for us to see but not easy for a computer).

#### Ex 2, Step 2

To find the missing number, we start with the first item in the list, which is `1`, add the difference (`1 + 2`) and **expect** the next value in the sequence to be `3`. We **repeat** that exercise, adding `3 + 2 = 5` and then `5 + 2 = 7` until we see the **unexpected** value which is `9` and not `7`. The missing value is `7`.

## How to find the 'difference'

In the full sequence `[1, 3, 5, 7, 9]`, the **difference** is 2. We can also think of it as the "gaps" between terms being the list `[2, 2, 2, 2]`. Note that the length of the full sequence is `5` but the number of "gaps" is only `4` (ie, length of the list `[2, 2, 2, 2]`).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In the full sequence `[1, 3, 5, 7, 9]`, the **difference** is 2. We can also think of it as the "gaps" between terms being the list `[2, 2, 2, 2]`. Note that the length of the full sequence is `5` but the number of "gaps" is only `4` (ie, length of the list `[2, 2, 2, 2]`).
In the full sequence `[1, 3, 5, 7, 9]`, the **difference** is 2. We can also think of it as the "gaps" between terms being the list `[2, 2, 2, 2]`. Note that the length of the full sequence is `5` but the number of "gaps" is only `4` (i.e., length of the list `[2, 2, 2, 2]`).


In the version we are given, with one value missing, `[1, 5, 7, 9]`, the differences are `[4, 2, 2]`. The first difference is the largest one, so it is easy for us to see that there is a number missing from the sequence between `1` and `5`.

### Can we find an algorithm to calculate the difference?

Remember, the problem specification said:

```console
The missing term will never be the first or last one.
```

This is important to our solution.

1. How many ways can you find to compute the **difference** between terms from the given list (ie the list with one value missing)?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. How many ways can you find to compute the **difference** between terms from the given list (ie the list with one value missing)?
1. How many ways can you find to compute the **difference** between terms from the given list (i.e. the list with one value missing)?

1. We can reply on the first and last values as being present, so can you compute the difference using only the first and last values?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. We can reply on the first and last values as being present, so can you compute the difference using only the first and last values?
1. We can rely on the first and last values as being present. Can you compute the difference using only the first and last values?


## Computing the difference

There is a way of computing the difference easily from the first and last value in the sequence. It relies on the fact that given the full sequence has `len` values in it, there are `len - 1` "gaps" and this gap is constant (ie it is the same every time).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There is a way of computing the difference easily from the first and last value in the sequence. It relies on the fact that given the full sequence has `len` values in it, there are `len - 1` "gaps" and this gap is constant (ie it is the same every time).
There is a way of computing the difference easily from the first and last value in the sequence. It relies on the fact that given the full sequence has `len` values in it, there are `len - 1` "gaps" and this gap is constant (i.e. it is the same every time).


The **full** sequence is `[1, 3, 5, 7, 9]`

The **gaps** are [2, 2, 2, 2]. We could think of the **range** of the sequence (from start to finish) as being `2 + 2 + 2 + 2 = 8`.

Another way of calculating the **range** of the sequence is to subtract the first value from the last value. In this example we get `9 - 1 = 8`.

The range has to be **shared equally** across the four "gaps". To share `8` across four "gaps" we perform the division `8 / 4 = 2` and this value `2` is our difference.

Here is a fragment of code from step 1 of our solution:

```javascript
const len = list.length; // remember the list has one item missing
const first = list[0];
const last = list[len - 1];
const range = last - first;
const difference = range / (len + 1 - 1);
// plus one because the list has a value missing and minus 1 to find the number of gaps
// we can simplify (len + 1 - 1) to len and use...
// const difference = range / len;
```

Can you write a solution to the whole problem now by adding the code for step 2? You can find some starter code here: [starter-code.zip](starter-code.zip).

To use the starter code:

1. Extract the zip file into a folder
1. Open that folder in VS Code
1. From VS code, open a new terminal in that folder.
1. In the terminal type the command `npm install`
1. To test your code run the command `npm test`.
22 changes: 22 additions & 0 deletions Problem_4_ArithmeticProgression/solutions/alternateSolution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function findMissing(list) {
const len = list.length;
const first = list[0];
const last = list[len - 1];

const range = last - first;
// remember that of a list of n elements (including the missing number),
// there are n - 1 gaps. len + 1 - 1 === len
const expectedGap = range / len;

/* console.log(
`first is ${first}, last is ${last}, range is ${range}, expectedGap is ${expectedGap}`
); */
for (let i = 1; i < len; i++) {
const gap = list[i] - list[i - 1];
if (gap !== expectedGap) {
return list[i - 1] + expectedGap;
}
}
}

module.exports = findMissing;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const findMissing = require("./alternateSolution");

describe("Arithmetic progression", () => {
test("Testing with [1, 3, 4]", function () {
expect(findMissing([1, 3, 4])).toBe(2);
});

test("Testing with [1, 3, 5, 9, 11]", function () {
expect(findMissing([1, 3, 5, 9, 11])).toBe(7);
});

test("Testing with [1, 5, 9, 17]", function () {
expect(findMissing([1, 5, 9, 17])).toBe(13);
});

test("Testing with [7, 14, 28, 35]", function () {
expect(findMissing([7, 14, 28, 35])).toBe(21);
});

test("Testing with [1, 5, 7, 9]", function () {
expect(findMissing([1, 5, 7, 9])).toBe(3);
});

test("Testing with [[5, 0, -5, -15, -20]]", function () {
expect(findMissing([5, 0, -5, -15, -20])).toBe(-10);
});

test("Testing with [[-5, -15, -20]]", function () {
expect(findMissing([-5, -15, -20])).toBe(-10);
});
});
35 changes: 35 additions & 0 deletions Problem_4_ArithmeticProgression/solutions/solution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
function findMissing(list) {
const gaps = findGaps(list);
//console.log(gaps);
const max = findMax(gaps);
console.log(`gaps ${gaps} max ${max}`);
const lower = max.start;
const upper = max.end;
console.log(`lower ${lower} upper ${upper}`);
const missing = lower + (max.end - max.start) / 2;
return missing;
}

function findGaps(list) {
let max = 0;
const gaps = [];
for (let i = 1; i < list.length; i++) {
const diff = Math.abs(list[i] - list[i - 1]);
gaps.push({ start: list[i - 1], end: list[i], diff: diff });
}
return gaps;
}

function findMax(gaps) {
let max = 0;
let maxGap;
for (const gap of gaps) {
if (gap.diff > max) {
max = gap.diff;
maxGap = gap;
}
}
return maxGap;
}

module.exports = findMissing;
31 changes: 31 additions & 0 deletions Problem_4_ArithmeticProgression/solutions/solution.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const findMissing = require("./solution");

describe("Arithmetic progression", () => {
test("Testing with [1, 3, 4]", function () {
expect(findMissing([1, 3, 4])).toBe(2);
});

test("Testing with [1, 3, 5, 9, 11]", function () {
expect(findMissing([1, 3, 5, 9, 11])).toBe(7);
});

test("Testing with [1, 5, 9, 17]", function () {
expect(findMissing([1, 5, 9, 17])).toBe(13);
});

test("Testing with [7, 14, 28, 35]", function () {
expect(findMissing([7, 14, 28, 35])).toBe(21);
});

test("Testing with [1, 5, 7, 9]", function () {
expect(findMissing([1, 5, 7, 9])).toBe(3);
});

test("Testing with [[5, 0, -5, -15, -20]]", function () {
expect(findMissing([5, 0, -5, -15, -20])).toBe(-10);
});

test("Testing with [[-5, -15, -20]]", function () {
expect(findMissing([-5, -15, -20])).toBe(-10);
});
});
Loading