简体   繁体   中英

Need help calculating the elements of a sequence

I wrote an algorithm that is supposed to calculate the nth element of a sequence, up to n = 2000000. This sequence is as following:

1 - The first element is 1;

2 - For each element x of the sequence, the elements 2x + 1 and 3x + 1 are also contained in the sequence;

3 - Every element is in ascending order, and there are no duplicate elements;

4 - The sequence has no other values;

such that the first few elements are [1, 3, 4, 7, 9, 10, 13, 15...], seq(50) = 175, seq(50000) = 1237222, seq(1234567) = 71221051, etc.

I wrote the following code:

public static long seq(int n) {
    LinkedList<Long> sequence = new LinkedList<>();
    int doubleCount = 0;
    int tripleCount = 0;
    long elementDouble = 1;
    long elementTriple = 0;
    sequence.addLast(elementDouble);
    while (sequence.size() <= n + 2) {
        elementDouble = 2 * sequence.get(doubleCount) + 1; 
        elementTriple = 3 * sequence.get(tripleCount) + 1;
        if (elementDouble < elementTriple && elementDouble > sequence.getLast()) {
            sequence.addLast(elementDouble);
            doubleCount++;
        } else if (elementDouble == sequence.getLast()) {
            doubleCount++;
        } else if (elementTriple > sequence.getLast()) {
            sequence.addLast(elementTriple);
            tripleCount++;
        } else {
            tripleCount++;
        }
    }
    return sequence.get(n);
}

which calculates 2x + 1 and 3x + 1 seperately, so that the smallest of the two values is added to the list and the other one stored and compared to its next counterpart. This gives me the correct results. However, for values of n greater than 1000000, it is extremely slow (over 5 minutes runtime). Is there any way I can improve the code so that I can use it for extremely large instances of n?

Thank you very much for your help:)

You might try maintaining two separate queues, q1 and q2 . Make 1 the first element of the sequence, and then enqueue 2*1 + 1 == 3 in q1 and 3*1 + 1 == 4 in q2 . The next element of the sequence is the smaller of the two elements at the front of each queue. Dequeue it and call it x . The next element of your sequence is x , and you can enqueue 2*x + 1 in q1 and 3*x + 1 in q2 .

Your code does very badly because you're calling get(index) on a LinkedList . Change to use ArrayList will greatly improve performance:

public static long seq(int n) {
    ArrayList<Long> sequence = new ArrayList<>();
    int doubleCount = 0;
    int tripleCount = 0;
    long elementDouble = 1;
    long elementTriple = 0;
    sequence.add(elementDouble);
    while (sequence.size() <= n + 2) {
        elementDouble = 2 * sequence.get(doubleCount) + 1; 
        elementTriple = 3 * sequence.get(tripleCount) + 1;
        if (elementDouble < elementTriple && elementDouble > sequence.get(sequence.size() - 1)) {
            sequence.add(elementDouble);
            doubleCount++;
        } else if (elementDouble == sequence.get(sequence.size() - 1)) {
            doubleCount++;
        } else if (elementTriple > sequence.get(sequence.size() - 1)) {
            sequence.add(elementTriple);
            tripleCount++;
        } else {
            tripleCount++;
        }
    }
    return sequence.get(n);
}

Tests

public static void main(String[] args) {
    test(50);
    test(50000);
    test(1000000);
    test(1234567);
    test(10000000);
    test(100000000);
}
static void test(int n) {
    long start = System.nanoTime();
    long seq = seq(n);
    long end = System.nanoTime();
    System.out.printf("%d: %d (%.9fs)%n", n, seq, (end - start) / 1e9);
}

Output

50: 175 (0.000202500s)
50000: 1237222 (0.008792100s)
1000000: 54381286 (0.100169600s)
1234567: 71221051 (0.084787500s)
10000000: 1031926810 (0.454602800s)
100000000: 19115394879 (4.044839300s)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM