Infinite while loop bug in algorithm - c++

#include<bits/stdc++.h>
using namespace std;
int main() {
int a[5] = {1, 2, 3, 4, 5};
int k;
cin >> k;
int i, j, ct;
i = 0;
j = 4;
ct = 0;
while (i < j) {
if (a[i] + a[j] > k) {
--j;
}
else if (a[i] + a[j] < k) {
++i;
}
else {
ct++;
}
}
cout << ct;
}
Trying to print the total number of pairs ct in a given sorted array whose sum is equal to k, k is any given input. But the problem is, value of i changes once and value of j remains same. why? hence i < j is always true and loop runs to infinite hence no certain value of ct comes out. Where is the problem in this code?

There are many issues in your code, but the reason for it being stuck is pretty simple. You have three cases
larger
smaller
equal
If you reach the equal case, then you do not change i nor j so it will always go to case equal, forever.

Let's say k=5:
In the while loop (i>j) or (0<4):
First case (1+5>k): true
j = 3
the while loop (0<3):
Second case (1+4 = 5)
ct = 1
the while loop (0<3):
Third case (1+4 = 5)
ct = 2
the while loop (0<3):
Fourth case (1+4 = 5)
ct = 3
the while loop (0<3):
Fifth case (1+4 = 5)
ct = 4
So you end up with an infinite loop that never ends because neither the i or j value is being updated
i.e the "else{} " is being infinitely run because the loop condition still holds.

Related

Heap-buffer overflow when implementing two-pointer approch

I'm solving this brain teaser
Given a 1-indexed array of integers numbers that is already sorted in
non-decreasing order, find two numbers such that they add up to a
specific target number. Let these two numbers be numbers[index1] and
numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Return the indices of the two numbers, index1 and index2, added by one
as an integer array [index1, index2] of length 2.
The tests are generated such that there is exactly one solution. You
may not use the same element twice.
Your solution must use only constant extra space.
Example 1:
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9.
Therefore, index1 = 1, index2 = 2.
We return [1, 2].
and my solution is giving this error:
=================================================================
==31==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000620 at pc 0x000000345e97 bp 0x7ffcd6847990 sp 0x7ffcd6847988
READ of size 4 at 0x602000000620 thread T0
#2 0x7f2c3b9790b2 (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x602000000620 is located 0 bytes to the right of 16-byte region [0x602000000610,0x602000000620)
I did some research and saw that this is usually caused by calling an index that's too far (i.e. outside the range of the data structure you're using) but since I'm using vectors I don't get why I have this error. It happened on the following test case: [5,25,75]
100.
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
// can have an i that points forward and a j that loops through everything until sum
// is greater
// checking recursively
// if sum greater stop checking (as list is increasing)
// can reset i each time??
// add 1 at the end
vector<int> indices;
int i = 0;
int j = 0;
// for loop on top?
for (int i; i < numbers.size(); i++)
int j = 0;
while (numbers[i] + numbers[j] <= target) {
if (numbers[i] + numbers[j] == target && i != j) {
// some if determining if i or j is greater
// to determine the order in which to push back
indices.push_back(i+1);
indices.push_back(j+1);
return indices;
} else {
j++;
}
}
return indices;
}
};
The other tests are passing but this one is failing. I am trying to use a two-pointer approach here.
There are several issues with this code, some simple syntactic mistakes, some algorithmic problems.
First, as others have mentioned, i is uninitialized in your outer for loop. Luckily, that never comes into play because you have no braces around the loop body. Your code is equivilent to
for (int i; i < numbers.size(); i++) {
int j = 0;
}
while (numbers[i] + numbers[j] <= target) {
// ...
}
This is presumably not what you intended, so you need to both initialize i and add {} around the loop body:
for (int i = 0; i < numbers.size(); i++) {
int j = 0;
while (numbers[i] + numbers[j] <= target) {
// ...
}
}
Of course, you also don't need the redundant definitions of i and j outside the loops. Those variables get hidden by the ones defined within the loops, and are never used.
Of course, this still doesn't address your out-of-range error. For that, you need to re-think your algorithm. Lets walk through it to find the issue. I'll just focus on the inner while loop.
Assuming, from your test case that numbers = {5, 25, 75} and target = 100.
First iteration:
i = 0 and j = 0
numbers[i] + numbers[j] -> numbers[0] + numbers[0] -> -> 5 + 5 -> 10. That's less than 100, so the loop is entered
if (10 == 100) is false, so the else branch is selected
j++, so now i = 0 and j = 1
Second iteration:
numbers[i] + numbers[j] -> numbers[0] + numbers[1] -> 5 + 25 -> 30. That's less than 100, so the loop continues
if (30 == 100) is false, so the else branch is selected
j++, so now i = 0 and j = 2
Third iteration:
numbers[i] + numbers[j] -> numbers[0] + numbers[2] -> 5 + 75 -> 80. That's less than 100, so the loop continues
if (80 == 100) is false, so the else branch is selected
j++, so now i = 0 and j = 3
Third iteration:
numbers[i] + numbers[j] -> numbers[0] + numbers[3] -> boom
j is now out of range of the valid indices of numbers, so when you attempt to access numbers[j] the behavior of your program becomes undefined. In this case, it crashed; the best possible outcome.
as the above comments pointed it out,
for (int i; i < numbers.size(); i++)
here 'int i' hides the previous local declaration of 'int i = 0;' (C4456), which is not desirable.
and the problem is that although i is bound to the range [0, n-1], j is not, which can cause access violation when j exceeds the range.
You can use below code which will pass your all test cases.
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
//first we will declare an additional vector which will return desired solution
vector<int> mult;
//by using two pointer approach
for(int i = 0; i<=nums.size(); i++){
for(int j = i+1; j<nums.size();j++){
//checking for condition
if(nums[i]+nums[j]==target){
mult.push_back(i);
mult.push_back(j);
j++;
return mult;
}
}
}
return mult;
}
};

Minimum Cost to reduce the size of array to 1

Given an array of N numbers (not necessarily sorted). We can merge any two numbers into one and the cost of merging the two numbers is equal to the sum of the two values. The task is to find the total minimum cost of merging all the numbers.
Example:
Let the array A = [1,2,3,4]
Then, we can remove 1 and 2, add both of them and keep the sum back in array. Cost of this step would be (1+2) = 3.
Now, A = [3,3,4], Cost = 3
In second step, we can 3 and 3, add both of them and keep the sum back in array. Cost of this step would be (3+3) = 6.
Now, A = [4,6], Cost = 6
In third step, we can remove both elements from the array and keep the sum back in array again. Cost of this step would be (4+6) = 6.
Now, A = [10], Cost = 10
So, total cost turns out to be 19 (10+6+3).
We will have to pick the 2 smallest elements to minimize our total cost. A simple way to do this is using a min heap structure. We will be able to get the minimum element in O(1) and insertion will be O(log n).
The time complexity of this approach is O(n log n).
But I tried another approach, and wasn't able to find the cases where it fails. The basic idea was that the sum of two smallest elements that we will choose at any time will always be greater than the sum of the pair of elements chosen before. So the "temp" array will always be sorted, and we will be able to access the minimum elements in O(1).
As I am sorting the input array and then simply traversing the array, the complexity of my approach is O(n log n).
int minCost(vector<int>& arr) {
sort(arr.begin(), arr.end());
// temp array will contain the sum of all the pairs of minimum elements
vector<int> temp;
// index for arr
int i = 0;
// index for temp
int j = 0;
int cost = 0;
// while we have more than 1 element combined in both the input and temp array
while(arr.size() - i + temp.size() - j > 1) {
int num1, num2;
// selecting num1 (minimum element)
if(i < arr.size() && j < temp.size()) {
if(arr[i] <= temp[j])
num1 = arr[i++];
else
num1 = temp[j++];
}
else if(i < arr.size())
num1 = arr[i++];
else if(j < temp.size())
num1 = temp[j++];
// selecting num2 (second minimum element)
if(i < arr.size() && j < temp.size()) {
if(arr[i] <= temp[j])
num2 = arr[i++];
else
num2 = temp[j++];
}
else if(i < arr.size())
num2 = arr[i++];
else if(j < temp.size())
num2 = temp[j++];
// appending the sum of the minimum elements in the temp array
int sum = num1 + num2;
temp.push_back(sum);
cost += sum;
}
return cost;
}
Is this approach correct? If not, please let me know what I am missing, and the test cases in which this algorithm fails.
SPOJ Link for the same problem
The logic seems very solid to me... all the computed sums will never be decreasing and therefore you only need to add up either oldest two computed sums, next two elements or oldest sum and next element.
I would just simplify the code:
#include <vector>
#include <algorithm>
#include <stdio.h>
int hsum(std::vector<int> arr) {
int ni = arr.size(), nj = 0, i = 0, j = 0, res = 0;
std::sort(arr.begin(), arr.end());
std::vector<int> temp;
auto get = [&]()->int {
if (j == nj || (i < ni && arr[i] < temp[j])) return arr[i++];
return temp[j++];
};
while ((ni-i)+(nj-j)>1) {
int a = get(), b = get();
res += a+b;
temp.push_back(a + b); nj++;
}
return res;
}
int main() {
fprintf(stderr, "%i\n", hsum(std::vector<int>{1,4,2,3}));
return 0;
}
Very nice idea!
Another improvement is noting that the cumulative length of the two arrays being processed (the original one and the temporary one holding the sums) will decrease at every step.
Since the first step will use two input elements, the fact that the temporary array grows one element at each step will still not be enough for a "walking queue" allocated in the array itself to reach the reading pointer.
This means that there is no need of a temporary array and the space for the sums can be found in the array itself...
int hsum(std::vector<int> arr) {
int ni = arr.size(), nj = 0, i = 0, j = 0, res = 0;
std::sort(arr.begin(), arr.end());
auto get = [&]()->int {
if (j == nj || (i < ni && arr[i] < arr[j])) return arr[i++];
return arr[j++];
};
while ((ni-i)+(nj-j)>1) {
int a = get(), b = get();
res += a+b;
arr[nj++] = a + b;
}
return res;
}
About the error on SPOJ... I tried briefly to search for the problem but I didn't succeed. I tried however generating random arrays of random lengths and checking this solution with what finds a "brute-force" one implemented directly from the specs and I'm reasonably confident that the algorithm is correct.
I know at least one programming arena (Topcoder) where sometimes the problems are carefully crafted so that the computation gives correct results if using unsigned but not if using int (or if using unsigned long long but not if using long long) because of integer overflow.
I don't know if SPOJ also does this kind of nonsense(1)... may be that is the reason some hidden test case fails...
EDIT
Checking with SPOJ the algorithm passes if using long long values... this is the entry I used:
#include <stdio.h>
#include <algorithm>
#include <vector>
int main(int argc, const char *argv[]) {
int n;
scanf("%i", &n);
for (int testcase=0; testcase<n; testcase++) {
int sz; scanf("%i", &sz);
std::vector<long long> arr(sz);
for (int i=0; i<sz; i++) scanf("%lli", &arr[i]);
int ni = arr.size(), nj = 0, i = 0, j = 0;
long long res = 0;
std::sort(arr.begin(), arr.end());
auto get = [&]() -> long long {
if (j == nj || (i < ni && arr[i] < arr[j])) return arr[i++];
return arr[j++];
};
while ((ni-i)+(nj-j)>1) {
long long a = get(), b = get();
res += a+b;
arr[nj++] = a + b;
}
printf("%lli\n", res);
}
return 0;
}
PS: This very kind of computation is also what is needed to build an Huffman tree for entropy coding given the symbols frequency table and thus it's not a mere random exercise but it has practical applications.
(1) I'm saying "nonsense" because in Topcoder they never give problems that require 65 bits; thus it's not a genuine care about overflows, but just setting traps for novices.
Another that I think is a bad practice I saw on TC is that some problems are carefully designed so that the correct algorithm if using C++ will barely fit in the timeout limit: just use another language (and get e.g. a 2× slowdown) and you cannot solve the problem.
First of all, think simple!
When using a priority queue, the problem is easy!
In the first test case :
1 6 3 20
// after pushing to Q
1 3 6 20
// and sum two top items and pop and push!
(1 + 3) 6 20 cost = 4
(4 + 6) 20 cost = 10 + 4
(10 + 20) cost = 30 + 14
30 cost = 44
#include<iostream>
#include<queue>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
priority_queue<long long int, vector<long long int>, greater<long long int>> q;
for (int i = 0; i < n; ++i) {
int k;
cin >> k;
q.push(k);
}
long long int sum = 0;
while (q.size() > 1) {
long long int a = q.top();
q.pop();
long long int b = q.top();
q.pop();
q.push(a + b);
sum += a + b;
}
cout << sum << "\n";
}
}
Basically we need to sort the list in desc order and then find its cost like this.
A.sort(reverse=True)
cost = 0
for i in range(len(A)):
cost += A[i] * (i+1)
return cost

What is the running time complexity of this for loop

for (int p = t; p > 0; p >>= 1) {
for (int i = 0; i < n - p; ++i) {
if ((i & p) != 0) {
sort2(a, i, i+p);
}
}
for(int q = t; q > p; q >>= 1) {
for(int i = 0; i < n- q; ++i) {
if ((i & p) != 0) {
sort2(a, i+p, i+q);
}
}
}
}
Here n is some positive integer and t is greater than n/2, but not equal to n.
As per my understanding, the inner for loop runs for (n-p) times but I could not figure out the outer for loop.
I tried finding it as below:
If t=64 and n=100, it takes the binary value of p which is equal to 64 and so p=1000000 base 2.
I understand that every time it reduces by one digit and it executes a total of 7 times in this case. I somehow couldn't figure out general time.
Also, my understanding is that the 3rd for loop i.e
for(int q = t; q > p; q >>= 1)
doesn't execute at all because the condition q>p doesn't satisfy as p=q=t.
Is this correct? I am just starting out with algorithms.
For this: Complexity would be BigO( log(t)(n-t)log(t) )
Excluding the sort2 function complexity inside the for loop.
Explaination:
Outer loop Complexity would be log(p)+1 [Each time it is right shifting the bit by 1 and going for greater than 0], so for t = 64, the loop will go as [64, 32, 16, 8, 4, 2, 1].
Inner loop complexity is going to be greater of ( O(n-p), O((n-t)log(t)) )
Execution
for the second inner loop having nested for loop with the most outer loop:

How to get all possibilities of adding two indexes inside an infinite array in c++

Ok so I am learning c++ and I got stumped with this in the language. Ok so say I have an infinite list ,and I want to figure out all the possible additions with it. EX [1,2,3] = 1 +2, 1+3, 2+1, 2+3, 3+1, 3+2.... and it would be with a list that would be so huge that I wouldn't be able to put every specific index into there.
Here were I ideas I was thinking ,but didn't work
bool sum(){
int b[] = {1, 5, 3, 9};
int n;
int equation;
for(n = 0; n < 4; ++n){
equation = Array[n] + Array [n+1 || n +2 || n+3 || n+4];
if(equation == 10){
return true;
}
}
return false;
}
I swear if feels like I am missing an equation or it's something right under my nose.
In this situation, you want to use a nested for loop.
The logic goes as follows: for every element in b, also check every element in b, and see if the sum adds up to 10.
for (size_t i = 0; i < sizeof(b); ++i){ //.length returns syntax error with //arrays
for (size_t j = 0; j < sizeof(b); ++j){// same as previously stated
if (i == j) continue; //So that you don't add the number to itself
if (b[i] + b[j] == 10){
return true;
}
}
}
return false
Output:
1
we know one is true so we know this solves the problem

Error trying to find all the prime numbers from 2 to n using Sieve of Eratosthenes in C++

I need to find all the prime numbers from 2 to n using the Sieve of Eratosthenes. I looked on Wikipedia(Sieve of Eratosthenes) to find out what the Sieve of Eratosthenes was, and it gave me this pseudocode:
Input: an integer n > 1
Let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n:
if A[i] is true:
for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n :
A[j] := false
Output: all i such that A[i] is true.
So I used this and translated it to C++. It looks fine to me, but I have a couple errors. Firstly, if I input 2 or 3 into n, it says:
terminate called after throwing an instance of 'Range_error'
what(): Range_error: 2
Also, whenever I enter a 100 or anything else (4, 234, 149, 22, anything), it accepts the input for n, and doesn't do anything. Here is my C++ translation:
#include "std_lib_facilities.h"
int main()
{
/* this program will take in an input 'n' as the maximum value. Then it will calculate
all the prime numbers between 2 and n. It follows the Sieve of Eratosthenes with
the algorithms from Wikipedia's pseudocode translated by me into C++*/
int n;
cin >> n;
vector<string>A;
for(int i = 2; i <= n; ++i) // fills the whole table with "true" from 0 to n-2
A.push_back("true");
for(int i = 2; i <= sqrt(n); ++i)
{
i -= 2; // because I built the vector from 0 to n-2, i need to reflect that here.
if(A[i] == "true")
{
for(int j = pow(i, 2); j <= n; j += i)
{
A[j] = "false";
}
}
}
//print the prime numbers
for(int i = 2; i <= n; ++i)
{
if(A[i] == "true")
cout << i << '\n';
}
return 0;
}
The issue is coming from the fact that the indexes are not in line with the value they are representing, i.e., they are moved down by 2. By doing this operation, they no longer have the same mathematical properties.
Basically, the value 3 is at position 1 and the value 4 is at position 2. When you are testing for division, you are using the positions as they were values. So instead of testing if 4%3==0, you are testing that 2%1=0.
In order to make your program works, you have to remove the -2 shifting of the indexes:
int main()
{
int n;
cin >> n;
vector<string>A;
for(int i = 0; i <= n; ++i) // fills the whole table with "true" from 0 to n-2
A.push_back("true");
for(int i = 2; i <= sqrt(n); ++i)
{
if(A[i] == "true")
{
for(int j = pow(i, 2); j <= n; j += i)
{
A[j] = "false";
}
}
}
//print the prime numbers
for(int i = 2; i <= n; ++i)
{
if(A[i] == "true")
cout << i << '\n';
}
return 0;
}
I agree with other comments, you could use a vector of bools. And directly initialize them with the right size and value:
std::vector<bool> A(n, false);
Here you push back n-1 elements
vector<string>A;
for(int i = 2; i <= n; ++i) // fills the whole table with "true" from 0 to n-2
A.push_back("true");
but here you access your vector from A[2] to A[n].
//print the prime numbers
for(int i = 2; i <= n; ++i)
{
if(A[i] == "true")
cout << i << '\n';
}
A has elements at positions A[0] to A[n-2]. You might correct this defect by initializing your vector differently. For example as
vector<string> A(n+1, "true");
This creates a vector A with n+1 strings with default values "true" which can be accessed through A[0] to A[n]. With this your code should run, even if it has more deficits. But I think you learn most if you just try to successfully implement the sieve and then look for (good) alternatives in the internet.
This is painful. Why are you using a string array to store boolean values, and not, let's say, an array of boolean values? Why are you leaving out the first two array elements, forcing you to do some adjustment of all indices? Which you then forget half the time, totally breaking your code? At least you should change this line:
i -= 2; // because I built the vector from 0 to n-2, i need to reflect that here.
to:
i -= 2; // because I left the first two elements out, I that here.
// But only here, doing it everywhere is too annoying.
As a result of that design decision, when you execute this line:
for(int j = pow(i, 2); j <= n; j += i)
i is actually zero which means j will stay zero forever.