首先,抱歉我的英语不好
特殊数字是数字的总和可以对数字的数字整除的数字。
示例: 135是一个特殊数字,因为数字的总和是1 + 3 + 5 = 9,数字的数字是3,9可以被3整除,因为9% 3 == 0。¥2,3,9,13,17,15,225,14825也是特殊数字。
的要求:
编写一个程序,该程序从名为SNUMS.INP的文件中读取数字n(n <= 10 ^ 6)(SNUMS.INP最多可包含10 ^ 6个数字)并将结果打印到文件SNUMS中.OUT。数字n是特殊数字的顺序,结果将是n阶的特殊数字(抱歉,我不知道如何表达它)。
示例: n = 3表示你必须打印出第3个特殊号码,即3,n = 10你需要打印出第10个特殊号码,即11号,n = 13你必须打印出13号特殊号码是17,n = 15你必须打印出第15个特殊号码,即20。
下面的示例将演示文件SNUMS.INP和SNUMS.OUT(记住:SNUMS.INP最多可包含10 ^ 6个数字)
SNUMS.INP:
2
14
17
22
SNUMS.OUT:
2
19
24
35
我有自己的算法,但运行时间超过1秒(我的SNUMS.INP有10 ^ 6个数字)。所以我需要最佳的算法,以便运行时间小于或等于1秒。
伙计们我决定发布自己用Java编写的代码,运行总是需要4秒多。你们可以提出一些改进建议或如何让它更快地运行
import java.util.Scanner;
import java.io.*;
public class Test
{
public static void main(String[]args) throws IOException
{
File file = new File("SNUMS.INP");
Scanner inputFile = new Scanner(file);
int order = 1;
int i = 1;
int[] special = new int[1000000+1];
// Write all 10^6 special numbers into an array named "special"
while (order <= 1000000)
{
if (specialNumber(i) == true)
{
special[order] = i;
order++;
}
i++;
}
// Write the result to file
PrintWriter outputFile = new PrintWriter("SNUMS.OUT");
outputFile.println(special[inputFile.nextInt()]);
while (inputFile.hasNext())
outputFile.println(special[inputFile.nextInt()]);
outputFile.close();
}
public static boolean specialNumber(int i)
{
// This method check whether the number is a special number
boolean specialNumber = false;
byte count=0;
long sum=0;
while (i != 0)
{
sum = sum + (i % 10);
count++;
i = i / 10;
}
if (sum % count == 0) return true;
else return false;
}
}
这是文件SNUMS.INP(示例)包含10 ^ 6个数字,如果你们想要测试。 https://drive.google.com/file/d/0BwOJpa2dAZlUNkE3YmMwZmlBOTg/view?usp=sharing
答案 0 :(得分:0)
我已经设法在Core i7 3.2 GHz的C#6.0(.Net 4.6 IA-64)0.6
秒内用HDD 7200 rpc解决了这个问题。希望预先计算在您的工作站上足够快:
// Precompute beautiful numbers
private static int[] BeautifulNumbers(int length) {
int[] result = new int[length];
int index = 0;
for (int i = 1; ; ++i) {
int sum = 0;
int count = 0;
for (int v = i; v > 0; sum += v % 10, ++count, v /= 10)
;
if (sum % count == 0) {
result[index] = i;
if (++index >= result.Length)
return result;
}
}
}
...
// Test file with 1e6 items
File.WriteAllLines(@"D:\SNUMS.INP", Enumerable
.Range(1, 1000000)
.Select(index => index.ToString()));
...
Stopwatch sw = new Stopwatch();
sw.Start();
// Precomputed numbers (about 0.3 seconds to be created)
int[] data = BeautifulNumbers(1000000);
// File (about 0.3 seconds for both reading and writing)
var result = File
.ReadLines(@"D:\SNUMS.INP")
.Select(line => data[int.Parse(line) - 1].ToString());
File.WriteAllLines(@"D:\SNUMS.OUT", result);
sw.Stop();
Console.Write("Elapsed time {0}", sw.ElapsedMilliseconds);
输出与
不同Elapsed time 516
到
Elapsed time 660
平均经过时间约为580
毫秒
答案 1 :(得分:0)
现在您已经在下面实现了算盘的比喻,这里有一些提示
而不是仅仅在一个周期内以1递增,我们可以更积极地增加吗?确实,我们可以,但需要额外的关注。
1
添加到数字之和,因此我们可能需要从某个数字中减去该数字,以保持sum of digits
表现良好。上面的一个问题是我们非常高兴地跳过“第一个特殊的N位数字”,但计算机不是我们一眼就能看到的。
幸运的是,“N个数字的第一个特殊”很容易计算:它是10^(N-1)+(N-1)
- 10^(N-1)
带来1
,其余为零,{{1}使其余部分使得数字的总和成为N-1
可以整除的第一个数字。当然,如果N
,这将会中断,但幸运的是,问题仅限于N > 10
特殊号码,最多需要7位数(第百万个特定号码是6806035 - 7位);
所以,我们可以检测到“带有N位数的第一个特殊数字”,我们知道我们应该小心地尝试 将它递增N.我们现在可以更好地看看“额外的”关心“?
代码 - 比前一代快两倍,在获取数据时完全“正统”(通过getter而不是直接访问数据成员)。 随意内联:
10^6
从数字构造数字必然会更快。
还记得the abacus吗?曾经用过吗?
import java.util.ArrayList;
import java.util.Arrays;
public class Abacus {
static protected int pow10[]=
{1,10,100,1000, 10000, 100000, 1000000, 10000000, 100000000}
;
// the value stored for line[i] corresponds to digit[i]*pow10[i]
protected int lineValues[];
protected int sumDigits;
protected int representedNumber;
public Abacus() {
this.lineValues=new int[0];
this.sumDigits=0;
this.representedNumber=0;
}
public int getLineValue(int line) {
return this.lineValues[line];
}
public void clearUnitLine() {
this.sumDigits-=this.lineValues[0];
this.representedNumber-=this.lineValues[0];
this.lineValues[0]=0;
}
// This is how you operate the abacus in real life being asked
// to add a number of units to the line presenting powers of 10
public boolean addWithCarry(int units, int line) {
if(line-1==pow10.length) {
// don't have enough pow10 stored
pow10=Arrays.copyOf(pow10, pow10.length+1);
pow10[line]=pow10[line-1]*10;
}
if(line>=this.lineValues.length) {
// don't have enough lines for the carry
this.lineValues=Arrays.copyOf(this.lineValues, line+1);
}
int digitOnTheLine=this.lineValues[line]/pow10[line];
int carryOnTheNextLine=0;
while(digitOnTheLine+units>=10) {
carryOnTheNextLine++;
units-=10;
}
if(carryOnTheNextLine>0) {
// we have a carry, the sumDigits will be affected
// 1. the next two statememts are equiv with "set a value of zero on the line"
this.sumDigits-=digitOnTheLine;
this.representedNumber-=this.lineValues[line];
// this is the new value of the digit to set on the line
digitOnTheLine+=units;
// 3. set that value and keep all the values synchronized
this.sumDigits+=digitOnTheLine;
this.lineValues[line]=digitOnTheLine*pow10[line];
this.representedNumber+=this.lineValues[line];
// 4. as we had a carry, the next line will be affected as well.
this.addWithCarry(carryOnTheNextLine, line+1);
}
else { // we an simply add the provided value without carry
int delta=units*pow10[line];
this.lineValues[line]+=delta;
this.representedNumber+=delta;
this.sumDigits+=units;
}
return carryOnTheNextLine>0;
}
public int getSumDigits() {
return this.sumDigits;
}
public int getRepresentedNumber() {
return this.representedNumber;
}
public int getLinesCount() {
return this.lineValues.length;
}
static public ArrayList<Integer> specials(int N) {
ArrayList<Integer> ret=new ArrayList<>(N);
Abacus abacus=new Abacus();
ret.add(1);
abacus.addWithCarry(1, 0); // to have something to add to
int increment=abacus.getLinesCount();
while(ret.size()<N) {
boolean hadCarry=abacus.addWithCarry(increment, 0);
if(hadCarry) {
// need to resynch the sum for a perfect number
int newIncrement=abacus.getLinesCount();
abacus.clearUnitLine();
if(newIncrement!=increment) {
// we switched powers of 10
abacus.addWithCarry(newIncrement-1, 0);
increment=newIncrement;
}
else { // simple carry
int digitsSum=abacus.getSumDigits();
// how much we should add to the last digit to make the sumDigits
// divisible again with the increment?
int units=increment-digitsSum % increment;
if(units<increment) {
abacus.addWithCarry(units, 0);
}
}
}
ret.add(abacus.getRepresentedNumber());
}
return ret;
}
// to understand how the addWithCarry works, try the following code
static void add13To90() {
Abacus abacus; // starts with a represented number of 0
// line==1 means units of 10^1
abacus.addWithCary(9, 1); // so this should make the abacus store 90
System.out.println(abacus.getRepresentedNumber());
// line==0 means units of 10^0
abacus.addWithCarry(13, 0);
System.out.println(abacus.getRepresentedNumber()); // 103
}
static public void main(String[] args) {
int count=1000000;
long t1=System.nanoTime();
ArrayList<Integer> s1=Abacus.specials(count);
long t2=System.nanoTime();
System.out.println("t:"+(t2-t1));
}
}