对于给定的输入n
,任务是找到largest integer that is <= n and has the highest digit sum
。
例如:
solve(100) = 99. Digit Sum for 99 = 9 + 9 = 18. No other number <= 100 has a higher digit sum.
solve(10) = 9
solve(48) = 48. Note that 39 is also an option, but 48 is larger.
Input range is 0 < n < 1e11
我尝试了什么?
我尝试了2种方法。首先,我尝试使用以下数学运算获取每个数字:
public static long solve(long n)
{
var answer = 0;
var highestSum = 0;
for (var i = 1; i <= n; i++)
{
var temp = i;
var sum = 0;
while (temp > 0)
{
sum += temp % 10;
temp /= 10;
}
if (sum >= highestSum)
{
highestSum = sum;
answer = i;
}
}
return answer;
}
第二次尝试,我尝试使用Linq扩展,如下所示:
public static long solve(long n)
{
var answer = 0;
var highestSum = 0;
for (var i = 1; i <= n; i++)
{
var sum = i.ToString().Sum(x => x - '0');
if (sum >= highestSum)
{
highestSum = sum;
answer = i;
}
}
return answer;
}
我的两个解决方案似乎都返回正确的值并为较小的值工作,但是对于较大的输入,它们似乎需要很长时间才能执行。如何使其更快地通过数字运行?是否有针对此任务的特定算法,还是我做错了其他事情?
答案 0 :(得分:4)
我们可以达到这个O(n中的位数)
如果我们迭代减少一个数字并将其右边的所有其他数字更改为9,则可以实现此目标。
让n
是我们当前的电话号码。
我们可以使用以下内容找到下一个号码:
b
是10的幂,代表当前数字的位置。每次迭代后,我们将n
减少为n/10
,并将b
更改为b*10
。
我们使用(n – 1) * b + (b – 1);
例如,如果数字为n = 521
和b = 1
,则
(521 – 1) * 1 + (1-1)
为您提供520
,这是我们需要做的事情,将位置编号减少1
,并用9
替换右边的所有其他数字
在n /= 10
给您n
作为52
之后,b*=10
给您b
作为10
,又被执行为{{1 }},这就是我们要做的(52-1)*(10) + 9
,将当前索引减少519
,将所有其他权限增加1
。
9
答案 1 :(得分:1)
可接受的答案很棒,但是我在寻找一种方法来确定正确答案而又不对数字进行求和并相互比较的过程中呆滞了。
我尝试了一些操作(如您所见,是否可以查看编辑历史记录),但是找不到公式。无奈之下,我编写了一个实用程序,向我显示了从1
到9999999
的所有数字,这些数字没有较小的数字和较大的数字,可以通过查看不足够大的数字来查看缺少的模式规模。
令我有些惊讶的是,前253
个数字中只有10
个数字与较小的数字相比,金额最大!我以某种方式认为这个数字会更大。
另外,事实证明,有一个显而易见的模式出现得相当快,并且在1000万次迭代中保持不变,所以我认为这是一个很好的模式。
下面是一些连续输出块的小样本:
0,1,2,3,4,5,6,7,8,9,
18,19,28,29,38,39,48,49,
58,59,68,69,78,79,88,89,98,99,189,198
8899,8989,8998,8999,
9899,9989,9998,9999,
18999,19899,19989,19998,19999
98999,99899,99989,99998,99999,
189999,198999,199899,199989,199998,199999
7899999,7989999,7998999,7999899,7999989,7999998,7999999,
8899999,8989999,8998999,8999899,8999989,8999998,8999999,
9899999,9989999,9998999,9999899,9999989,9999998,9999999
很明显!
9
或全9
且带有单个8
,则总和最高。
9
。这是一个代码实现:
public static long Solve(long n)
{
if (HasValidSuffix(n)) return n;
long firstDigit;
int numDigits;
// Loop to determine the first digit and number of digits in the input
for (firstDigit = n, numDigits = 1; firstDigit > 9; firstDigit /= 10, numDigits++) ;
return Enumerable.Range(0, numDigits - 1)
.Aggregate(firstDigit - 1, (accumulator, next) => accumulator * 10 + 9);
}
// Returns true for positive numbers less than 10 or
// numbers that end in either all 9's or all 9's and one 8
public static bool HasValidSuffix(long input)
{
var foundAnEight = false;
for (var n = input; n > 9; n /= 10)
{
var lastDigit = n % 10;
if (lastDigit < 8) return false;
if (lastDigit == 9) continue;
if (foundAnEight) return false;
foundAnEight = true;
}
return true;
}