Explanation of formula to count # of iterations in a loop - algorithm

https://stackoverflow.com/a/66458617/18069660
total iterations = (end - start + incr)/incr; // for <=
total iterations = (end - start + incr - 1)/incr; // for <
I have tested both of these formulas and different versions of each for different kinds of for loops. I understand how they work, what I do not understand is how they were made.
Why does the total number of iterations = (the end value minus the start value + the increment)/(divided by the increment).
Why and how were these values chosen and used in such a manner to count the number of iterations. What is the connection between them? How was the formula derived?

Let's first look at the loop that uses <=:
for (int i = start; i <= end; i += incr)
Let's look at the value of i at each iteration:
Iteration
value of i
1
start
2
start + incr
3
start + 2*incr
4
start + 3*incr
...
...
n
start + (n-1)*incr
Case A. i becomes equal to end
If end happens to be one of the values in the second column, for instance, end == start + k*incr for some k, then we can see the number of iterations is k+1.
So we have now the following rule:
If end can be written as start + k*incr for some integer k, then the number of iterations is k+1 and so we can write:
end == start + (numIterations - 1)*incr
Which is equivalent to saying:
numIterations = (end - start) / incr + 1
Or also:
numIterations = (end - start + incr) / incr
Case B: i never becomes equal to end
In this case there is no integer k such that end == start + k*incr. We can find the greatest k for which end < start + k*incr. In other words, there is a positive remainder < incr such that end == start + k*incr + remainder.
We repeat the logic in the previous point, but with that non-zero remainder:
end == start + (numIterations - 1)*incr + remainder
Which is equivalent to saying:
numIterations = (end - start - remainder) / incr + 1
Or also:
numIterations = (end - start - remainder + incr) / incr
When / represents integer division, we don't have to subtract the remainder in that numerator. The integer division will exclude the fractional part that you would get with a real division. So we can simplify to:
numIterations = (end - start + incr) / incr
I hope this explains the case for a loop with <= end.
Loop with < end
When the loop variable cannot become equal to end, but at the most to end-1, then let's translate this case to a loop where the condition is <= end - 1. It is equivalent.
Then apply the formula above by replacing end with end-1, and we get the second form of the formula you presented.

Related

How can I count number of iterations/steps to find answers of a method - RUBY

How can I get the number of iterations/steps that this method takes to find an answer?
def binary_search(array, n)
min = 0
max = (array.length) - 1
while min <= max
middle = (min + max) / 2
if array[middle] == n
return middle
elsif array[middle] > n
max = middle - 1
elsif array[middle] < n
min = middle + 1
end
end
"#{n} not found in this array"
end
One option to use instead of a counter is the .with_index keyword. To use this you'll need to use loop instead of while, but it should work the same. Here's a basic example with output.
arr = [1,2,3,4,5,6,7,8]
loop.with_index do |_, index| # The underscore is to ignore the first variable as it's not used
if (arr[index] % 2).zero?
puts "even: #{arr[index]}"
else
puts "odd: #{arr[index]}"
end
break if index.eql?(arr.length - 1)
end
=>
odd: 1
even: 2
odd: 3
even: 4
odd: 5
even: 6
odd: 7
even: 8
Just count the number of iterations.
Set a variable to 0 outside the loop
Add 1 to it inside the loop
When you return the index, return the count with it (return [middle, count]).
I assume the code to count numbers of interations required by binary_search is to be used for testing or optimization. If so, the method binary_search should be modified in such a way that to produce production code it is only necessary to remove (or comment out) lines of code, as opposed to modifying statements. Here is one way that might be done.
def binary_search(array, n)
# remove from production code lines marked -> #******
_bin_srch_iters = 0 #******
begin #******
min = 0
max = (array.length) - 1
loop do
_bin_srch_iters += 1 #******
middle = (min + max) / 2
break middle if array[middle] == n
break nil if min == max
if array[middle] > n
max = middle - 1
else # array[middle] < n
min = middle + 1
end
end
ensure #******
puts "binary_search reqd #{_bin_srch_iters} interations" #******
end #******
end
x = binary_search([1,3,6,7,9,11], 3)
# binary_search reqd 3 interations
#=> 1
binary_search([1,3,6,7,9,11], 5)
# binary_search reqd 3 interations
#=> nil

Maximum bitwise AND of all possible pairs in a given range

Given a range [l, r] find the maximum bitwise AND of all the possible pairs present.
What approach should I take in order to to solve it efficiently?
Here is a javascript implementation:
function maxAndInRange2(start, end) {
if (end - start == 0) return 0;
if (end - start == 1) return end & start;
if (end % 2 == 0) return (end - 1) & (end - 2)
return end & (end - 1)
}
If end is odd, then the answer must be end & (end - 1), because end - 1 will have all the same binary digits except the last one, which will be turned into a 0. So the result of this will be end - 1, clearly no other pair can be higher than this.
If end is even, then (end - 1) is odd. With the same logic, (end - 1) & (end - 2) will give us (end - 2). Can there be a higher pair than this? Only end - 1 could be higher, but end & (end - 1) won´t give us end - 1 in this case, so (end - 2) is the highest result

Ruby armstrong numbers in a range

puts "Enter range(starts at 1), ends at the number that you enter: "
range = gets.chomp.to_i
number = 1
while number <= range
temporary_number = number
sum_angstrom = 0
number += number
while(temporary_number != 0)
digit = temporary_number % 10
temporary_number /= 10
sum_angstrom = sum_angstrom + (digit ** 3)
end
if (sum_angstrom == number)
puts number
end
end
This time, I tried to make a program to show the armstrong numbers in a range that's taken from the user's input. The program just stops after I enter the number and press enter and i can't figure out why.
Keep in mind that i can't use for(each), that's why i'm using while so often.
First of all, change number += number to number += 1; otherwise you will only test the powers of 2.
Second, move the number += 1 line at the bottom of the while block it is in. Otherwise you will always test if sum_armstrong(n) == n+1.
This works:
puts "Enter range(starts at 1), ends at the number that you enter: "
range = gets.chomp.to_i
number = 1
while number <= range
temporary_number = number
sum_angstrom = 0
while(temporary_number != 0)
digit = temporary_number % 10
temporary_number /= 10
sum_angstrom = sum_angstrom + (digit ** 3)
end
if (sum_angstrom == number)
puts number
end
number += 1
end
Armstrong Number in Ruby one liner
n = 153
s = 0
n.to_s.split("").map{|e| s+=(e.to_i*e.to_i*e.to_i)}
puts (n==s ? "Armstrong number" : "Not Armstrong number")
You can iterate in a range to print the value based on your requirement.
Main logic lies in below line.
n.to_s.split("").map{|e| s+=(e.to_i*e.to_i*e.to_i)}
Improving my answer a little bit
n.digits.map{|e| s+=(e**3)}

scanning binary sequences of length n with k 1's and n-k 0's

I want to write a loop that scans all binary sequences of length n with k 1's and n-k 0's.
Actually, in each iteration an action is performed on the sequence and if a criterion is met the loop will break, otherwise it goes to next sequence. (I am not looking for nchoosek or perms since for large values of n it takes so much time to give the output).
What MATLAB code do you suggest?
You could implement something like an iterator/generator pattern:
classdef Iterator < handle
properties (SetAccess = private)
n % sequence length
counter % keeps track of current iteration
end
methods
function obj = Iterator(n)
% constructor
obj.n = n;
obj.counter = 0;
end
function seq = next(obj)
% get next bit sequence
if (obj.counter > 2^(obj.n) - 1)
error('Iterator:StopIteration', 'Stop iteration')
end
seq = dec2bin(obj.counter, obj.n) - '0';
obj.counter = obj.counter + 1;
end
function tf = hasNext(obj)
% check if sequence still not ended
tf = (obj.counter <= 2^(obj.n) - 1);
end
function reset(obj)
% reset the iterator
obj.counter = 0;
end
end
end
Now you can use it as:
k = 2;
iter = Iterator(4);
while iter.hasNext()
seq = iter.next();
if sum(seq)~=k, continue, end
disp(seq)
end
In the example above, this will iterate through all 0/1 sequences of length 4 with exactly k=2 ones:
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0

number which appears more than n/3 times in an array

I have read this problem
Find the most common entry in an array
and the answer from jon skeet is just mind blowing .. :)
Now I am trying to solve this problem find an element which occurs more than n/3 times in an array ..
I am pretty sure that we cannot apply the same method because there can be 2 such elements which will occur more than n/3 times and that gives false alarm of the count ..so is there any way we can tweak around jon skeet's answer to work for this ..?
Or is there any solution that will run in linear time ?
Jan Dvorak's answer is probably best:
Start with two empty candidate slots and two counters set to 0.
for each item:
if it is equal to either candidate, increment the corresponding count
else if there is an empty slot (i.e. a slot with count 0), put it in that slot and set the count to 1
else reduce both counters by 1
At the end, make a second pass over the array to check whether the candidates really do have the required count. This isn't allowed by the question you link to but I don't see how to avoid it for this modified version. If there is a value that occurs more than n/3 times then it will be in a slot, but you don't know which one it is.
If this modified version of the question guaranteed that there were two values with more than n/3 elements (in general, k-1 values with more than n/k) then we wouldn't need the second pass. But when the original question has k=2 and 1 guaranteed majority there's no way to know whether we "should" generalize it as guaranteeing 1 such element or guaranteeing k-1. The stronger the guarantee, the easier the problem.
Using Boyer-Moore Majority Vote Algorithm, we get:
vector<int> majorityElement(vector<int>& nums) {
int cnt1=0, cnt2=0;
int a,b;
for(int n: A){
if (n == a) cnt1++;
else if (n == b) cnt2++;
else if (cnt1 == 0){
cnt1++;
a = n;
}
else if (cnt2 == 0){
cnt2++;
b = n;
}
else{
cnt1--;
cnt2--;
}
}
cnt1=cnt2=0;
for(int n: nums){
if (n==a) cnt1++;
else if (n==b) cnt2++;
}
vector<int> result;
if (cnt1 > nums.size()/3) result.push_back(a);
if (cnt2 > nums.size()/3) result.push_back(b);
return result;
}
Updated, correction from #Vipul Jain
You can use Selection algorithm to find the number in the n/3 place and 2n/3.
n1=Selection(array[],n/3);
n2=Selection(array[],n2/3);
coun1=0;
coun2=0;
for(i=0;i<n;i++)
{
if(array[i]==n1)
count1++;
if(array[i]==n2)
count2++;
}
if(count1>n)
print(n1);
else if(count2>n)
print(n2);
else
print("no found!");
At line number five, the if statement should have one more check:
if(n!=b && (cnt1 == 0 || n == a))
I use the following Python solution to discuss the correctness of the algorithm:
class Solution:
"""
#param: nums: a list of integers
#return: The majority number that occurs more than 1/3
"""
def majorityNumber(self, nums):
if nums is None:
return None
if len(nums) == 0:
return None
num1 = None
num2 = None
count1 = 0
count2 = 0
# Loop 1
for i, val in enumerate(nums):
if count1 == 0:
num1 = val
count1 = 1
elif val == num1:
count1 += 1
elif count2 == 0:
num2 = val
count2 = 1
elif val == num2:
count2 += 1
else:
count1 -= 1
count2 -= 1
count1 = 0
count2 = 0
for val in nums:
if val == num1:
count1 += 1
elif val == num2:
count2 += 1
if count1 > count2:
return num1
return num2
First, we need to prove claim A:
Claim A: Consider a list C which contains a majority number m which occurs more floor(n/3) times. After 3 different numbers are removed from C, we have C'. m is the majority number of C'.
Proof: Use R to denote m's occurrence count in C. We have R > floor(n/3). R > floor(n/3) => R - 1 > floor(n/3) - 1 => R - 1 > floor((n-3)/3). Use R' to denote m's occurrence count in C'. And use n' to denote the length of C'. Since 3 different numbers are removed, we have R' >= R - 1. And n'=n-3 is obvious. We can have R' > floor(n'/3) from R - 1 > floor((n-3)/3). So m is the majority number of C'.
Now let's prove the correctness of the loop 1. Define L as count1 * [num1] + count2 * [num2] + nums[i:]. Use m to denote the majority number.
Invariant
The majority number m is in L.
Initialization
At the start of the first itearation, L is nums[0:]. So the invariant is trivially true.
Maintenance
if count1 == 0 branch: Before the iteration, L is count2 * [num2] + nums[i:]. After the iteration, L is 1 * [nums[i]] + count2 * [num2] + nums[i+1:]. In other words, L is not changed. So the invariant is maintained.
if val == num1 branch: Before the iteration, L is count1 * [nums[i]] + count2 * [num2] + nums[i:]. After the iteration, L is (count1+1) * [num[i]] + count2 * [num2] + nums[i+1:]. In other words, L is not changed. So the invariant is maintained.
f count2 == 0 branch: Similar to condition 1.
elif val == num2 branch: Similar to condition 2.
else branch: nums[i], num1 and num2 are different to each other in this case. After the iteration, L is (count1-1) * [num1] + (count2-1) * [num2] + nums[i+1:]. In other words, three different numbers are moved from count1 * [num1] + count2 * [num2] + nums[i:]. From claim A, we know m is the majority number of L.So the invariant is maintained.
Termination
When the loop terminates, nums[n:] is empty. L is count1 * [num1] + count2 * [num2].
So when the loop terminates, the majority number is either num1 or num2.
If there are n elements in the array , and suppose in the worst case only 1 element is repeated n/3 times , then the probability of choosing one number that is not the one which is repeated n/3 times will be (2n/3)/n that is 1/3 , so if we randomly choose N elements from the array of size ‘n’, then the probability that we end up choosing the n/3 times repeated number will be atleast 1-(2/3)^N . If we eqaute this to say 99.99 percent probability of getting success, we will get N=23 for any value of “n”.
Therefore just choose 23 numbers randomly from the list and count their occurrences , if we get count greater than n/3 , we will return that number and if we didn’t get any solution after checking for 23 numbers randomly , return -1;
The algorithm is essentially O(n) as the value 23 doesn’t depend on n(size of list) , so we have to just traverse array 23 times at worst case of algo.
Accepted Code on interviewbit(C++):
int n=A.size();
int ans,flag=0;
for(int i=0;i<23;i++)
{
int index=rand()%n;
int elem=A[index];
int count=0;
for(int i=0;i<n;i++)
{
if(A[i]==elem)
count++;
}
if(count>n/3)
{
flag=1;
ans=elem;
}
if(flag==1)
break;
}
if(flag==1)
return ans;
else return -1;
}

Resources