sxbrentxs
sxbrentxs

Reputation: 93

Double linear sequence gives odd results

I'm trying to get my performance skills (none existent) up to par but ran into a problem with writing out a formula into code. This is the formula I'm trying to - quote unquote - "convert" to code.

Consider a sequence u where u is defined as follows:

The number u(0) = 1 is the first one in u. For each x in u, then y = 2 * x + 1 and z = 3 * x + 1 must be in u too. There are no other numbers in u. Ex: u = [1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, ...]

1 gives 3 and 4, then 3 gives 7 and 10, 4 gives 9 and 13, then 7 gives 15 and 22 and so on...

And this is what I have so far:

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Console.WriteLine(DblLinear(10));
        //Expected result: 22
        Console.WriteLine(DblLinear(20));
        //Expected result: 57
        Console.WriteLine(DblLinear(30));
        //Expected result: 91
        Console.WriteLine(DblLinear(50));
        //Expected result: 175
    }
    public static int DblLinear (int n) 
    {
        List<int> linArr = new List<int>();
        linArr.Add(1);

        int i = 0;
        while(linArr.Count < n)
        {
            linArr.Add((2 * linArr[i]) + 1);
            linArr.Add((3 * linArr[i]) + 1);
            linArr.Sort();
            i++;
        }
        return linArr[n - 1];
    }
}

The calculations are right until it hits 27. After that it just runs wild and I have no idea what it does wrong.

Upvotes: 3

Views: 973

Answers (2)

Enigmativity
Enigmativity

Reputation: 117084

What's going wrong is that you're using a single index to build your values.

When you get to i == 27, as per your example, the first series produces 55 and the second produces 82. But the first should have also produced 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81 before the second produces 82 for your sequence to be properly computed.

You need to run two separate indexes and only increment each when the value produced by their respective series is lowest (or equal to the other).

Here's how I would do it:

public static IEnumerable<int> DblLinear()
{
    Func<int, int> fxy = x => 2 * x + 1;
    Func<int, int> fxz = x => 3 * x + 1;

    var intermediate = new System.Collections.Generic.SortedSet<int>();

    Action<int> safeAdd = x =>
    {
        if (!intermediate.Contains(x))
        {
            intermediate.Add(x);
        }
    };

    safeAdd(1);

    while (true)
    {
        var x = intermediate.First();
        safeAdd(fxy(x));
        safeAdd(fxz(x));
        intermediate.Remove(x);
        yield return x;
    }
}

Now this can be used to produce the entire sequence so it is a good idea to use the LINQ .Take(...) operator.

You could using it like this:

Console.WriteLine(String.Join(", ", DblLinear().Take(20)));

...and that gives me:

1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, 28, 31, 39, 40, 43, 45, 46, 55

Your test code, once modified to handle the list, works just fine:

    Console.WriteLine(DblLinear().Skip(10).First());
    //Expected result: 22
    Console.WriteLine(DblLinear().Skip(20).First());
    //Expected result: 57
    Console.WriteLine(DblLinear().Skip(30).First());
    //Expected result: 91
    Console.WriteLine(DblLinear().Skip(50).First());
    //Expected result: 175

Upvotes: 2

Anton&#237;n Lejsek
Anton&#237;n Lejsek

Reputation: 6103

You take one item from sequence and produce two. So You really need some data structure to store them, as their numbers would increase. Heap would be the best. If You want to go with what we have directly in .net, You can use SortedSet.

public static IEnumerable<int> DblLinear2()
{
    SortedSet<int> seq = new SortedSet<int> { 1 };

    while (true)
    {
        int min = seq.First();
        seq.Remove(min);
        yield return min;
        seq.Add(min * 2 + 1);
        seq.Add(min * 3 + 1);
    }
}

The result:

1, 3, 4, 7, 9, 10, 13, 15, 19, 21, 22, 27, 28, 31, 39, 40, 43, 45, 46, 55, 57, 58, 63, 64, 67, 79, 81, 82, 85, 87...

Upvotes: 6

Related Questions