How to calculate the time complexity of the following function? - c

The time complexity of the following code is O(2^n), could you please explain to me why?
int f(int n)
{
if (n == 1)
return 1;
return 1 + f(f(n-1));
}
Thanks in advance

f(n) = n is a solution for this recurence relation
Proof:
f(n) = f(f(n-1)) + 1 = f(n-1) + 1 = (n-1) + 1 = n
Sample VBA code that verifies it:
Sub test()
For i = 1 To 20
Debug.Print i, f(i)
Next
End Sub
Function f(ByVal n As Long) As Long
If n = 1 Then
f = 1
Else
f = 1 + f(f(n - 1))
End If
End Function
Since we have established that f(n) = n, we can conclude that
f(n-1) = n-1
Assuming that it takes An calls to get f(n), An being a recurrence relation:
An = 1 + 2 * An-1
The call to calculate f(n)
The numbers of calls necessary to calculate f(n-1) which will return n-1
then the same number of calls to calculate f(f(n-1)) since we are calling f with n-1 again.
The solution of the recurrence relation is 2^n - 1

Cost complexity is 2^n -1
VBA Code:
Option Explicit
Dim count As Long
Sub test()
Dim i As Integer
For i = 1 To 20
count = 0
f i
Debug.Print i, count
Next
End Sub
Function f(ByVal n As Long) As Long
count = count + 1
If n = 1 Then
f = 1
Else
f = 1 + f(f(n - 1))
End If
End Function
Output:
1 1
2 3
3 7
4 15
5 31
6 63
7 127
8 255
9 511
10 1023
11 2047
12 4095
13 8191
14 16383
15 32767
16 65535
17 131071
18 262143
19 524287
20 1048575

Related

How is the time complexity of the following while loop will be O(logn)?

I did not understand how this piece of code will generate a complexity of O(log n).how many times the statements inside the loop will work?
int a = 0, i = N;
while (i > 0) {
a += i;
i /= 2;
}
Let N=16, number of iteration is
i | loop
--------
16 | 1
8 | 2
4 | 3
2 | 4
1 | 5
You can see log2(16) = 4 and the number of iterations is log2(16) + 1. Or you can create a formulation for it
f(N) = F(N/2) + 1. Let suppose we have N = 2^K and so we have:
F(N) = F(N/2) + 1
F(N) = F(N/4) + 1 + 1
F(N) = F(N/8) + 1 + 1 + 1 = F(N/(2^3)) + 3
...
...
...
F(N) = F(N/2^K) + K => F(2^K/2^K) + K => F(1) + K => 1 + K
So if N = 2K Then K = log2(N)
The number of iterations of the loop is the number of significant bits in N because i is halved at the end of each iteration. Hence the loop iterates log2(N) times for N>0 and none otherwise. Each iteration has 3 simple operations, an addition, a division and a test, so the time complexity is O(log(N)).

Get an 2 dimension array with 0 and 1 combination

My English is not good, so please forgive me if what I describle is not clear for you.
I want to create 2 dimension Array with 0 and 1
when I input n, it should create: Array01(1 to 2^n as long, n as long), and 0 and 1 is combination like this:
n = 1 ==> Arr (2 rows x 1 column)
0 |
1 |
n = 2 ==> Arr (4 rows x 2 columns)
0 0 |
0 1 |
1 0 |
1 1 |
n = 3 ==> Array (8 rows x 3 columns)
0 0 0 |
0 0 1 |
0 1 0 |
1 0 0 |
1 1 0 |
1 0 1 |
0 1 1 |
1 1 1 |
You can use a function like below
Option Explicit
Public Function CreateMatrix(ByVal n As Long) As Variant
Dim Matrix() As Long
ReDim Matrix(1 To 2 ^ n, 1 To n)
Dim i As Long
For i = 0 To 2 ^ n - 1
Dim BinaryString As String
BinaryString = DecToBin(i, n)
Dim c As Long
For c = 1 To n
Matrix(i + 1, c) = CLng(Mid$(BinaryString, c, 1))
Next c
Next i
CreateMatrix = Matrix
End Function
Public Function DecToBin(ByVal DecimalIn As Variant, Optional ByVal NumberOfBits As Variant) As String
Dim Result As String
DecimalIn = CDec(DecimalIn)
Do While DecimalIn <> 0
Result = Trim$(Str$(DecimalIn - 2 * Int(DecimalIn / 2))) & Result
DecimalIn = Int(DecimalIn / 2)
Loop
If Not IsMissing(NumberOfBits) Then
If Len(Result) > NumberOfBits Then
Result = "Error - Number too large for bit size"
Else
Result = Right$(String$(NumberOfBits, "0") & Result, NumberOfBits)
End If
End If
DecToBin = Result
End Function
and call it like
' generate the matrix
Dim MyMatrix() As Long
MyMatrix = CreateMatrix(n:=3)
' and write it to a sheet
Worksheets("Sheet1").Range("A1").Resize(UBound(MyMatrix, 1), UBound(MyMatrix, 2)).Value = MyMatrix
How does this work?
If we look at the matrix below we can see each row as a binary number that can be converted into a decimal number. So binary 000 is decimal 0, then binary 001 is decimal 1 and binary 010 is decimal 2 and so on:
0 0 0 | 'decimal 0
0 0 1 | 'decimal 1
0 1 0 | 'decimal 2
1 0 0 | 'decimal 3
1 1 0 | 'decimal 4
1 0 1 | 'decimal 5
0 1 1 | 'decimal 6
1 1 1 | 'decimal 7
So we know if we want to create that matrix we need to convert the decimal numbers 1 to 7 into binary numbers. Each of this binary numbers then represents one row of the matrix.
Since the only number to define the martix is n (in the example n = 3) we can use that to calculate the dimensions of the matrix:
rows: 2 ^ n (in the example 2^3 = 8)
columns: n
So we define a matrix of that size ReDim Matrix(1 To 2 ^ n, 1 To n).
Then we need to generatate the decimal numbers from 1 to 7 to be able to convert them into binaries. We do that with a loop: For i = 0 To 2 ^ n - 1 (in the example this means For i = 0 To 7).
In that loop we convert each decimal number i into a binary string of the length n. We do that using BinaryString = DecToBin(i, n).
Finally we just need to split that string into the columns of our matrix. Therefore we use another loop that loops through the characters of that BinaryString For c = 1 To n (which means start with character 1 until character n). And fill the matrix:
Matrix(i + 1, c) = CLng(Mid$(BinaryString, c, 1))
Here Mid$(BinaryString, c, 1) picks the character out of the string and CLng converts it into a Long number so it is numeric and writes it into the correct position of the matrix Matrix(i + 1, c).
Fanally we return that matix as result of our function CreateMatrix = Matrix.
This post is 10 months old. But I saw a new post by the OP which led me here, so I thought I'd share another solution.
This can be solved by formula instead of script.
Suppose in cell A1 of some sheet you place the number for n.
In some other cell (say, A3 or C1), you could use the following formula to generate the list in question:
=FILTER(TEXT(SEQUENCE(10^A1,1,0),REPT("0",A1)),NOT(REGEXMATCH(SEQUENCE(10^A1,1,0)&"","[2-9]")))
Essentially, this formula creates a SEQUENCE of all possible numbers between 0 and 10 to the nth, formatted to contain n digits; then it FILTERs out any elements of that sequence that contain any digits from 2 to 9 (i.e., anything other than elements containing only 1s and 0s).

How to find the number of times a group of a specific value is present in an array?

I have a 1 by 1000 (1 row by 1000 columns) matrix that contain only 0 and 1 as their elements. How can I find how many times 1 is repeated 3 times consecutively.
If there are more than 3 ones then it is necessary to reset the counting. So 4 would be 3+1 and it counts as only one instance of 3 consecutive 1s but 6 would be 3+3 so it counts as two instances of having 3 consecutive 1s.
This approach finds the differences between when A goes from 0 to 1 (rising edge) and from 1 to 0 (falling edge). This gives the lengths of consecutive 1s in each block. Then divide these numbers by 3 and round down to get the number of runs of 3.
Padding A with a 0 at the start and end just ensures we have a rising edge at the start if A starts with a 1, and we have a falling edge at the end if A ends with a 1.
A = round(rand(1,1000));
% padding with a 0 at the start and end will make this simpler
B = [0,A,0];
rising_edges = ~B(1:end-1) & B(2:end);
falling_edges = B(1:end-1) & ~B(2:end);
lengths_of_ones = find(falling_edges) - find(rising_edges);
N = sum(floor(lengths_of_ones / 3));
Or in a much less readable 2 lines:
A = round(rand(1,1000));
B = [0,A,0];
N = sum(floor((find(B(1:end-1) & ~B(2:end)) - find(~B(1:end-1) & B(2:end))) / 3));
You can define your custom functions like below
v = randi([0,1],1,1000);
% get runs in cell array
function C = runs(v)
C{1} = v(1);
for k = 2:length(v)
if v(k) == C{end}(end)
C{end} = [C{end},v(k)];
else
C{end+1} = v(k);
end
end
end
% count times of 3 consecutive 1s
function y = count(x)
if all(x)
y = floor(length(x)/3);
else
y = 0;
end
end
sum(cellfun(#count,runs(v)))
Here is another vectorized way:
% input
n = 3;
a = [1 1 1 1 0 0 1 1 1 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1]
% x x x x x = 5
% output
a0 = [a 0];
b = cumsum( a0 ) % cumsum
c = diff( [0 b( ~( diff(a0) + 1 ) ) ] ) % number of ones within group
countsOf3 = sum( floor( c/n ) ) % groups of 3
You like it messy? Here is a one-liner:
countsOf3 = sum(floor(diff([0 getfield(cumsum([a 0]),{~(diff([a 0])+1)})])/n))

How to sum values in array from different columns + EXCEL VBA

I need to calculate this in excel vba ,using array loop only :
round 0 round 1
9 28
65 84
28 47
84 103
41 60
66 85
115 134
I need to sum values in round 0 in loop so the sum result (408) must be divided by 7 , if not I WANT to sum one value from the round 1 (in this case 84 instead of 65 ) to the rest of values in round 0 so the sum result can divided by 7 . There will be so many round up to 7 . I need VBA code to accomplish this..
Notes :
round 0 and round 1 all in one two-dimensional array
My Question is : is there a way to sum values from different columns in multi-dimensional array ??
there is an image attached .
I appreciate any help or idea .
Thanks in advance
Excel VBA Array Model:
http://im56.gulfup.com/8rDErI.png
Here an example file contains macro "Question1.xlsm"
http://www.gulfup.com/?TKAAYM
Notes : click the link under the big green down arrow to download the file.
UPDATE :
here another macro to the file "Question1.xlsm" :
Sub A1()
Dim arrTemp1() As Integer
Dim sum1 As Integer
arrblkTable1 = Sheets("Sheet1").Range("blkTable1").Value
ReDim Preserve arrTemp1(0 To 1, 1 To 7)
For a = 0 To 1
sum1 = 0
For c = 1 To 7
arrTemp1(a, c) = arrblkTable1(c, 1) + (a * 19)
text6 = text6 & arrTemp1(a, c) & vbCrLf
Worksheets("TEST3").Cells(a + 1, c).Value = arrTemp1(a, c)
sum1 = sum1 + arrTemp1(a, c)
Next c
If XLMod(sum1, 7) = 0 Then
MsgBox "Yes " & sum1
Else
MsgBox "No " & sum1
End If
Next a
MsgBox text6
End Sub
Function XLMod(a, b)
' This replicates the Excel MOD function
XLMod = a - b * Int(a / b)
End Function
UPDATE : here a new update to the previous macro :
Sub A1()
Dim arrTemp1(), arrTemp2(), arrSUMs() As Integer
Dim sum1 As Integer
arrblkTable1 = Sheets("Sheet1").Range("blkTable1").Value
arrblkTable2 = Sheets("Sheet1").Range("blkTable2").Value
'-------------------------------- arrTemp1 ------------------------------
ReDim Preserve arrTemp1(0 To 1, 1 To 7)
For a = 0 To 1
sum1 = 0
For c = 1 To 7
arrTemp1(a, c) = arrblkTable1(c, 1) + (a * 19)
text6 = text6 & arrTemp1(a, c) & vbCrLf
Worksheets("TEST3").Cells(a + 1, c).Value = arrTemp1(a, c)
sum1 = sum1 + arrTemp1(a, c)
Next c
If XLMod(sum1, 7) = 0 Then
MsgBox "Yes " & sum1
Else
MsgBox "No " & sum1
For c = 1 To 7
sum1 = sum1 - arrTemp1(a, c)
arrTemp1(a, c) = arrblkTable1(c, 1) + ((a + 1) * 19)
sum1 = sum1 + arrTemp1(a, c)
If XLMod(sum1, 7) = 0 Then
MsgBox "Yes " & sum1 & " " & arrTemp1(a, c)
End If
Next c
End If
Next a
For x = 0 To UBound(arrTemp1)
For y = 1 To UBound(arrTemp1)
text7 = text7 & arrTemp1(x, y) & vbCrLf
Next y
Next x
MsgBox text7
End Sub
Function XLMod(a, b)
' This replicates the Excel MOD function
XLMod = a - b * Int(a / b)
End Function
I need now to put each sum1 in one array , how I can do that ??
If I understood it correctly you want something similar to this:
Sub p()
v = Range("A2:A8")
v1 = Sheets("Sheet1").Range("B2:B8")
s = Application.WorksheetFunction.Sum(v)
b = False
Count = 0
For i = 1 To 7
temp = v
temp(i, 1) = v1(i, 1)
s = Application.WorksheetFunction.Sum(temp)
b = s Mod 7 = 0
If b = True Then
Count = Count + 1
End If
Next
MsgBox Count
End Sub
It may help tremendously if you can give more detail about what problem you're trying to solve, instead of focusing on how to solve it this way. There is a possibility that there's another way of doing it that hasn't occurred to you that will be much simpler.
This isn't an answer. Yet. But it will take more space than is allowed in a comment to ensure we've got this right.
For your sample data:
round 0 round 1
9 28
65 84
28 47
84 103
41 60
66 85
115 134
You want to:
Sum all the values in Round 0 (9 + 65 + 28 + 84 + 41 + 66 + 115) = 408
Take that sum (408) mod 7 and see if the result is 0
408 / 7 = 58.28, so (408 mod 7) <> 0
If the result isn't 0 (as in this case)
Start substituting numbers from round 1 for numbers in Round 0
Sum (28 + 65 + 28 + 84 + 41 + 66 + 115) = 427
427 / 7 = 61 (427 mod 7) = 0
This is now your valid result set.
Had the first number in Round 1 been 29
Sum (29 + 65 + 28 + 84 + 41 + 66 + 115) = 428
428 / 7 = 61.14 so (428 mod 7) <> 0
Substitute the next number from round 1 for the next number from round 0
Sum (9 + 84 + 28 + 84 + 41 + 66 + 115) = 427
This is now your valid result set.
Is that the logic you're after?
What happens if you get to the end of round 1 and you don't find a total that (mod 7 = 0)?

What algorithm maps number 27 to BBC

To clarify the confusion - I want to write a function that maps a number to the following list of letter combinations.
My question is best illustrated with the following table.
A 1
B 2
C 3
AA 4
AB 5
AC 6
BA 7
BB 8
BC 9
CA 10
CB 11
CC 12
AAA 13
AAB 14
AAC 15
ABA 16
ABB 17
ABC 18
ACA 19
ACB 20
ACC 21
BAA 22
BAB 23
BAC 24
BBA 25
BBB 26
BBC 27
I want to design a function that is able to map a given number, to the left column of this here table. I've tried assigning numerals to the letters first.
A = 0
B = 1
C = 2
This allows me form the following table (Cn - Column number, from right to left).
C3 C2 C1 Number
0 1
1 2
2 3
0 0 4
0 1 5
0 2 6
1 0 7
1 1 8
1 2 9
2 0 10
2 1 11
2 2 12
0 0 0 13
0 0 1 14
0 0 2 15
0 1 0 16
0 1 1 17
0 1 2 18
0 2 0 19
0 2 1 20
0 2 2 21
1 0 0 22
1 0 1 23
1 0 2 24
1 1 0 25
1 1 1 26
1 1 2 27
So this looks like an recursive loop type algorithm, but I can't figure out how to put this down in code. Any suggestions?
As whoever the person was (user: n.m.) who wrote the comment that disappeared, this is just base-3 counting, except all numerals are offset by +1. The digits really stand for A=0, B=1, C=2
Hence BBC = ('B'+1)*3^2 + ('B'+1)*3 + ('C'+1) = 2*9 + 2*3 + 3 = 27
The pseudocode for fromInt(), Antoine has already given you it. Same idea:
char* fromInt(int n) {
result = ""
working_val = (n-1)
while (working_val>0) {
Prepend to result the digit "CAB"[ working_val % 3 ]
working_val /= 3
}
return result
}
Strictly we don't care about catching the special-case 0 which Antoine noted, because your list doesn't have a representation for 0.
#include <stdio.h>
#include <string.h>
int toInt(const char *str, int acc) {
if(*str)
return toInt(++str, acc * 3 + *str - 'A' + 1);
else
return acc;
}
char *fromInt(int n, char *outbuff){
char* p = outbuff;
while(n){
*p++ = 'A' + ((n % 3 == 0)? 3 : n % 3) - 1;
n = (n - 1) / 3;
}
*p = '\0';
return strrev(outbuff);//strrev isn't ANSI C
}
int main(void) {
char buff[] = "BBC";
int x = toInt(buff, 0);
printf("%d\n", x);
printf("%s\n", fromInt(x, buff));
return 0;
}
This is a kind of base-3 system, but the digits are 1 (A), 2 (B) and 3 (C), there is no 0.
The conversion formula from this representation is, as usual,
3^n*a_n + 3^(n-1)*a_{n-1} + ... + 3^0*a_0
The reverse conversion is just like a regular conversion to base 3, the only difference is that a modified remainder function is used:
int modified_remainder(m, n)
{
int answer = m % n;
if (answer == 0) answer = n;
return answer;
}
Now given the number m, the last digit of its representation would be
a_0 = modified_remainder(m, 3)
The one before last is
m_1 = (m - a_0) / 3; // m-a_0 is always divisible by 3
a_1 = modified_remainder(m_1, 3)
The next one is
m_2 = (m_1 - a_1) / 3
a_2 = modified_remainder(m_2, 3)
and so on. You stop when m_k < n.
Try to verify these claims, it's a good exercise.

Resources