The sum of the divisors of an N number - c#

Find then sum all the divisors from 1 to N.
The main problem is, that this code runs really poor with high numbers.
The following code was taken from: https://www.geeksforgeeks.org/sum-divisors-1-n
static int divisorSum(int n)
{
int sum = 0;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j * j <= i; ++j)
{
if (i % j == 0)
{
if (i / j == j)
sum += j;
else
sum += j + i / j;
}
}
}
return sum;
}

Based on #Joel solution, I just improved it:
static long divisorSum(int n)
{
long sum = 0;
for (long i = 1; i <= n/2; ++i)
sum += i * (n / i);
sum += (n/2+1+n)*(n-n/2)/2; // It's a sum of an arithmetic progression‏‏‏‏
return sum;
}
For i > n/2 the expression i * (n / i) is simply i (because n/i = 1), so we can get the sum of all the numbers between n/2 + 1 to n by computing a sum of an arithmetic progression‏‏‏‏. It will run faster, although it is O(n) too.

You could do something like this O(n):
static long divisorSum(int n)
{
long sum = 0;
for (long i = 1; i <= n; ++i)
sum += i * (n / i);
return sum;
}
static void Main(string[] args)
{
int val = 129999;
Console.WriteLine(divisorSum(val));
Console.ReadLine();
}
Tests:
12999 => 8ms
129999 => 25ms
2147483647 => 18770ms (Max Int32 value)
int val = 129999;
int maxInt = int.MaxValue;
//val (129999)
var watch = System.Diagnostics.Stopwatch.StartNew();
Console.WriteLine(divisorSum(val));
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Console.WriteLine(elapsedMs); //25ms
//MaxInt (2147483647)
watch = System.Diagnostics.Stopwatch.StartNew();
Console.WriteLine(divisorSum(maxInt));
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds; //18770ms
Console.WriteLine(elapsedMs);
Console.ReadLine();

There is no need to use a collection of sorts, since you sum everything up and don't need to think about duplicates. I don't think there is a way to get a solution for this which is a perfect O(n), but this is the closest I can think of:
int sum = 0;
for (int i = 1; i <= n; i++)
{
double sqrt = Math.Sqrt (i);
for (int j = 1; j <= sqrt; j++)
{
if (i % j == 0)
{
sum += j;
if (j != sqrt)
sum += i / j;
}
}
}
Divisors are pairs, so there isn't a need to go all the way to i every time (e.g 1 * 10, 10 * 1 are the same). You can go till the square-root of i (the 'mid-point'), and save time, hence it's not O(n^2), but not perfectly O(n).

Related

Factorials of Big numbers without BigInteger (C#)

Is there an algorithm for calculating a factorial without using System.Numerics library? We receive an int number and we need to return factorial of this number as string(if n = 30, we should return "265252859812191058636308480000000", if n = 70, we should return "11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000" ect. Numbers are very big)
I tried to find out, did anyone already write an article about that, but I didn't find anything.
It suffices to implement multiplication of a large number as a string by a small integer.
Illustration: 12! = 11! x 12 is obtained by multiplying every digit by 12 and summing (with shifts):
39916800
36
108
108
12
72
96
0
0
---------
479001600
A lazy solution. It is possible to evaluate the factorial with just BigNum addition, replacing the multiplications by successive additions. (For n!, we will perform 1+2+3+...n-1 additions. This is acceptable for moderate n.)
The computation uses two pre-allocated string (arrays of char), which are initially filled with null bytes (Writeline skips them). When adding from right to left, we stop when we meet a null.
int n = 20;
// Factorial and temporary string; 100! fits in 158 digits
const int N = 158;
char[] f = new char[N], t = new char[N];
f[N - 1] = '1'; // 1!
// Product up to n by successive additions
for (int i = 2; i <= n; i++)
{
// t= f
f.CopyTo(t, 0);
for (int j = 0; j < i - 1; j++)
{
// f+= t, repeated i-1 times
int c = 0; // Carry
for (int k = N - 1; k >= 0; k--)
{
if (t[k] == 0 && c == 0) break; // Significant part exhausted
int d = Math.Max(0, t[k] - '0') + Math.Max(0, f[k] - '0') + c;
c= d / 10; d = d % 10; f[k] = (char)(d + '0'); // Next carry/digit
}
}
Console.WriteLine(f);
}
Output:
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
static string FindFactorial(int n)
{
int[] result = new int[500000];
result[0] = 1;
int resultSize = 1;
for (int x = 2; x <= n; x++)
resultSize = Multiply(x, result, resultSize);
string factorial = "";
for (int i = resultSize - 1; i >= 0; i--)
factorial += result[i].ToString();
return factorial;
}
static int Multiply(int x, int[] result, int resultSize)
{
int carry = 0;
for (int i = 0; i < resultSize; i++)
{
int product = result[i] * x + carry;
result[i] = product % 10;
carry = product / 10;
}
while (carry != 0)
{
result[resultSize] = carry % 10;
carry /= 10;
resultSize++;
}
return resultSize;
}
This will work

Computing the product of big numbers

I'm trying to compute
,
where Ci is the i-th Catalan number.
To solve the problem, I loop from 0 to n and sum the product of two Catalan numbers:
BigInteger catalanSum = 0;
for (int i = 0; i <= n; i++)
catalanSum += catalan(i) * catalan(n - i);
The catalan function is returning the binomial coefficent divided by n + 1:
BigInteger catalan(int n)
{
return NchooseK(2 * n, n) / (n + 1);
}
And to compute the binomial coefficient I use this function:
BigInteger NchooseK(int n, int k)
{
BigInteger res = 1;
if (k > n - k)
k = n - k;
for (int i = 0; i < k; ++i)
{
res *= (n - i);
res /= (i + 1);
}
return res;
}
It works fine up to n = 1000, but as soon it get highers it really slows down alot. Is there any way I can optimize this calculation?
EDIT:
I sped up the computation by saving the catalans first using the following code-snippet, thanks to xanatos answer:
BigInteger[] catalans = new BigInteger[n+1];
BigInteger catalanSum = 0;
for (int i = 0; i <= n; i++)
catalans[i] = catalan(i);
for (int i = 0; i <= n; i++)
catalanSum += catalans[i] * catalans[n - i];
EDIT 2:
When catalan[i] == catalan[n - i], wouldn't the remaining half of computations have the same product as the first half?
The computation you are describing seems like the first recurrence relation for computing the nth Catalan Number (and you're needlessly applying a binomial computation as well when you could just use the Catalan numbers themselves in the recurrence). That's O(n^2) complexity plus the complexity for all the binomial computations. Why not use the second recurrence relation?
catalan(0) = 1
catalan(n + 1) = 2*(2*n + 1) / (n + 2) * n
There are two things you can do:
First, check OEIS for your sequence. You will find that the sequence has an entry. And this entry has a useful formula:
2*(2*n-1)*a(n-1) = (n+1)*a(n)
So, calculating the Catalan numbers can be done much more efficiently:
BigInteger lastCatalan = 1;
catalans[0] = lastCatalan;
for(int i = 1; i <= n; ++i)
{
lastCatalan = (2 * (2 * i - 1) * lastCatalan) / (i + 1);
catalans[i] = lastCatalan;
}
The second thing is that your summation is symmetric. I.e., you just need to sum half of the entries:
BigInteger catalanSum = 0;
for (int i = 0; i < (n + 1) / 2; i++)
catalanSum += catalans[i] * catalans[n - i];
catalanSum = 2 * catalanSum;
if (n % 2 == 0)
catalanSum += catalans[n / 2] * catalans[n / 2];
After גלעד ברקן pointed out that the sum you are looking for is the n+1-th Catalan number, this can be simplified drastically:
BigInteger catalanSum= 1;
for(int i = 1; i <= n + 1; ++i)
catalanSum = (2 * (2 * i - 1) * catalanSum) / (i + 1);
You could also cache the factorials.

C# Sum of digits of a number if the sum equals 9

i want all the numbers with 3 digits that have the sum of 9 to be write in the console.
This is what i came up so far and it doesnt work:
class Program
{
static void Main(string[] args)
{
int sum = 0;
for (int n = 100; n < 1000; n++)
{
while (n <1000)
{
sum += n % 10;
n /= 10;
if (sum == 9)
Console.WriteLine(sum);
}
}
}
}
I'd use three loops, one for every digit:
for (int i1 = 1; i1 < 10; i1++)
for (int i2 = 0; i2 < 10; i2++)
for (int i3 = 0; i3 < 10; i3++)
{
if (i1 + i2 + i3 == 9)
Console.WriteLine("{0}{1}{2}", i1, i2, i3);
}
You're not resetting sum after every loop iteration. sum should equal zero at the start of every iteration like. Also, the while loop is wrong. Try this:
for(int n=100;n<1000;n++)
{
sum=0;
int i = n;
while(i!=0) {
sum += i % 10;
i /= 10;
}
if (sum == 9)
Console.WriteLine("Number {0} has digit sum of {1}", n, sum);
}
Why soo commplicated?
for (int n = 100; n < 1000; n++)
{
var s1 = n/100 % 10;
var s2 = n/10 % 10;
var s3 = n/1 % 10;
var sum = s1+s2+s3;
if (sum == 9)
Console.WriteLine(n);
}
For people, who dont like easy way :D
Enumerable.Range(0, 1000).Select(x => x.ToString())
.Where(x => x.Length == 3).Select(x => new {x, sum=x.ToCharArray()
.Select(c=>int.Parse(c.ToString())).Sum()}).Where(x=>x.sum == 9)
.Select(x=>x.x).ToList().ForEach(Console.WriteLine);
Oki, tried to create non-generic but fastest solution.
for (var i = 1; i <= 10; i++)
for (var j = 0; j < 10; j++)
{
if ((i>1 && j == 0) || i < j)
{
Console.WriteLine(i * 90 + j * 9);
}
}
I think you are looking for this:
class Program
{
static void Main(string[] args)
{
for (int n = 100; n < 1000; n++)
{
int sum = 0;
int num = n;
while (num != 0)
{
int r = num % 10;
sum += r;
num /= 10;
}
if (sum == 9)
Console.WriteLine(n);//.....Number whose all digit sum ==9
}
}
}

MaxCounters codility understanding

I have wanted to try some challenges on Codility and started from beginning. All assignments were relatively easy up to the one called MaxCounters. I do not believe that this one is especially hard although it is the first one marked as not painless.
I have read the task and started coding in C# language:
public static int[] maxPart(int N, int[] A){
int[] counters = new int[N];
for(int i = 0; i < A.Length; i++){
for(int j = 0; j < counters.Length; j++){
if(A[i] == counters[j] && (counters[j] >= 1 && counters[j] <= N )){
counters [j] = counters [j] + 1;
}
if(A[i] == N + 1 ){
int tmpMax = counters.Max ();
for(int h = 0; h < counters.Length; h++){
counters [h] = tmpMax;
}
}
}
}
return counters;
}
Having 3 loops of course makes it really slow, but lets leave it for later. My concern is how I understood this like this and all the other people see it like on this question here.
From the assignment's description.
it has 2 actions:
increase(X) − counter X is increased by 1,
max counter − all counters are set to the maximum value of any
counter.
which occur under conditions:
if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
if A[K] = N + 1 then operation K is max counter.
Both conditions are stated in the code above. Obviusly it is wrong but I am confused, and I do not know how could I understand it differently.
Why is this code wrong, what am I missing from task description?
One of the top rated answers looks like this:
public int[] solution(int N, int[] A) {
int[] result = new int[N];
int maximum = 0;
int resetLimit = 0;
for (int K = 0; K < A.Length; K++)
{
if (A[K] < 1 || A[K] > N + 1)
throw new InvalidOperationException();
if (A[K] >= 1 && A[K] <= N)
{
if (result[A[K] - 1] < resetLimit) {
result[A[K] - 1] = resetLimit + 1;
} else {
result[A[K] - 1]++;
}
if (result[A[K] - 1] > maximum)
{
maximum = result[A[K] - 1];
}
}
else
{
// inefficiency here
//for (int i = 0; i < result.Length; i++)
// result[i] = maximum;
resetLimit = maximum;
}
}
for (int i = 0; i < result.Length; i++)
result[i] = Math.max(resetLimit, result[i]);
return result;
}
This code results with 100% on Codility.
Question:
I would like to know how the author knew from the task to use result[A[K] - 1]? What would resetLimit represent?
Maybe I completely misunderstood the question due to my English I am not sure. I just can not go over it.
EDIT:
Based on my code provided, how did I misunderstood the assignment? Generally I am asking for explanation of the problem. Whether to explain what needs to be done, or take the code as correct result and provide and explanation why is this done this way?
In my opinion you somehow mixed the index of the counter (values in A) and the value of the counter (values in counter). So there is no magic in using A[i]-1 - it is the value X from the problem description (adjusted to 0-based index).
My naive approach would be, the way I understood the problem (I hope it makes clear, what your code is doing wrong):
public static int[] maxPart(int N, int[] A){
int[] counters = new int[N];
for(int i = 0; i < A.Length; i++){
int X=A[i];
if(X>=1 && X<=N){ // this encodes increment(X), with X=A[i]
counters [X-1] = counters [X-1] + 1; //-1, because our index is 0-based
}
if(X == N + 1 ){// this encodes setting all counters to the max value
int tmpMax = counters.Max ();
for(int h = 0; h < counters.Length; h++){
counters [h] = tmpMax;
}
}
}
}
return counters;
}
Clearly, this would be too slow as the complexity isO(n^2) with n=10^5 number of operations (length of the array A), in the case of the following operation sequence:
max counter, max counter, max counter, ....
The top rated solution solves the problem in a lazy manner and does not update all values explicitly every time a max counter operation is encountered, but just remembers which minimal value all counters must have after this operation in resetLimit. Thus, every time he must increment a counter, he looks up whether its value must be updated due to former max counter operations and makes up for all max counter operation he didn't execute on this counter
if(result[A[K] - 1] < resetLimit) {
result[A[K] - 1] = resetLimit + 1;
}
His solution runs in O(n) and is fast enough.
Here is my solution in JavaScript.
const maxCounters = (N, A) => {
for (let t = 0; t < A.length; t++) {
if (A[t] < 1 || A[t] > N + 1) {
throw new Error('Invalid input array A');
}
}
let lastMaxCounter = 0; // save the last max counter is applied to all counters
let counters = []; // counters result
// init values by 0
for (let i = 0; i < N; i++) {
counters[i] = 0;
}
let currentMaxCounter = 0; // save the current max counter each time any counter is increased
let maxApplied = false;
for (let j = 0; j < A.length; j++) {
const val = A[j];
if (1 <= val && val <= N) {
if (maxApplied && counters[val - 1] < lastMaxCounter) {
counters[val - 1] = lastMaxCounter;
}
counters[val - 1] = counters[val - 1] + 1;
if (currentMaxCounter < counters[val - 1]) {
currentMaxCounter = counters[val - 1];
}
} else if (val === N + 1) {
maxApplied = true;
lastMaxCounter = currentMaxCounter;
}
}
// apply the lastMaxCounter to all counters
for (let k = 0; k < counters.length; k++) {
counters[k] = counters[k] < lastMaxCounter ? lastMaxCounter : counters[k];
}
return counters;
};
Here is C# solution give me 100% score
public int[] solution(int N, int[] A) {
int[] operation = new int[N];
int max = 0, globalMax = 0;
foreach (var item in A)
{
if (item > N)
{
globalMax = max;
}
else
{
if (operation[item - 1] < globalMax)
{
operation[item - 1] = globalMax;
}
operation[item - 1]++;
if (max < operation[item - 1])
{
max = operation[item - 1];
}
}
}
for (int i = 0; i < operation.Length; i++)
{
if (operation[i] < globalMax)
{
operation[i] = globalMax;
}
}
return operation;
}
Here is a pretty elegant soulution in Swift:
public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
var globalMax = 0
var currentMax = 0
var maximums: [Int: Int] = [:]
for x in A {
if x > N {
globalMax = currentMax
continue
}
let newValue = max(maximums[x] ?? globalMax, globalMax) + 1
currentMax = max(newValue, currentMax)
maximums[x] = newValue
}
var result: [Int] = []
for i in 1...N {
result.append(max(maximums[i] ?? globalMax, globalMax))
}
return result
}
Try this Java snippet. Its more readable and neater, you don't need to worry about bounds check and might evacuate your first findings related to the more efficient approach you have found, btw the max is on the main forloop not causing any overhead.
public final int[] solution(int N, int[] A)
{
int condition = N + 1;
int currentMax = 0;
int lastUpdate = 0;
int[] counters = new int[N];
for (int i = 0; i < A.length; i++)
{
int currentValue = A[i];
if (currentValue == condition)
{
lastUpdate = currentMax;
}
else
{
int position = currentValue - 1;
if (counters[position] < lastUpdate)
{
counters[position] = lastUpdate + 1;
}
else
{
counters[position]++;
}
if (counters[position] > currentMax)
{
currentMax = counters[position];
}
}
}
for (int i = 0; i < N; i++)
{
if (counters[i] < lastUpdate)
{
counters[i] = lastUpdate;
}
}
return counters;
}
Inspired by Andy's solution, here is a solution in Python that is O(N + M) and gets a score of 100. The key is to avoid the temptation of updating all the counters every time A[K] > 5. Instead you keep track of a global max and reset an individual counter to global max just before you have to increment it. At the end, you set the remaining un-incremented counters to global max. See the comments in the code below:
def solution(N,A):
max = 0
global_max = 0
counters = [0] * N
for operation in A:
if operation > N:
#don't update counters.
#Just keep track of global max until you have to increment one of the counters.
global_max = max
else:
#now update the target counter with global max
if global_max > counters[operation - 1]:
counters[operation - 1] = global_max
#increment the target counter
counters[operation - 1] += 1
#update max after having incremented the counter
if counters[operation - 1] > max:
max = counters[operation - 1]
for i in range(N):
#if any counter is smaller than global max, it means that it was never
#incremented after the global_max was reset. Its value can now be updated
#to global max.
if counters[i] < global_max:
counters[i] = global_max
return counters
Here's a C# solution that gave me 100% score.
The idea is to simply not update the max counters on the spot but rather do it when you actually get to that counter, and then even out any counters that were not set to the max in another loop.
class Solution
{
public int[] solution(int N, int[] A)
{
var result = new int[N];
var latestMax = 0;
var currentMax = 0;
for (int i = 0; i < A.Length; i++)
{
var currentValue = A[i];
if (currentValue >= 1 && currentValue <= N)
{
if (result[currentValue - 1] < currentMax)
{
result[currentValue - 1] = currentMax;
}
result[currentValue - 1]++;
if (result[currentValue - 1] > latestMax)
{
latestMax = result[currentValue - 1];
}
}
else if (currentValue == N + 1)
{
currentMax = latestMax;
}
}
for (int i = 0; i < result.Length; i++)
{
if (result[i] < currentMax)
{
result[i] = currentMax;
}
}
return result;
}
}

Sum of digits in C#

What's the fastest and easiest to read implementation of calculating the sum of digits?
I.e. Given the number: 17463 = 1 + 7 + 4 + 6 + 3 = 21
You could do it arithmetically, without using a string:
sum = 0;
while (n != 0) {
sum += n % 10;
n /= 10;
}
I use
int result = 17463.ToString().Sum(c => c - '0');
It uses only 1 line of code.
For integer numbers, Greg Hewgill has most of the answer, but forgets to account for the n < 0. The sum of the digits of -1234 should still be 10, not -10.
n = Math.Abs(n);
sum = 0;
while (n != 0) {
sum += n % 10;
n /= 10;
}
It the number is a floating point number, a different approach should be taken, and chaowman's solution will completely fail when it hits the decimal point.
public static int SumDigits(int value)
{
int sum = 0;
while (value != 0)
{
int rem;
value = Math.DivRem(value, 10, out rem);
sum += rem;
}
return sum;
}
int num = 12346;
int sum = 0;
for (int n = num; n > 0; sum += n % 10, n /= 10) ;
I like the chaowman's response, but would do one change
int result = 17463.ToString().Sum(c => Convert.ToInt32(c));
I'm not even sure the c - '0', syntax would work? (substracting two characters should give a character as a result I think?)
I think it's the most readable version (using of the word sum in combination with the lambda expression showing that you'll do it for every char). But indeed, I don't think it will be the fastest.
I thought I'd just post this for completion's sake:
If you need a recursive sum of digits, e.g: 17463 -> 1 + 7 + 4 + 6 + 3 = 21 -> 2 + 1 = 3
then the best solution would be
int result = input % 9;
return (result == 0 && input > 0) ? 9 : result;
int n = 17463; int sum = 0;
for (int i = n; i > 0; i = i / 10)
{
sum = sum + i % 10;
}
Console.WriteLine(sum);
Console.ReadLine();
I would suggest that the easiest to read implementation would be something like:
public int sum(int number)
{
int ret = 0;
foreach (char c in Math.Abs(number).ToString())
ret += c - '0';
return ret;
}
This works, and is quite easy to read. BTW: Convert.ToInt32('3') gives 51, not 3. Convert.ToInt32('3' - '0') gives 3.
I would assume that the fastest implementation is Greg Hewgill's arithmetric solution.
private static int getDigitSum(int ds)
{
int dssum = 0;
while (ds > 0)
{
dssum += ds % 10;
ds /= 10;
if (dssum > 9)
{
dssum -= 9;
}
}
return dssum;
}
This is to provide the sum of digits between 0-9
public static int SumDigits1(int n)
{
int sum = 0;
int rem;
while (n != 0)
{
n = Math.DivRem(n, 10, out rem);
sum += rem;
}
return sum;
}
public static int SumDigits2(int n)
{
int sum = 0;
int rem;
for (sum = 0; n != 0; sum += rem)
n = Math.DivRem(n, 10, out rem);
return sum;
}
public static int SumDigits3(int n)
{
int sum = 0;
while (n != 0)
{
sum += n % 10;
n /= 10;
}
return sum;
}
Complete code in: https://dotnetfiddle.net/lwKHyA
int j, k = 1234;
for(j=0;j+=k%10,k/=10;);
A while back, I had to find the digit sum of something. I used Muhammad Hasan Khan's code, however it kept returning the right number as a recurring decimal, i.e. when the digit sum was 4, i'd get 4.44444444444444 etc.
Hence I edited it, getting the digit sum correct each time with this code:
double a, n, sumD;
for (n = a; n > 0; sumD += n % 10, n /= 10);
int sumI = (int)Math.Floor(sumD);
where a is the number whose digit sum you want, n is a double used for this process, sumD is the digit sum in double and sumI is the digit sum in integer, so the correct digit sum.
static int SumOfDigits(int num)
{
string stringNum = num.ToString();
int sum = 0;
for (int i = 0; i < stringNum.Length; i++)
{
sum+= int.Parse(Convert.ToString(stringNum[i]));
}
return sum;
}
If one wants to perform specific operations like add odd numbers/even numbers only, add numbers with odd index/even index only, then following code suits best. In this example, I have added odd numbers from the input number.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Please Input number");
Console.WriteLine(GetSum(Console.ReadLine()));
}
public static int GetSum(string num){
int summ = 0;
for(int i=0; i < num.Length; i++){
int currentNum;
if(int.TryParse(num[i].ToString(),out currentNum)){
if(currentNum % 2 == 1){
summ += currentNum;
}
}
}
return summ;
}
}
The simplest and easiest way would be using loops to find sum of digits.
int sum = 0;
int n = 1234;
while(n > 0)
{
sum += n%10;
n /= 10;
}
#include <stdio.h>
int main (void) {
int sum = 0;
int n;
printf("Enter ir num ");
scanf("%i", &n);
while (n > 0) {
sum += n % 10;
n /= 10;
}
printf("Sum of digits is %i\n", sum);
return 0;
}
Surprised nobody considered the Substring method. Don't know whether its more efficient or not. For anyone who knows how to use this method, its quite intuitive for cases like this.
string number = "17463";
int sum = 0;
String singleDigit = "";
for (int i = 0; i < number.Length; i++)
{
singleDigit = number.Substring(i, 1);
sum = sum + int.Parse(singleDigit);
}
Console.WriteLine(sum);
Console.ReadLine();

Categories