Why reserving space with std::vector runs slower? - c++

I created the following function: given a m * n matrix of ones and zeros, it return how many square submatrices have all ones
For example
Input: matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
Output: 15
Explanation:
There are 10 squares of side 1.
There are 4 squares of side 2.
There is 1 square of side 3.
There is the program without reserving space.
int countSquares(vector<vector<int>>& matrix)
{
const size_t rows{ matrix.size() }, cols{ matrix[0].size() }; //Get the number of rows and colums
//Creating a dynamic programing matrix
vector<vector<int>> dp(rows, vector<int>(cols)); //Initializing m * n elements (this should be slower than reserving without initializing)
dp[0][0] = matrix[0][0];
size_t count = dp[0][0]; //counter of the squares
for (size_t i{ 1 }; i < rows; ++i)
count += dp[i][0] = matrix[i][0]; //Count squares in the first row and update the dynamic programming first row
for (size_t i{ 1 }; i < cols; ++i)
count += dp[0][i] = matrix[0][i]; //Count squares in the first colums and update the dynamic programming first column
//Count the rest of squares and update the dynamic programming matrix
for (size_t i{ 1 }; i < rows; ++i)
for (size_t j{ 1 }; j < cols; ++j)
count += dp[i][j] = matrix[i][j] ? min({ dp[i - 1][j], dp[i - 1][j - 1], dp[i][j - 1] }) + 1 : 0;
return count;
}
This is exactly the same program but without initialization the dynamic programming matrix at construction and reserving all space before use
int countSquares(vector<vector<int>>& matrix)
{
const size_t rows{ matrix.size() }, cols{ matrix[0].size() }; //Get the number of rows and colums
//Creating a dynamic programing matrix
vector<vector<int>> dp; //This time without default initialization
dp.reserve(rows);
dp.push_back(vector<int>());
dp.back().reserve(cols);
dp.back().push_back(matrix[0][0]);
size_t count = dp[0][0];
//Count squares in the first row and update the dynamic programming first row
for (size_t i{ 1 }; i < rows; ++i)
{
dp.push_back(vector<int>());
dp.back().reserve(cols);
dp.back().push_back(matrix[i][0]);
count += dp.back().back();
}
//Count squares in the first colums and update the dynamic programming first column
for (size_t i{ 1 }; i < cols; ++i)
{
dp[0].push_back(matrix[0][i]);
count += dp[0].back();
}
//Count the rest of squares and update the dynamic programming matrix
for (size_t i{ 1 }; i < rows; ++i)
for (size_t j{ 1 }; j < cols; ++j)
{
dp[i].push_back(matrix[i][j] ? min({ dp[i - 1][j], dp[i - 1][j - 1], dp[i][j - 1] }) + 1 : 0);
count += dp[i].back();
}
return count;
}
Why the first option runs 50% faster ??
Update 1: I timed my functions with std::chrono::system_clock::now() in visual studio (creating a really long matrix) and also using this page :
https://leetcode.com/problems/count-square-submatrices-with-all-ones/
the first option runs at 90% and the second one at 40%

Related

Magical Subarrays in an Array

Can someone explain how to solve the question below, Much appreciated!
Given an integer array[] of size n, your task is to count the number of magical subarrays in the arr.
Here any subarray array[l…r] is considered to be magical if it satisfies the magical condition.
it should contain an even number(non zero) of odd numbers
More Formally the count of odd numbers in the subarray should be even and should be greater than 0
Constraints
1<=n<=10^5
1<=array[i]<=2*(10)^5
#TestCase 1;
Input:
n=4
array[]={2,1,2,3}
output:2
the magical subarrays are: {2,1,2,3} , {1,2,3}
#Testcase 2
n=6
array[]={1,2,5,2,3,7}
output:7
the magical subarrays are:{1,2,5}, {1,2,5,2}, {2,5,2,3}, {5,2,3}, {2,3,7}, {3,7}, {1,2,5,2,3,7}
The code below gives TLE for the above constraints
long long magicalSubarrays(int n,vector<int> arr)
{
vector<int> O;
for (int i = 0; i < arr.size(); i++) {
if (arr[i] % 2 == 1) {
O.push_back(i);
}
}
int k=O.size();
long long sum = 0;
for (int i = 0; i < O.size(); i++) {
for (int j = i + 1; j < O.size(); j += 2) {
int left = (i-1<0)? O[i]: O[i]-1-O[i-1];
int right= (j+1>=k)? n-1-O[j]: O[j+1]-1-O[j];
sum += (1 + left) * (1 + right);
}
}
return sum;
}
Let O be the array that contains all indices of odd elements.
Every magical subarray must then consist of:
every number from O[i] to O[j] inclusive (where j = i+1+2*k for some k)
an arbitrary number of even items left of i
an arbitrary number of even items right of j
Or, in C++-flavored pseudocode:
int magical_subarrays(const std::vector<int>& arr) {
std::vector<size_t> O;
for (int i = 0; i < arr.length(); i++) {
if (arr[i] % 2 == 1) {
O.push_back(i);
}
}
int sum = 0;
for (int i = 0; i < O.length(); i++) {
for (int j = i + 1; j < O.length(); j += 2) {
int left = /* exercise for the reader. It involves O[i] and O[i-1]. */
int right = /* exercise for the reader. It involves O[j] and O[j+1]. */
sum += (1 + left) * (1 + right);
}
}
return sum;
}

Matrix in diagonal order using array list only

Encountered this problem on hackerrank ,
Please guide on how to print a matrix diagonally in 2D array using ArrayList only.
Here is my code below:
public static List<Integer> downwardDigonal(List<List<Integer>> matrix, int n) {
for (int slice = 0; slice < 2 * n - 1; ++slice) {
int z = (slice < n) ? 0 : slice - n + 1;
for (int j = z; j <= slice - z; ++j) {
matrix.get(j).get(slice-j) ;
}
}
return matrix;
}

C++ Filling partially filled 2D array with Average

I'm trying to experiment with 2D arrays in C++ and I'm working on a project that makes a 4x4 2D array that holds a number of student grades but it is partially filled via a text file. Only 3 out of the 4 columns are filled. I want to filled the last column with an average of the grades in the previous rows of each column.
The problem is I can't figure out exactly how to fill the last column.
This my code for calculating the average.
const int SIZE = 4;
const int ROWS = 4;
const int COLS = 4;
int total = 0;
for (int i = 0; i < ROWS; i++)
{
total = 0;
for (int j = 0; j < COLS - 1; j++)
{
total += studentGrades[i][j];
average = total / (COLS - 1);
studentGrades[0][3] = average;
studentGrades[1][3] = average;
studentGrades[2][3] = average;
studentGrades[3][3] = average;
}
}
It seems like I'm close because I'm getting good results but the last column isn't displaying the right values and I feel like there's a more efficient way to fill the last column instead of manually inserting into each index.
You are assigning the last computed average to all rows every time. This means at the end you will have the average of row 4 in all 4 columns. Also consider changing your variables (studentGrades and total) to a floating point type for more accuracy.
const int SIZE = 4;
const int ROWS = 4;
const int COLS = 4;
for (int i = 0; i < ROWS; i++)
{
int total = 0;
for (int j = 0; j < COLS - 1; j++)
total += studentGrades[i][j];
studentGrades[i][COLS - 1] = total / (COLS - 1);
}
You could also make use of the standard library:
#include <numeric>
// ...
constexpr int Rows = 4, Cols = 4, NGrades = Cols - 1;
for (int i = 0; i < Rows; i++)
studentGrades[i][NGrades] = std::accumulate(studentGrades[i], studentGrades[i] + NGrades, 0) / NGrades;
As in my first solution, consider using floating point types. To enable float arithmetic change the 0 of std::accumulate to 0.0 or 0.0f.
Here is an explanation of std::accumulate.
The logic is wrong. You can only calculate the average and fill the last column after you have totaled the other columns, and you can only fill one row at a time, instead of trying to do all four rows together. This is the correct loop
for (int i = 0; i < ROWS; i++)
{
total = 0;
for (int j = 0; j < COLS - 1; j++)
{
total += studentGrades[i][j];
}
average = total / (COLS - 1);
studentGrades[i][3] = average;
}
It's just a matter of doing things in the right order and at the right time.
Plus you should pay attention to the integer division problem that Yksisarvinen pointed out.

looping through a 2D array (diagonal) c++

So I initialized an array as array[8][8] let's suppose that I'm at point (row, column) and for example, it is row 4 column 4 and I want to loop through every diagonal direction (southeast, southwest, northeast, northwest)
so I wrote 4 different functions to check each direction alone, and here is an example for Northeast
for(int i = 0; i < 8; i++)
for(int j = 0; j < 8; j++)
if(array[i - 1][j+1] == 'x')
{
count = count + 1;
}
is there is a way to loop in all diagonal directions at the same time?
another problem is what about getting out of bounds, like if the point is (7,7), then there will be no value in northeast because it will exceed the array bounds array[6][8], and that is out of array bounds. How can I deal with this problem? or does the compiler return an error when it happens?
You can of course check in each direction, e.g.
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
if (check_north_east(array, i, j))
++count;
if (check_north_west(array, i, j))
++count;
if (check_south_east(array, i, j))
++count;
if (check_south_west(array, i, j))
++count;
}
}
The compiler will happily go beyond the array bounds. So you must make sure, the code won't do it, and check yourself
const int NROWS = 8, NCOLS = 8;
bool check_north_east(char array[][NCOLS], int row, int col)
{
if (row <= 0 || col >= NCOLS - 1)
return false;
return array[row - 1][col + 1] == 'x';
}

Getting awkward results when trying to find largest product in array for project euler 11

I am asked to find the largest product of 4 adjacent numbers horizontally, diagonally, or vertically, in a 20x20 grid for project euler problem 11. The grid can be found here:http://projecteuler.net/problem=11.
I could not find a more efficient approach than to loop over the entire array 4 times. I made a variable max that was initially set equal to 0. I then looped over the array horizontally, and found the products. If a product was greater than max, max was set to that product, etc. I did this for all 4 loops. However, my answer is wrong, and probably too big.
#include <iostream>
using namespace std;
int main () {
int twenty_grid[20][20] =
{
{ 8, 2, 22, /* data elided since the question links to it */ },
…
}
int max = 0;
// Pass 1: This determines the greatest element horizontally
for (int i = 0; i < 20; ++i) {
for (int j = 0; j < 17; ++j) {
// j stops at 17 to avoid a segmentation fault.
int n = twenty_grid[i][j] *
twenty_grid[i][j+1] *
twenty_grid[i][j+2] *
twenty_grid[i][j+2] *
twenty_grid[i][j+3];
if (n > max)
max = n;
}
}
// Now we do the same loop, except we do i + 1, i + 2, etc,
// rather than j +1, j+2. This does it vertically. Pass 2:
for (int i = 0; i < 17; ++i) {
for (int j = 0; j < 20; ++j) {
int n = twenty_grid[i][j] *
twenty_grid[i+1][j] *
twenty_grid[i+2][j] *
twenty_grid[i+3][j];
if (n > max) {
max = n;
}
}
}
// Finally, we increment both i and j to get the diagonals.
for (int i = 0; i < 17; ++i) {
for (int j = 0; j < 20; ++j) {
int n = twenty_grid[i][j] *
twenty_grid[i+1][j+1] *
twenty_grid[i+2][j+2] *
twenty_grid[i+3][j+3];
if (n > max) {
max = n;
}
}
}
// For diagonals, 2 passes are needed to account for both directions.
for (int i = 0; i < 17; i++) {
for (int j = 3; j < 20; j++) {
int n = twenty_grid[i][j] *
twenty_grid[i + 1][i -1] *
twenty_grid[i + 2][i -2] *
twenty_grid[i + 3][i -3];
if (n > max)
max = n;
}
}
cout << max << endl;
return 0;
}
To take a look at why my answer was constantly wrong, I began to print out each individual product as it was calculated. To my surprise, many of them were negative. After checking my loops, it doesn't seem like they access any data out of the array. Could someone lead me in the right direction for fixing this code?
I found several problems.
The first block of code multiplies twenty_grid[i][j+2] twice.
In the third block of code the end condition for the inner loop should be j < 17.
The last block of code uses i as an array index instead of j in three places.
It produces the correct answer after fixing these issues.