Nested Loop Explanation needed - nested-loops

This is a very basic question but haven't been able to find a clear explanation. Why does the below code give 30 as a result for k?
I just would like to understand the mechanism, but for some reason, I cannot get my head around this. I know we first start looking at the inner for loop - we get 10 iterations until number2 reaches 10 (and k becomes 10, number 1 becomes 24. But what's next?
int number1(4), number2, k = 0;
while (number1 < 10)
{
for (number2 = 1; number2 <= 10; number2++)
++k;
number1 = number1 + 2;
}
cout << k << endl;

This line:
number1 = number1 + 2;
is not in the inner loop. Assuming C/C++, if you don't wrap the code inside the loops with curly braces, only the first line after the loop directive gets evaluated as the loop code.
What happens in a single outer loop iteration is as follows:
The inner loop runs 10 times.
k gets incremented 10 times.
You drop to the outer loop. number1 gets incremented by 2.
The outer loop repeats 3 times. Thus k gets incremented 3 x 10 times.

I added brackets to the code below.
It is the same as the code above, but alittle more clear.
int number1(4), number2, k = 0;
while (number1 < 10)
{
for (number2 = 1; number2 <= 10; number2++)
{ //Added the brackets
++k;
}
number1 = number1 + 2;
}
cout << k << endl;
Your indentation is goofy

Related

factorial trailing zeroes BigO problems

when I submit to leetcode, it run case 500/502 but failed, reason: 1808548329. But when I run it on my own mac, it gave the same answer as the accepted one.
my code :
int trailingZeroes(int n) {
int count = 0;
int tmp = 0; //check every number in [1, i]
for (int i = 1; i <= n; i++) {
tmp = i;
while (tmp % 5 == 0) {
count++;
tmp /= 5;
}
}
return count;
}
and the ac answer:
int trailingZeroes2(int n) {
return n == 0 ? 0 : n / 5 + trailingZeroes(n / 5);
}
they run the same result, on my mac:
std::cout << trailingZeroes(1808548329) << std::endl; //452137076
std::cout << trailingZeroes2(1808548329) << std::endl; //452137076
Is the reason that first solution not accepted because of time complexity?
(cus' i am running it on my own mac, but it gives the same answer that the ac gave)
how can i calculate the time complexity of the first solution,
is it O(NlogN) ? I am not sure. can u do me a favor? : -)
edited, remove pics.
Your solution is O(n).
The inner loop repeats at least once every 5 items
The inner loop repeats at least twice every 25 items
...
The inner loop repeats at least k times every 5^k items.
Summing it together gives you that the inner loop runs:
n/5 + n/25 + n/125 + ... + 1 =
n (1/5 + 1/25 + 1/125 + ... + 1/n)
This is sum of geometric series, which is in O(n)
In addition, the outer loop itself has O(n) iterations, with each constant cost, if ignoring the inner loops, so this remains O(n).
The alternative solution, however runs in O(logn), which is significantly more efficient.

Confusion about complexity of two dependent loops?

for(i=1; i < n; i++){
for(j=1; j <= i; j++){
statement1;
}
}
outer loop = O(N)
Inner loop = N(N-1)/2
Total = N*N(N-1)/2 = N^3
it seems n^3 is complexity of these nested loops. but accordings to books, its complexity is n^2 from N(N-1)/2 .
The only interesting thing to count is how often statement1 will be executed.
Therefore, note that something like
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
statement1;
triggers 2 * 3 = 6 executions. So you count how often the inner loop gets executed per outer loop iteration.
However, in your example you did a mistake and multiplied the iterations of the outer loop with the total iterations of the inner loop, not the number of iterations per outer loop iteration.
In the example above that would be like 2 * 6 = 12 instead of only 2 * 3 = 6.
Let's take a closer look at what happens in your specific example. The outer loop triggers n iterations of the inner loop. The inner loop first yields 1 iteration. In the next iteration of the outer loop it will yield 2 iterations, then 3 and so on.
In total you will thus receive 1 + 2 + ... + n = (n^2 - n)/2 iterations of the inner loop. Again, note the 'in total'. So statement1 will in total be executed (n^2 - n)/2 times. The outer loops iterations are already taken into account for the computation of the inner loops total runs, no additional multiplication.
(n^2 - n)/2 is obviously in O(n^2) due to its asymptotic complexity. Intuitively only the biggest factor plays a role, we can drop other stuff by estimating with <=.
(n^2 - n)/2
<= n^2 - n
<= n^2 in O(n^2)
for(i=1; i < n; i++){
for(j=1; j <= i; j++){
statement1;
}
}
In order to simplify the problem, let's assume that n is 5 here.
So line 1 will execute 5 times since it will check and increment i value 5 times.
line 2 will execute (5-1)=4 times because for i=5, it will not execute but line 1 will execute for i=5.
line 3 will execute for 1 time, 2 times 3 times and so on, each time i is incremented.
Take complexity of 3rd line into context and you'll find that it is executing 1+2+3+4=10 times. It's simply the sum of numbers from 1 to 4 or you can say, n(n+1)/2 where n=4.
We can ignore the complexity of line 1 and line 2 since they are constant and in asymptotic notation , the complexity will be O(n^2).
You can think about the 2 nested loops as checking all the cells on the diagonal and below the diagonal on a N x N matrix.
So you'll always do a number of operations close to 1/2 of N^2. So the total number of operations of your code will be N^2 * constant. By the definition of Big-O notation, that means that your code runtime complexity is O(n^2).
Here is a simple code to help you understand my explanation.
#include <vector>
#include <iostream>
using std::vector;
using std::cout;
using std::endl;
// These function count the number of times that your code will execute statement1
int count(int N){
int total = 0;
for(int l = 0; l < N; ++l){
for(int r = 0; r <= l; ++r){
total++;
}
}
return total;
}
// this code will show the cells of the matrix that you are "executing"
int showMatrix(int N){
vector<vector<bool> > mat(N, vector<bool>(N, false) );
for(int l = 0; l < N; ++l){
for(int r = 0; r <= l; ++r){
mat[l][r] = true;
}
}
for(int line = 0; line < N; ++line){
for(int column = 0; column < N; ++column){
cout << (mat[line][column] == true ? "1 " : "0 ");
}
cout << endl;
}
}
int main(){
showMatrix(10);
cout << count(10) << endl;
return 0;
}

Running time of algorithms

In this algorithm
int j=1;
while (j<=n/2) {
int i=1;
while (i <= j) {
cout << j << " "<< i << endl;
i++;
}
cout << endl;
j++;
}
Would the running time of this algorithm be T(n)=(n^2/2)+n+4
for (int i=2; i <=n; i++) {
for (int j=0; j <= n;) {
cout << i << " "<< j << endl;
j=j+(n/4);
}
cout << endl;
}
It would be T(n)=(n-2)^2+2
for the first one. T(n)=sum of number from 1 to n/2 because, the outer loop while be entered n/2 times and for those n/2 times the inner loop will enter 1 time and first turn, 2 times and the 2nd turn, 3 times at the 3rd turn...
T(n) = ((n/2)/2) * ((n/2)+1) = n/4 * (n/2+1) = n/4 * ((n+2)/2)
Maybe you can simplify it more by doing the multiplication.
The 2nd one. T(n) = (n+1) * (n/4) because the outer loop will enter n+1 times and for each of those times the inner loop will enter n/4 times.
T(n) = (n+1) * (n/4)
In the 2nd one, the loop increment is proportional to the loop end point. The number of iterations doesn't increase with n, only the range of values. Starting from j=0, it takes at most 5 increments of j+=(n/4) for j <= n to become false. (Only 4 if n is a multiple of 4). Either way, this is O(1).
So the 2nd version's inner loop does ~5 operations, and there's a cout << endl outside the loop, so each iteration of the outer loop does ~6 print operations. (If they're to a terminal, it will only be line-buffered, so count cost by number of lines printed = number of system calls. If it's going to a file, it'll be block buffered by default, so cost ~= number of operations ~= number of 4k blocks of data printed.)
The 2nd version's outer loop runs from i=2 .. n, so it runs n-1 times, printing 6 lines each time. (or 5 if n%4 == 0). T(loop2) = 6n.
Hassan's analysis looks ok for the first loop.

Does a loop invariant need to be defined both before and after the loop?

I've been really confused so far about loop invariants and their specific properties. Do they need to be true both BEFORE and AFTER the loop? Or just at some point in the loop body itself?
For example:
int sum = 0;
for (int = 0; i < 10; i++) {
sum += i
}
The invariant would be that sum is equal to 0 + 1 + 2 + ... + i. You could say at the end of the second iteration where i = 1, sum = 1. That works, but the invariant needs to be valid in the beginning of the iteration too - and it isn't. Sum is 0 before the loop starts, violating that invariant. Is that correct?
Yes, the loop invariant needs to be defined and true both before and after the loop.
Here is the fully annotated code. We have turned the for loop to a while, for clarity. We define an empty sum (i-1<0) to be 0:
int sum = 0;
// sum == 0
int i= 0;
// Loop invariant: sum == 0 + 1 + ... i-1
while (i < 10) {
// Loop invariant: sum == 0 + 1 + ... i-1
sum += i;
// sum == 0 + 1 + ... i
i++;
// Loop invariant: sum == 0 + 1 + ... i-1
}
// Loop invariant: sum == 0 + 1 + ... i-1, and i == 10 => sum == 0 + 1 + ... 9
As you see, the loop invariant is sum == 0 + 1 + ... i-1. It is (trivially) established before the loop, modified then restored in the loop, and true after the loop. Together with the loop exit condition (i == 10), it ensures the correctness (sum == 45).
A loop invariant does not belong to the whole loop, but to one specific point in the loop. You'd write one loop invariant that is true just before the sum is increased, one that is true just after the sum is increased, one just after i is increased.
As you go through the statements of the loop, you get different invariants. The one at the end of the loop should then lead to the one at the start of the loop being correct when you re-enter the loop.

how to skip a few iterations in a loop in Ruby?

Suppose I have the C code below
for(i = 0; i < 10; i++){
printf("Hello");
if(i == 5){
a[3] = a[2] * 2;
if(a[3] == b)
i = a[3]; //Skip to index = a[3]; depends on runtime value
}
}
How to convert to Ruby? I know we can skip one iteration using next, but I have to skip a few iterations depending on conditional value and I don't know how many iterations to skip before runtime?
Here is the code I am actually working on (as mentioned by Coreyward):
I am looking for "straight line" in the array that the values differs less than 0.1(less than 0.1 will considered as a "straight line"). The range has to be longer than 50 to be considered as a long "line". After I find the line range [a,b], i wanna skip the iterations to upper limit b so it would not start again from a+1, and it will start to find new "straight line" from b+1
for(i=0; i<arr.Length; i++){
if(arr[i] - arr[i + 50] < 0.1){
m = i; //m is the starting point
for(j=i; j<arr.Length; j++){ //this loop makes sure all values differs less than 0.1
if(arr[i] - arr[j] < 0.1){
n = j;
}else{
break;
}
}
if(n - m > 50){ //Found a line with range greater than 50, and store the starting point to line array
line[i] = m
}
i = n //Start new search from n
}
}
Your case isn't easily covered by typical ruby iterators, but ruby also has ordinary while loops which can completely cover c-for. the following is equivalent to your c for loop above.
i = 0;
while i < 10
puts "Hello"
if i == 5
a[3] = a[2] * 2
i = a[3] if a[3] == b
end
# in your code above, the for increment i++ will execute after assigning new i,
# though the comment "Skip to index = a[3]" indicates that may not be your intent
i += 1
end
Another way is using the enumerator class:
iter = (1..10).to_enum
while true
value = iter.next
puts "value is #{value.inspect}"
if value == 5
3.times {value = iter.next}
end
end
gives
value is 1
value is 2
value is 3
value is 4
value is 5
value is 9
value is 10
StopIteration: iteration reached at end
from (irb):15:in `next'
from (irb):15
from C:/Ruby19/bin/irb:12:in `<main>'

Resources