有更有效的方法吗? 给定数字N - 找到所有自恋(阿姆斯特朗)数字< N. 这是我的代码,但我想有更高效的解决方案。也许,我们可以通过位操作解决它吗?
public static void main(String args[]) throws Exception
{
long a = System.nanoTime();
int t [] = getNumbers(4_483_647L);
long b = System.nanoTime();
System.out.println("Time totally "+(b-a));
for(int k: t)
System.out.print(k+" ");
}
public static int[] getNumbers(long N)
{
int length=1;
int porog=10, r=1, s=1;
double k;
LinkedList<Integer> list = new LinkedList<>();
for(int i=1; i<N; i++)
{
if(i==porog)
{
length++;
porog*=10;
}
s = i;
k=0;
while(s>0)
{
r = s%10;
k+=Math.pow(r, length);
if(k>i)break;
s=s/10;
}
if((int)k==i)
list.add(i);
}
int[] result = new int[list.size()];
int i=0;
for(int n: list)
{
result[i] = n;
i++;
}
return result; } }
答案 0 :(得分:3)
一些观察结果:
long
,那么您的结果也应该是long
类型,以防万一(int
适合您,因为自恋数字相距很远)Long
,则可以使用Collections.toArray()
将结果重新打包到数组中...... Math.pow()
,因为你可以在每个十年使用乘法从上面的评论中应用我的想法并更改方法签名,你得到的东西运行速度提高了大约30倍:
public static Long[] getNumbers(long N) {
int porog = 10;
LinkedList<Long> list = new LinkedList<>();
// initial powers for the number 0-9
long[] powers = { 0l, 1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l };
for (long i = 1; i < N; i++) {
if (i == porog) {
porog *= 10;
// calculate i^length
for (int pi = 1; pi < 10; pi++) {
powers[pi] *= pi;
}
}
long s = i;
long k = 0;
while (s > 0) {
int r = (int)(s % 10);
k += powers[r];
if (k > i)
break;
s /= 10;
}
if (k == i)
list.add(i);
}
return list.toArray(new Long[]{});
}
答案 1 :(得分:2)
来自Rosetta Code blog(不是我自己的代码)
public static boolean isNarc(long x){
if(x < 0) return false;
String xStr = Long.toString(x);
int m = xStr.length();
long sum = 0;
for(char c : xStr.toCharArray()){
sum += Math.pow(Character.digit(c, 10), m);
}
return sum == x;
}
答案 2 :(得分:1)
主要优化是不来检查范围内的所有数字(for(int i=1; i<N; i++)
)。看看here。
答案 3 :(得分:1)
可以非常有效地生成阿姆斯特朗数字。例如,可以在10-15毫秒内生成所有整数。
我们可能会注意到,对于每个多组数字,例如[1, 1, 2, 4, 5, 7, 7]
,只有一个权力总和,而这些权力又可能是或者不是来自集合中的数字。在示例1^7 + 1^7 + 2^7 + 4^7 + 5^7 + 7^7 + 7^7 = 1741725
中,可以用数字表示,因此是阿姆斯壮的数字。
我们可以基于这种考虑建立算法。
1 to N
N
位数digits^N
为每个长度N
计算的案例数等于组合数(N + 9, 9) = (N+9)!/(9!N!)
。因此,对于小于10的所有Ns
,我们将仅生成92,377个多集。 N<20
:20,030,009。
请参阅GitHub以了解一些方法的说明,以及一些基准测试和Java代码。请享用! :)
答案 4 :(得分:1)
我不是专业的编码人员,只是自学成才,没有工作经验,因此,如果我的代码有点草率,我深表歉意。
我采用了dovetalk的解决方案,并且1)自己编写了它,以便更好地理解它。b)进行了一些调整,从而大大延长了运行时间。我希望这可以帮助其他人寻求有关此问题的帮助:
public static long[] getNumbers(long N) {
long tempII = N;
LinkedHashSet<Long> narcNums = new LinkedHashSet<>();
long tempResult;
long digitLengthTemp = 10;
long tempI;
long[] powers = {0l, 1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l};
for (long i = 0; i < N; i++) {
if (i == digitLengthTemp) {
digitLengthTemp *= 10;
for (short x = 2; x < powers.length; x++) powers[x] *= x;
}
//set value of top digits of numbers past first 3 to a remedial value
tempI = i;
long remedialValue = 0;
tempI /= 10; tempI /= 10; tempI /= 10;
while (tempI > 0) {
short index = (short) (tempI % 10);
remedialValue += powers[index];
tempI /= 10;
}
//only passes 1000 at a time to this loop and adds each result to remedial top half
for (int j = 0; j < (tempII > 1000 ? 1000 : tempII); j++) {
//sets digit length and increases the values in array
if (i == 0 && j == digitLengthTemp) {
digitLengthTemp *= 10;
for (short x = 2; x < powers.length; x++) powers[x] *= x;
}
//resets temp results
tempResult = remedialValue;
tempI = j;
//gets the sum of each (digit^numberLength) of number passed to it
while (tempI > 0) {
if (tempResult > i + j) break;
short index = (short) (tempI % 10);
tempResult += powers[index];
tempI /= 10;
}
//checks if sum equals original number
if (i + j == tempResult) narcNums.add(i + j);
}
i += 999; // adds to i in increments of 1000
tempII -= 1000;
}
//converts to long array
long[] results = new long[narcNums.size()];
short i = 0;
for (long x : narcNums) {
results[i++] = x;
}
return results;
}