I was trying to write a loop invariant and post condition for this code:
sum = 0;
for (i = 0; i < 10; ++i)
++sum;
sum = 10 is the obvious post condition here. But a friend told me that i = sum is also a loop invariant and sum = 12 is also a post condition. I checked the following:
loop invariant is initially true: that's true for i = sum since both are 0 initially
loop invariant is preserved: assume i < 10 and i = sum then after one iteration it's still true that ++i = ++sum
loop invariant implies post condition: assume i >= 10 and i = sum then sum = 12 is also true
But obviously sum doesn't equal to 12 here. So what's wrong with my reasoning here?
Take a slightly different invariant i == sum && i <= 10. Together with i >= 10 you get then i = sum = 10.
Btw. in your original reasoning you cannot conclude that sum = 12 is true but only that sum >= 10. The latter is correct, just not strong enough to prove the desired result.
// Loop invariant SUM_IS_INDEX: sum == i
// Loop variant: i is increased in every step, and initial value 0 before 10.
sum = 0;
for (i = 0;
// SUM_IS_INDEX before the actual loop
i < 10;
// next loop step, after first step:
// sum == index + 1
++i
// next index = index + 1
// sum == index
// SUM_IS_INDEX after a loop step, continuing
) {
// SUM_IS_INDEX
++sum;
// sum == index + 1
}
// Post: i >= 10 (negation of the for condition), SUM_IS_INDEX
The comment about 12 relates more to i. To have i == 10 one would need to add a predicate on increments of just 1.
Best practise is to rewrite the for in control flow order:
sum = 0;
i = 0;
while (i < 10)
++sum;
++i:
}
This prevents silly mistakes.
Related
Recently, In a competitive coding exam I got this question -
A good number is number whose sum of digits is divisible by 5. example - 5 (5), 14 (1+4), 19(1+9), 23(2+3)
Question is - you are provided a integer n and another integer k you have to find kth good number greater the n.
Constraints - 1<k<10^9
Sample test 1 -
input: n = 6, k = 5
output: 32
Explanation: After 6 good numbers are - 14, 19, 23, 28, 32 (5th is 32)
Sample test 2 -
input: n = 5, k = 1
output: 14
Explanation: 5 is 1st good number but we need greater than 5 so ans is 14
I have tried it with native approach i.e for each number greater then n checking if it is good and loop until I found k good numbers, here is my code -
def solve(n,k):
n+=1
count = 0
while count<k:
if sum(map(int,str(n)))%5==0:
count+=1
n+=1
return n-1
but above code was gave me TLE, how to do it in better time complexity, I have searched on internet for similar question but unable to find, help.
Let's start with a simple question:
I give you a list of five consecutive numbers. How many of those numbers are divisible by 5? (I'm not talking abouts sums of digits yet. Just the numbers, like 18, 19, 20, 21, 22.
No problem there, right? So a slightly different question:
In a list of ten consecutive numbers, how many are divisible by 5?
Still pretty easy, no? Now let's look at your "good" numbers. We'll start by introducing the function digit_sum(n), which is the sum of the digits in n. For now, we don't need to write that function; we just need to know it exists. And here's another simple question:
If n is a number which does not end in the digit 9 and s is digit_sum(n), what is digit_sum(n+1)? (Try a few numbers if that's not immediately clear.) (Bonus question: why does it matter whether the last digit is 9? Or to put it another way, why doesn't it matter which digit other than 9 is at the end? What's special about 9?)
Ok, almost there. Let's put these two ideas together:
Suppose n ends with 0. How many of the ten numbers digit_sum(n), digit_sum(n+1), digit_sum(n+2), … digit_sum(n+9) are divisible by 5? (See question 2).
Does that help you find a quick way to compute the kth good number after n? Hopefully, the answer is yes. Now you just need to generalise a little bit.
maybe your digits algorithm is too time consuming? try this:
def digits(n):
sum = 0
while n:
n, r = divmod(n, 10)
sum += r
return sum
def solve(n,k):
n+=1
count = 0
while count<k:
if digits(n)%5==0:
count+=1
n+=1
return n-1
still it’s a trivial solution, and always you can run it offline and just submit a lookups table.
And here is a link for this sequence: http://oeis.org/A227793
Here's a digit dynamic-program that can answer how many such numbers we can find from 1 to the parameter, k. The function uses O(num_digits) search space. We could use it to search for the kth good number with binary search.
The idea generally is that the number of good numbers that include digit d in the ith position, and have a prefix mod 5 of mod1 so far, is equal to the count of valid digit-suffixes that have the complementary mod, mod2, so that (mod1 + mod2) mod 5 = 0.
JavaScript code comparing with brute force:
function getDigits(k){
const result = [];
while (k){
result.push(k % 10);
k = ~~(k / 10);
}
return result.reverse();
}
function g(i, mod, isK, ds, memo){
const key = String([i, mod, isK]);
if (memo.hasOwnProperty(key))
return memo[key];
let result = 0;
const max = isK ? ds[i] : 9;
// Single digit
if (i == ds.length-1){
for (let j=0; j<=max; j++)
result += (j % 5 == mod);
return memo[key] = result;
}
// Otherwise
for (let j=0; j<=max; j++){
const m = j % 5;
const t = (5 + mod - m) % 5;
const next = g(i+1, t, isK && j == max, ds, memo);
result += next;
}
return memo[key] = result;
}
function f(k){
if (k < 10)
return (k > 4) & 1;
const ds = getDigits(k);
const memo = {};
let result = -1;
for (let i=0; i<=ds[0]; i++){
const m = i % 5;
const t = (5 - m) % 5;
const next = g(1, t, i==ds[0], ds, memo);
result += next;
}
return result;
}
function bruteForce(k){
let result = 0;
//let ns = [];
for (let i=1; i<=k; i++){
const ds = getDigits(i);
const sum = ds.reduce((a, b) => a + b, 0);
if (!(sum % 5)){
//ns.push(i);
result += 1;
}
}
//console.log(ns);
return result;
}
var k = 3000;
for (let i=1; i<k; i++){
const _bruteForce = bruteForce(i);
const _f = f(i);
if (_bruteForce != _f){
console.log(i);
console.log(_bruteForce);
console.log(_f);
break;
}
}
console.log('Done.');
count[0] = 1;
for (int x = 1; x <= n; x++) {
for (auto c : coins) {
if (x-c >= 0) {
count[x] += count[x-c];
}
}
}
count[0] = 1;
for (auto c : coins) {
for (int x = 1; x <= n; x++) {
if (x-c >= 0) {
count[x] += count[x-c];
}
}
}
The first piece of code gives the number of possible permutations of each amount, whereas the second gives the combinations, why is this is the case?
The second code updates number of ways to compose values count[i] with new coin. So after k-th round of outer loop we have count[] list filled with combinations of k coins only, and the rest of coins is not used yet. If we remember combinations themselves for sorted coin list, we will see ordered ones like 1 1 5 10 - 5 never will go before 1. That is why combinations.
The first code at m-th round of outer loop fills m-th cell count[m] using all possible coins. So we can get for m=7 both 1 1 5 and 1 5 1 and 5 1 1. That is why all permutations are counted here
Given a n*m matrix, a cell is called good cell if row number (i) divides column number (j)
Example :
2*3 matrix => cells are {1,1}, {1,2}, {1,3}, {2,1}, {2,2}, {2,3} from which good cells can be defined as {1,1}, {1,2}, {1,3}, {2,2}
So the output is 4
I have figure out the logic for this, row 1 has all cells as good cells, row 2 has m/2 good cells, row 3 has m/3 good cells. (I am using just the integer dividend)
m/1 + m/2 + m/3 + ........ + m/n;
For which my code looks like =>
long count=1;
long answer = 0;
while(count<=n){
answer=answer + m/count;
count++;
}
But this code is getting timed out when I am submitting my solution. Need help to find better approach for this.
PS: Coding challenge is already over.
Try this one,
for(int i = 0 ; i < n; i++)
{
for(int j = 0; j < m; j += i) // j += i will save unwanted loops
{
// rest of your logic
}
}
As the value of i gets higher and higher nested loop will become more efficient
edit
The below code will be more efficient & correct than above. Now nested loop starts with the value of i instead of 0
for(int i = 0 ; i < n; i++)
{
for(int j = i; j < m; j += i) //j = i & j += i will save unwanted loops
{
// rest of your logic
}
}
as noted by n pronouns m this post incorrect since it only considers the case n==m
You may have a look at the Dirichlet divisor problem
One attempt is the formula of Benoit Cloitre:
(below octave implem)
function s = sumit(n)
s = 0;
for i = 1:n
s += floor(n/i);
end
end
n = 1e6
expect = sumit(n)
%A006218
u = floor(sqrt(n));
res = 2*sum(floor(n./(1:u))) - u^2
Where you avoid summing quite some terms.
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.
I'm trying to write an algorithm that will return True/False whether a contiguous sequence in a sorted array that contains only positive integers, can sum up to N.
For example:
Array = { 1, 2, 3, 4 };
6 is good! 1 + 2 + 3 = 6
8 is not good! 1 + 3 + 4 = 8, but it's not contiguous, since we skipped the 2.
This is what I have tried to do:
int[] arr = ...;
int headIndex = 1, tailIndex = 0, sum = arr[0];
while (sum != n)
{
if (sum < n)
{
sum += arr[headIndex++];
}
if (sum > n)
{
sum -= arr[tailIndex++];
}
}
return sum == n;
Obviously the above does not work (In some cases it might get stuck in an infinite loop). Any suggestions?
One thing I haven't mentioned earlier, and is very important- the algorithm's complexity must be low as possible.
This is just a sketch:
Loop from left to right, find the largest k that n1 + ... + nk <= target, set sum = n1 + ... + nk. If the array sum is smaller than target, then return false.
If sum == target, we are done. If not, then any subarray S that sum to target will have S.length < k, and will begin from an element that is larger than the first one. So we kick out the first from the sum: sum -= n1, leftEnd++. Now we can go back to step 1, but no need to compute k from scratch.
Since the left end moves at most N times, and the right end moves at most N times, this algorithm has time complexity O(N), and constant space requirement.
var i = 0;
while(i != arr.Length)
{
var remembre = i;
var tmp = 0;
for(; tmp < N && i < arr.Length; ++i)
tmp += arr[i];
if(N == tmp)
return true;
i = remembre + 1;
}
return false;
I believe this should work.
Simply:
for i = 1 to n - 1:
j = 0
while (j < i):
sm = 0
for k = j to i:
sm = sm + array[k]
if sm == N:
return True
j = j + 1
return False
This works in O(n^3) time.
Here is a solution in code. It's been heavily influenced by #Ziyao Wei's sketch, which simplified my original approach (in particular, there is no need to backtrack and add the small numbers back on, only to take them off as I first thought).
public static bool HasConsecutiveSum(IList<int> list, int requiredSum)
{
int start = 0;
int sum = 0;
for (int end = 0; end < list.Count; end++)
{
sum += list[end];
while (sum > requiredSum)
{
sum -= list[start++];
if (start > end)
{
return false;
}
}
if (sum == requiredSum)
{
return true;
}
}
return false;
}
I think the most optimal algorithm works with a window that moves over the list. The value of the window (WV) is the sum of the elements that fall within the window. If WV is less then N, move the head and add the new value that fits within the window to WV, if the value is bigger then N, move the tail one up and subtract the value that falls of the window from WV. The algorithm stops when WV equals N, or the tail moves beyond the head, or the head is at the end of the list, and WV is still to low.
This would run in linear time: every element in the list is once added and once subtracted at most.
Written down in some code to illustrate the idea (python alike), but not tested
WV = list[0]
L = len(list)
tail = 0
head = 0
while WV != N
if WV < N
head += 1
if head < L
WV += list[head]
else
return false // beyond end of list
elif WV > N
if tail < head
WV -= list[tail]
tail += 1
else
return false // single element bigger then N, and list is sorted
return true