优化相邻数字的算法

时间:2018-11-18 17:39:51

标签: java

我给了两个整数“ n”和“ m”,我必须找到在[n,m]范围内的所有步进数。如果所有相邻数字的绝对差为2,则该数字称为步进数。131是步进数,而421不是。我面临的问题是我必须按排序顺序打印它们,而不能重复从小到大的数字但是我的算法会随机打印它们,并且M最多可以为10 ^ 30,这在设置我的程序时会耗尽内存。有什么建议我该怎么做?

import java.util.*;

class Main {

public static void bfs(Long n, Long m, Long num) {

    Queue<Long> q = new LinkedList<Long>();

    q.add(num);

    while (!q.isEmpty()) {

        Long stepNum = q.poll();

        if (stepNum <= m && stepNum >= n) {

            System.out.print(stepNum+" ");
        }

        if (stepNum == 0 || stepNum > m)
            continue;

        Long lastDigit = stepNum % 10;

        Long stepNumA = stepNum * 10 + (lastDigit - 2);
        Long stepNumB = stepNum * 10 + (lastDigit + 2);

        if (lastDigit == 0)
            q.add(stepNumB);

        else if (lastDigit == 9)
            q.add(stepNumA);

        else {
            q.add(stepNumA);
            q.add(stepNumB);
        }
    }
}

public static void displaySteppingNumbers(Long n, Long m) {

    for (Long i = (long) 0; i <= 9; i++)
        bfs(n, m, i);
}

// Driver code
public static void main(String args[]) {
    Long n = (long) 1;
    Long m = (long) Math.pow(10, 16);


    displaySteppingNumbers(n, m);

}
}

3 个答案:

答案 0 :(得分:1)

我相信您可能已经考虑过了。我将从一种确定单个long是否为步进数的方法开始。使用String.valueOf(long)获得String表示形式,然后遍历该String中的字符,比较相邻的值。如果两个数字的绝对差不是2,则返回false。检查所有数字后,默认为true。喜欢,

private static boolean isSteppingNumber(long v) {
    char[] arr = String.valueOf(v).toCharArray();
    for (int i = 0; i + 1 < arr.length; i++) {
        // The - '0' is really only useful for debugging.
        int a = arr[i] - '0', b = arr[i + 1] - '0';
        if (Math.abs(b - a) != 2) {
            return false;
        }
    }
    return true;
}

并且,如果有帮助,您可以使用lambda之类的方法

private static boolean isSteppingNumber(long v) {
    char[] arr = String.valueOf(v).toCharArray();
    return IntStream.range(0, arr.length - 1)
            .allMatch(i -> Math.abs(arr[i + 1] - arr[i]) == 2);
}

接下来,从nm的循环(我更喜欢原始的long类型)。喜欢,

public static void displaySteppingNumbers(long n, long m) {
    LongStream.rangeClosed(n, m).filter(x -> isSteppingNumber(x))
            .forEachOrdered(System.out::println);
}

答案 1 :(得分:0)

您有一个正确的想法,就是可以像搜索图形一样搜索数字。但是,为了以正确的顺序获取它们,我建议使用最低优先级队列而不是队列。

您的实现还有另一个问题-您没有正确检查邻接关系的边界,例如如果lastDigit大于7,则lastDigit + 2不相邻。

import java.util.*;

public class Main {

    public static void displaySteppingNumbers(Long m, Long n) {
        PriorityQueue<Long> heap = new PriorityQueue<>();
        for (Long i = 1L; i <= 9L; i++) {
            heap.add(i);
        }

        while (heap.peek() <= n) {
            Long steppingNumber = heap.poll();
            System.out.println(steppingNumber);
            Long lastDigit = steppingNumber % 10;
            if (lastDigit >= 2)
                heap.add(steppingNumber * 10 + lastDigit - 2);
            if (lastDigit <= 7)
                heap.add(steppingNumber * 10 + lastDigit + 2);
        }
    }


    public static void main(String []args){
        Long m = 100L;
        Long n = 300L;

        displaySteppingNumbers(m, n);
    }
}

答案 2 :(得分:0)

请在将来发布伪信息。 这是程序中前1000个数字的输出:

1 9 13 97 131 135 975 979 
2 20 24 202 242 246 
3 31 35 309 313 353 357 
4 42 46 420 424 464 468 
5 53 57 531 535 575 579 
6 64 68 642 646 686 690 
7 75 79 753 757 797 
8 86 90 864 868 902 
9 97 975 979 

我只是在每个bfs调用之前添加了/n
这实际上是一个有趣的小难题
写出一组数字的输出
您会找到一个二进制链接,其中0表示
依次减2和1,再在
中减2 序列,即数字131357可以写为:
110111,您只需要查找之间的所有二进制数
给定范围,这就是您的解决方案:D