I'm trying to find the maximum contiguous subarray with start and end index. The method I've adopted is divide-and-conquer, with O(nlogn) time complexity.
I have tested with several test cases, and the start and end index always work correctly. However, I found that if the array contains an odd-numbered of elements, the maximum sum is sometimes correct, sometimes incorrect(seemingly random). But for even cases, it is always correct. Here is my code:
int maxSubSeq(int A[], int n, int &s, int &e)
{
// s and e stands for start and end index respectively,
// and both are passed by reference
if(n == 1){
return A[0];
}
int sum = 0;
int midIndex = n / 2;
int maxLeftIndex = midIndex - 1;
int maxRightIndex = midIndex;
int leftMaxSubSeq = A[maxLeftIndex];
int rightMaxSubSeq = A[maxRightIndex];
int left = maxSubSeq(A, midIndex, s, e);
int right = maxSubSeq(A + midIndex, n - midIndex, s, e);
for(int i = midIndex - 1; i >= 0; i--){
sum += A[i];
if(sum > leftMaxSubSeq){
leftMaxSubSeq = sum;
s = i;
}
}
sum = 0;
for(int i = midIndex; i < n; i++){
sum += A[i];
if(sum > rightMaxSubSeq){
rightMaxSubSeq = sum;
e = i;
}
}
return max(max(leftMaxSubSeq + rightMaxSubSeq, left),right);
}
Below is two of the test cases I was working with, one has odd-numbered elements, one has even-numbered elements.
Array with 11 elements:
1, 3, -7, 9, 6, 3, -2, 4, -1, -9,
2,
Array with 20 elements:
1, 3, 2, -2, 4, 5, -9, -4, -8, 6,
5, 9, 7, -1, 5, -2, 6, 4, -3, -1,
Edit: The following are the 2 kinds of outputs:
// TEST 1
Test file : T2-Data-1.txt
Array with 11 elements:
1, 3, -7, 9, 6, 3, -2, 4, -1, -9,
2,
maxSubSeq : A[3..7] = 32769 // Index is correct, but sum should be 20
Test file : T2-Data-2.txt
Array with 20 elements:
1, 3, 2, -2, 4, 5, -9, -4, -8, 6,
5, 9, 7, -1, 5, -2, 6, 4, -3, -1,
maxSubSeq : A[9..17] = 39 // correct
// TEST 2
Test file : T2-Data-1.txt
Array with 11 elements:
1, 3, -7, 9, 6, 3, -2, 4, -1, -9,
2,
maxSubSeq : A[3..7] = 20
Test file : T2-Data-2.txt
Array with 20 elements:
1, 3, 2, -2, 4, 5, -9, -4, -8, 6,
5, 9, 7, -1, 5, -2, 6, 4, -3, -1,
maxSubSeq : A[9..17] = 39
Can anyone point out why this is occurring? Thanks in advance!
Assuming that n is the correct size of your array (we see it being passed in as a parameter and later used to initialize midIndexbut we do not see its actual invocation and so must assume you're doing it correctly), the issue lies here:
int midIndex = n / 2;
In the case that your array has an odd number of elements, which we can represented as
n = 2k + 1
we can find that your middle index will always equate to
(2k + 1) / 2 = k + (1/2)
which means that for every integer, k, you'll always have half of an integer number added to k.
C++ doesn't round integers that receive floating-point numbers; it truncates. So while you'd expect k + 0.5 to round to k+1, you actually get k after truncation.
This means that, for example, when your array size is 11, midIndex is defined to be 5. Therefore, you need to adjust your code accordingly.
Related
So the aim is to take two arrays as shown below
int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int k[4] = {1, 2, 3, 4};
and add each element of k to each element of x in a loop as shown
1 2 3 4 5 6 7 8 9 10
+1 +2 +3 +4 +1 +2 +3 +4 +1 +2
This should give us a final array [2, 4, 6, 8, 6, 8, 10, 12, 10, 12].
Any suggestions as to how I could achieve this in C++
Loop through the indexes of the larger array, using the modulus (%) operator to wrap-around the indexes when accessing the smaller array.
int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int k[4] = {1, 2, 3, 4};
int res[10];
for (int i = 0; i < 10; ++i) {
res[i] = x[i] + k[i % 4];
}
Online Demo
With % you can have the wrap-around behavior and with std::size(from C++17 onwards) the size of the array.
#include <algorithm>
#include <iostream>
int main()
{
int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int k[4] = {1, 2, 3, 4};
for(int i = 0; i < std::size(x); ++i)
{
x[i] = x[i] + k[i%std::size(k)];
}
//lets confirm if x has the right elmennts
for(const int& element: x)
{
std::cout<< element<<std::endl;
}
}
Note that here i have not used a separate array to store the resulting array. Instead the elements are added into the original array x. Storing the result in a new array is trivial.
Lets say I have an array A of size n, where 0 <= A[i] <= n.
Lets say I have 2 arrays Forward and Backward, size n, where:
Forward[i] = index j where
A[j] = min(A[i], A[i+1], ..., A[n-1])
and
Backward[i] = index j where
A[j] = min(A[i], A[i-1], ..., A[0])
My question is:
given A, Forward and Backward
given 2 indexes l and r
Can I discover the index k such that A[k] = min(A[l], A[l+1], ..., A[r]) in constant time?
No. Atleast not in O(1) time. A counter example is as follows. 0-based indexing is used here. Let
index = {0, 1, 2, 3, 4, 5, 6, 7, 8}
A = {1, 3, 5, 7, 9, 6, 4, 2, 0}
Forward = {8, 8, 8, 8, 8, 8, 8, 8, 8}
Backward = {0, 0, 0, 0, 0, 0, 0, 0, 8}
Now, if I ask you to get the index of the minimum value in range [3, 7], how will you do it?
Basically they will be of no use to find in the range [a, b]
if forward[a] > b and backward[b] < a.
No you cant. A counter example is:
A = {0, 4, 3, 2, 3, 4, 0}
Forward = {6, 6, 6, 6, 6, 6, 6}
Backward = {0, 0, 0, 0, 0, 0, 0}
l = 1, k = 5
ie Forward and Backward are of no use in that case and you have to search the array which is O(k-l).
Suppose I have a matrix and a vector given by. How can I perform a search algorithm like binary search to return the index?
Example:
const int V_SIZE = 10,H_SIZE = 7;
int a1[V_SIZE][H_SIZE] = {
{1,2,0,0,0,0,0},
{1,3,0,0,0,0,0},
{2,2,4,0,0,0,0},
{2,2,6,0,0,0,0},
{3,2,4,7,0,0,0},
{4,1,3,5,9,0,0},
{4,1,4,6,8,0,0},
{4,2,3,4,7,0,0},
{5,2,3,5,7,8,0},
{6,1,3,4,5,7,10}
}; // sorted
int a2 [H_SIZE] = {4,1,3,5,9,0,0};
Perform a search for the vector a2 in the matrix a1 and the return value is 6
Thank a lot
You could use a 2D std::array in combination with std::lower_bound:
const int V_SIZE = 10,H_SIZE = 7;
std::array<std::array<int, H_SIZE>, V_SIZE> a1 {
{{{1,2,0,0,0,0,0}},
{{1,3,0,0,0,0,0}},
{{2,2,4,0,0,0,0}},
{{2,2,6,0,0,0,0}},
{{3,2,4,7,0,0,0}},
{{4,1,3,5,9,0,0}},
{{4,1,4,6,8,0,0}},
{{4,2,3,4,7,0,0}},
{{5,2,3,5,7,8,0}},
{{6,1,3,4,5,7,10}}
}}; // sorted
std::array<int, H_SIZE> a2 {{4,1,3,5,9,0,0}};
int idx = std::lower_bound(std::begin(a1), std::end(a1), a2) - std::begin(a1);
LIVE DEMO
If the matrix is sorted on the first number, you could use binary search to find an approximate index. You then have to go back until you find the first row starting with the same number as in the vector, as well as forward to find the last row starting with the same number. Then you loop over the vector, searching for a match for the second, third, etc. number in the range of rows you have.
What about something like this using std::array?
template <int HSIZE>
bool operator<(const std::array<int, HSIZE> &lhs, const std::array<int, HSIZE> &rhs)
{
for (int i = 0; i < HSIZE; i++)
if (lhs[i] != rhs[i])
return lhs[i] < rhs[i];
return false;
}
std::array<int, 7> a1[] =
{
{ 1, 2, 0, 0, 0, 0, 0 },
{ 1, 3, 0, 0, 0, 0, 0 },
{ 2, 2, 4, 0, 0, 0, 0 },
{ 2, 2, 6, 0, 0, 0, 0 },
{ 3, 2, 4, 7, 0, 0, 0 },
{ 4, 1, 3, 5, 9, 0, 0 },
{ 4, 1, 4, 6, 8, 0, 0 },
{ 4, 2, 3, 4, 7, 0, 0 },
{ 5, 2, 3, 5, 7, 8, 0 },
{ 6, 1, 3, 4, 5, 7, 10 }
};
void search(void)
{
std::array<int, 7> a2 = { 4, 1, 3, 5, 9, 0, 0 };
std::array<int, 7> *a1_end = a1 + sizeof(a1) / sizeof(std::array<int, 7>);
std::array<int, 7> *it = std::lower_bound(a1, a1_end, a2);
}
Since the question would be a bit long, ill add that here, I also want to add a row in a vector to the Finald vector.
MatrixXf ProdA(7, 7);;
VectorXf Intd(7);
VectorXf Finald(7);
ProdA <<
7, 5, 1, 9, 11, 2, 0,
5, 2, 8, 3, 11, 3, 3,
3, 9, 0, 1, 3, 1, 7,
6, 0, 1, 9, 11, 33, 3,
3, 5, 3, 3, 4, 3, 3,
3, 9, 1, 1, 0, 1, 15,
6, 2, 6, 2, 5, 12, 3,
Intd << 4, 5, 2, 12, 4, 1, 6;
Finald << 0, 0, 0, 0, 0, 0, 0;
for (int i = 0; i < 7; i++){
Finald.row(i) += ProdA.rowwise().sum();
Finald.row(i) += Intd.row(i);
}
So far this is what I have got. Obviously I get an error if I put i in rowwise. So as an example, I want to add the first row of ProdA , and the first number of Intd into the first space in the Finald vector, and then loop through every row of ProdA and Intd, and sum them all into Finald.
Thanks in advance!
I'm not 100% certain that I correctly understand your problem, but the way I understood it, this should work:
VectorXf ones(7);
ones << 1, 1, 1, 1, 1, 1, 1;
Finald = ProdA * ones + Intd;
I'm not sure if your matrix library (which seems to be Eigen) stores vectors as row or column vectors. So you might have to use ones.transpose() instead.
Here is my array:
int grid[gridsize+1] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2, 4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6, 4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8, 4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8 };
Each number represents a colour, I would like to create multiple arrays for each unique number. The created arrays will store the locations of that number from the original array.
e.g
colour1[5]
[0]=0 //because the number 1 is stored in element 0.
[1]=1
[2]=8
[3]=9
The numbers in grid will change every time I run, so things need to be dynamic?
I can write inefficient code that accomplishes this, but it's just repetitive and I can't comprehend a way to turn this into something I can put in a function.
Here is what I have;
int target_number = 1
grid_size = 64;
int counter = -1;
int counter_2 = -1;
int colour_1;
while (counter < grid_size + 1){
counter = counter + 1;
if (grid[counter] == target)
counter_2 = counter_2 + 1;
colour_1[counter_2] = counter;
}
}
I have to do this for each colour, when I try to make a function, it cannot access the main array in main so is useless.
You can just use vector<vector<int>> to represent your counters. No maps or sorting are needed.
EDIT: added additional pass to determine maximum color, so no run-time resize is needed.
Here is the code:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int grid[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, /*...*/};
const size_t gridSize = std::end(grid) - std::begin(grid);
int maxColor = *std::max_element(std::begin(grid), std::end(grid));
std::vector<std::vector<int>> colorPos(maxColor);
for (size_t i = 0; i < gridSize; ++i)
colorPos[grid[i] - 1].push_back(i);
for (size_t i = 0; i < colorPos.size(); ++i) {
std::cout << (i + 1) << ": ";
for (int p : colorPos[i])
std::cout << p << ' ';
std::cout << std::endl;
}
return 0;
}
The output:
1: 0 1 8 9 10 17
2: 2 3 4 5 6 7 14 15 22 30
3: 11 12 13 19 20 28
4: 16 24 32 33 40 48 56
5: 18 25 26 27 34 35 36 44
6: 21 23 29 31 37 38 39
7: 41 42 49 50 57 58 59 60
8: 43 45 46 47 51 52 53 54 55 61 62 63
I think you'd be best off using a counting sort, which is a sorting algorithm that works very well for sorting large groups of simple types with many duplicate values in better than O(n log n) time. Here's some sample code, annotated for clarity:
// set up our grid
int grid_raw[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2, 4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6, 4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8, 4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8};
// build a vector using our raw list of numbers. This calls the range constructor:
// (number 3) http://www.cplusplus.com/reference/vector/vector/vector/
// The trick to using sizeof is that I don't have to change anything if my grid's
// size changes (sizeof grid_raw gives the number of bytes in the whole array, and
// sizeof *grid_raw gives the number of bytes in one element, so dividing yields
// the number of elements.
std::vector<int> grid(grid_raw, grid_raw + sizeof grid_raw / sizeof *grid_raw);
// count the number of each color. std::map is an associative, key --> value
// container that's good for doing this even if you don't know how many colors
// you have, or what the possible values are. Think of the values in grid as being
// colors, not numbers, i.e. ++buckets[RED], ++buckets[GREEN], etc...
// if no bucket exists for a particular color yet, then it starts at zero (i.e,
// the first access of buckets[MAUVE] will be 0, but it remembers each increment)
std::map<int, int> buckets;
for (vector<int>::iterator i = grid.begin(); i != grid.end(); ++i)
++buckets[*i];
// build a new sorted vector from buckets, which now contains a count of the number
// of occurrences of each color. The list will be built in the order of elements
// in buckets, which will default to the numerical order of the colors (but can
// be customized if desired).
vector<int> sorted;
for (map<int, int>::iterator b = buckets.begin(); b != buckets.end(); ++b)
sorted.insert(sorted.end(), b->second, b->first);
// at this point, sorted = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, ...}
Read more about the Counting Sort (includes example python code)
Here's an ideone that demonstrates sorting your grid.
I'm not 100% sure this answers your question... but you included sorting in the title, even though you didn't say anything about it in the body of your question.
Maybe it would be better to use some associative container as for example std::unordered_map or std::multimap.
Here is a demonstrative program
#include <iostream>
#include <map>
int main()
{
int grid[] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2,
4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6,
4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8,
4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8
};
std::multimap<int, int> m;
int i = 0;
for ( int x : grid )
{
m.insert( { x, i++ } );
}
std::multimap<int, int>::size_type n = m.count( 1 );
std::cout << "There are " << n << " elements of color 1:";
auto p = m.equal_range( 1 );
for ( ; p.first != p.second ; ++p.first )
{
std::cout << ' ' << p.first->second;
}
std::cout << std::endl;
return 0;
}
The output
There are 6 elements of color 1: 0 1 8 9 10 17
Or
#include <iostream>
#include <map>
int main()
{
int grid[] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2,
4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6,
4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8,
4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8
};
std::multimap<int, int> m;
int i = 0;
for ( int x : grid )
{
m.insert( { x, i++ } );
}
for ( auto first = m.begin(); first != m.end(); )
{
auto n = m.count( first->first );
std::cout << "There are " << n
<< " elements of color " << first->first << ":";
auto p = m.equal_range( first->first );
for ( ; p.first != p.second ; ++p.first )
{
std::cout << ' ' << p.first->second;
}
std::cout << std::endl;
first = p.first;
}
return 0;
}
the output is
There are 6 elements of color 1: 0 1 8 9 10 17
There are 10 elements of color 2: 2 3 4 5 6 7 14 15 22 30
There are 6 elements of color 3: 11 12 13 19 20 28
There are 7 elements of color 4: 16 24 32 33 40 48 56
There are 8 elements of color 5: 18 25 26 27 34 35 36 44
There are 7 elements of color 6: 21 23 29 31 37 38 39
There are 8 elements of color 7: 41 42 49 50 57 58 59 60
There are 12 elements of color 8: 43 45 46 47 51 52 53 54 55 61 62 63
If you are not forced to use plain arrays, I can propose a map of colors to a vector of positions:
the map is an associative container, that for any color key returns a reference
the referenced used here will be a vector (a kind of dynamic array) containing all the positions.
Your input grid contains color codes:
typedef int colorcode; // For readability, to make diff between counts, offsets, and colorcodes
colorcode grid[] = { 1, 1, /* .....input data as above.... */ ,8 };
const size_t gridsize = sizeof(grid) / sizeof(int);
You would then define the color map:
map<colorcode, vector<int>> colormap;
// ^^^ key ^^^ value maintained for the key
With this approach, your color1[..] would then be replaced by a more dynamic corlormap[1][..]. And it's very easy to fill:
for (int i = 0; i < gridsize; i++)
colormap[grid[i]].push_back(i); // add the new position to the vector returned for the colormap of the color
To verify the result, you may iterate through the map, and for each existing value iterate through the positions:
for (auto x : colormap) { // for each color in the map
cout << "Color" << x.first << " : "; // display the color (key)
for (auto y : x.second) // and iterate through the vector of position
cout << y << " ";
cout << endl;
}
You don't know for sure how many different color codes you have, but you want to store for accodes