Related
When enumerating all partitions of a positive integer with the following 2 restrictions:
the size of each partition is always PartitionSize
all elements of these partitions are less than or equal to MaxVal, and greater than zero.
...I am faced with a task of numbering/indexing these partitions, in such manner that I can store their indices and later retrieve them to quickly regenerate the elements of one partition from an arbitrary index. The indices do not need to be consecutive.
Q: What would be the best way to go about calculating such partition indices?
The function that generates these partitions is listed below:
void GenPartitions(const unsigned int myInt, const unsigned int PartitionSize, unsigned int MaxVal)
{
if ((MaxVal = MaxPartitionVal(myInt, PartitionSize, MaxVal)) == 0)
return;
unsigned int MinVal = 1;
unsigned int idx_Last = PartitionSize - 1;
unsigned int RightSum = MaxVal; //Sum to the right of the Decrement Point (inclusive)
unsigned int idx_Dec = idx_Last; //The point that needs to be decremented
vector<unsigned int> partition(PartitionSize);
partition[idx_Last] = MaxVal; //Initiallize first partition
do {
unsigned int cur = idx_Dec - 1;
unsigned int LeftRemain = myInt - RightSum - (idx_Dec - 1) * MinVal; //Calculate the remainder to the left
while (LeftRemain > partition[idx_Dec]) //While the remainder is too big to satisfy the left to right ascending ordering.
{
LeftRemain -= partition[idx_Dec] - 1; //
partition[cur--] = partition[idx_Dec];
}
partition[cur] = LeftRemain; //Last remainder
for (unsigned int i = 0; i < cur; i++) //Set the elements where the reminder did not reach.
partition[i] = MinVal;
for (auto d : partition) //DISPLAY THE PARTITON HERE ...or do sth else with it.
std::cout << setw(2) << d << ",";
std::cout << endl;
for (idx_Dec = 0; (idx_Dec < idx_Last) && (partition[idx_Dec] + 1 > partition[idx_Dec + 1]); idx_Dec++); //Find the rising edge
unsigned int val_1stUp = partition[idx_Dec]+1;
for (++idx_Dec; (idx_Dec <= idx_Last) && (val_1stUp > partition[idx_Dec] - 1); idx_Dec++); //Find the falling edge occuring AFTER the rising edge.
if (idx_Dec > idx_Last)
break; //Could not find the falling edge. We are done.
partition[idx_Dec]--; //Decrement at the Decrement Point
//std::cout << setw((idx_Dec*3)+1) << "" << "v" << endl; //Show the Decrement Points
RightSum = 0; //This needs optimization. There is no need to start from the Decrement Point every time. This sum can be adjusted on-the-go, as changes are made to the partition.
for (unsigned int i = idx_Dec; i <= idx_Last; i++) //Calculate the sum to the right of the Decrement Point (inclusive). This needs optimization.
RightSum += partition[i];
} while(true);
}
Note, that this functions generates partitions in which all elements in each partition are ordered from smallest to largest (left to right). This feature cannot become broken.
The ordering between partitions themselves (vertical) is lexicographic. I would not be happy to lose it, but I could live without it.
SAMPLE OUTPUT OF: GenPartitions(20, 4, 10):
1, 1, 8,10
1, 2, 7,10
1, 3, 6,10
2, 2, 6,10
1, 4, 5,10
2, 3, 5,10
2, 4, 4,10
3, 3, 4,10
1, 1, 9, 9
1, 2, 8, 9
1, 3, 7, 9
2, 2, 7, 9
1, 4, 6, 9
2, 3, 6, 9
1, 5, 5, 9
2, 4, 5, 9
3, 3, 5, 9
3, 4, 4, 9
1, 3, 8, 8
2, 2, 8, 8
1, 4, 7, 8
2, 3, 7, 8
1, 5, 6, 8
2, 4, 6, 8
3, 3, 6, 8
2, 5, 5, 8
3, 4, 5, 8
4, 4, 4, 8
1, 5, 7, 7
2, 4, 7, 7
3, 3, 7, 7
1, 6, 6, 7
2, 5, 6, 7
3, 4, 6, 7
3, 5, 5, 7
4, 4, 5, 7
2, 6, 6, 6
3, 5, 6, 6
4, 4, 6, 6
4, 5, 5, 6
5, 5, 5, 5
Also, I purposely elected not to implement this as a recursive function, because of low performance and RAM/stack impact that recursive solutions have for very large partitions (despite their simpler implementations).
Below are the helper functions if anyone wants to compile it.
#include <iostream>
#include <iomanip>
#include <vector>
unsigned int MaxPartitionVal(const unsigned int myInt, const unsigned int PartitionSize, unsigned int MaxVal)
{
if ((myInt < 2) || (PartitionSize < 2) || (MaxVal < 1) || (PartitionSize > myInt) || (myInt > (PartitionSize*MaxVal))) //Sanity checks
return 0;
unsigned int last = PartitionSize - 1;
if (MaxVal + last > myInt)
MaxVal = myInt - last; //It is not always possible to start with the MaxValue. Decrease it to sth possible
return MaxVal;
}
This answer is provided in the hope that it is useful, but without any warranty of being optimal :).
Notations
First, a few typedefs (change as needed):
using iType = uint_fast64_t; // Type of the generated indices.
using pType = unsigned; // Type of the parts in a partition.
using pSize = std::vector<pType>::size_type; // Size of a partition.
Notations:
parts(num, size, max) is the set of integer partitions of num, having size parts inferior or equal to max.
p is an element of parts (a std::vector, so 0 indexed).
getIndex(p, num, size, max) computes the index of p.
getPartition(index, num, size, max) computes the partition of the given index.
Basic idea
Since indices don't have to be consecutive, we can rephrase the problem as such:
getIndex(...) multiplexes (or compresses) multiple integers into a single one.
getPartition(...) demultiplexes (or decompresses) the single integer into the original ones.
A common solution to that is:
multiplexing using consecutives additions & multiplications.
demultiplexing using consecutives euclidian divisions & modulos.
Since we know that each part of a partition verifies 1 <= part && part <= max, a first implementation can be:
iType getIndex(const std::vector<pType>& partition, pType max) {
pSize i = partition.size();
iType result = 0;
while (i > 0) {
i--;
const pType iMin = 1;
const pType iMax = max;
pType part = partition[i];
result = result*(iMax+1-iMin) + (part-iMin);
}
return result;
}
std::vector<pType> getPartition(iType index, pSize size, pType max) {
std::vector<pType> result(size,0);
iType currentIndex = index;
for (pSize i = 0; i < size; i++) {
const pType iMin = 1;
const pType iMax = max;
pType divider = iMax + 1 - iMin;
result[i] = iMin + currentIndex % divider;
currentIndex = currentIndex / divider;
}
return result;
}
Live demo
This works, however computed indices are quite large. The trick to get lower indices is to compute finer values of iMax and iMin at each loop iteration, using the fact that we're working on partitions, not on an aribrary vector in [1;max].
Better compression with range constraints
Adding a self-imposed constraint:
partitions are sorted from largest to lowest part: p[i] >= p[i+1]
We can deduce, for p in parts(num, size, max):
p[0] >= 1 + (num-1) / size
p[0] <= num + 1 - size
Constraints 2 & 3 can be applied recursively to all p[i], by noting that p[1..size-1] is in parts(num-p[0], size-1, p[0])
Therefore we can compute better iMin & iMax, and inject them in the previous implementation:
// !! Requires a sorted partition, from greatest to lowest part.
iType getIndex2(const std::vector<pType>& partition, pType max) {
pSize size = partition.size();
iType result = 0;
pType currentNum = 0;
pSize i = partition.size();
while (i > 0) {
i--;
pType part = partition[i];
currentNum = currentNum + part;
pType iMax = currentNum+1-(size-i); // constraint 3
if (i > 0) {
iMax = std::min<pType>(iMax, partition[i-1]); // constraint 1
} else {
iMax = std::min<pType>(iMax, max);
}
pType iMin = 1+(currentNum-1)/(size-i); // constraint 2
result = result*(iMax+1-iMin) + (part-iMin);
}
return result;
}
std::vector<pType> getPartition2(iType index, pType num, pSize size, pType max) {
std::vector<pType> result(size,0);
iType currentIndex = index;
pType iMax = std::min<pType>(max, num + 1 - size); // constraint 3
pType currentNum = num;
for (pSize i = 0; i < size; i++) {
pType iMin = 1+(currentNum-1)/(size-i); // constraint 2
pType diviser = iMax+1-iMin;
result[i] = iMin + currentIndex % diviser;
currentIndex = currentIndex / diviser;
currentNum = currentNum - result[i];
iMax = std::min<pType>(result[i], currentNum + 1 - (size - i -1)); // constraint 1 & 3 for step (i+1)
}
return result;
}
Live demo
TODO
sanity checks: the provided implementations can go into undefined behaviour if the partition is not sorted, or the partition/index is not valid.
evaluate when iType will be overflowed (and check if it's good enough for you). I don't know how fast the indices grows depending on num,size and max.
How can I find the maximum length between two similar elements in an array?
{6, 6, 4, 2, 3, 6, 1, 2, 3, 4, 5, 6, 5, 4}
from this array the maximum length between two 6's
is {1, 2, 3, 4, 5} not {4, 2, 3}
Your problem statement is to find maximum length of the subarray that only has unique elements.
This can obviously done in O(n*n) if you choose a range from i ... j and update max length if the subarray doesn't have duplicates.
max_len = 0
for(int i = 0; i < n; ++i)
for(int j = 0; j <= i; ++j)
max_len = max( len(arr[i ... j] ), max_len) if arr[i ... j] has unique elements
We can optimize the above code by storing the last occurance of each number and finding the distance based on it.
int find_max_length(vector<int> arr) {
map<int, int> last_occ; //store the last occurance of each number
int n = arr.size();
//initialize last occurance as -1
for(int i = 0; i < n; ++i)
last_occ[arr[i] ] = -1;
//store the starting position of the subarray that has unique numbers
int unique_pos = 0, max_length = 1;
for(int i = 0; i < n; ++i) {
if(last_occ[arr[i] ] != -1) // the number can't be a part of the subarray since a copy of it exists. Trackback subarray
unique_pos = last_occ[arr[i] ] + 1;
//all elements from unique_pos to the current index will be unique
max_length = max(max_length, i - unique_pos + 1);
last_occ[arr[i] ] = i;
}
return max_length;
}
You can make the program return the range of the index and print the numbers that are part of the max_length by making a slight modification.
This one runs in O(n)*log(n) since fetching from map is log n
I am struggling to understand the concept of randomly reading numbers from an array of integers using 'rand()'. I have created a random number generator between 1-3 and want to output an index of an array, then for the generator to randomly output the next generated number from the previous index, until it reaches the end of the array. For example:
'rand()'= 3, 'array[2]'
'rand()' = 2, 'array[4]'
'rand()' = 3, 'array[7]'
if that makes sense?? etc, etc.
The code I'm currently using just outputs a sequence of random numbers. I have place a 'seed' so I can look at the same sequence.
int main()
{
int arrayTest[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20};
srand(4);
for(int i = 0; i < 20; i++)
{
arrayTest[i] = (rand() % 3);
cout << arrayTest[i] << endl;
}
}
I am somewhat guessing at what you really want. But it seems to want to make random increments to an index, and use that index to read from the array in a loop.
So this code just doesn't do anything like you want
arrayTest[i] = (rand() % 3);
It writes (not reads) a random value to an array using a sequential (i.e. non-random) index.
Here's what I think you want
int main()
{
int arrayTest[20] = { ... };
srand(4);
int index = -1;
for(int i = 0; i < 20; i++)
{
index += (rand() % 3) + 1; // add random number from 1 to 3 to index
if (index >= 20) // if index too big for array
index -= 20; // wrap around to beginning of array
cout << arrayTest[index] << endl; // read array at random index, and output
}
}
But I'm not completely sure, in particular the way your testArray has the numbers 1 to 20 in order is making me a bit suspicious. Maybe if you explain why you want to do whatever you want to do it would be a bit clearer.
I have known java for a while and I was trying to translate a java program i wrote to c++ but the copy function gives an odd result:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
long gcd2(long a, long b) {
if ( a == 0 )
return b;
return gcd2(b%a,a);
}
long gcd(long nums[]) {
long ans = nums[0];
int len = sizeof(nums);
for (int i = 1; i < len; i++)
ans = gcd2( nums[i] , ans );
return ans;
}
string com(string s) {
s = s+",";
return (","+s);
}
void printa(long array[]) {
for (int i = 0 ; i < sizeof(array); i++)
cout << array[i] << ", ";
cout << "\n";
}
int main()
{
int length;
cin >> length;
long input[length];
for (int i = 0; i < length; i++)
cin >> input[i];
string possible = "";
int ans = 0;
for (int a = 0; a < length; a++) {
for (int b = length; b > a; b--) {
long arr[b-a];
std::copy(input+a,input+b,arr);
printa(arr);
long gcdans = gcd(arr);
if (possible.find( com(gcdans+"") ) == -1 ) {
possible += com(gcdans+"");
ans++;
}
}
}
cout << (ans);
return 0;
}
I give it the input of:
4
9 6 2 4
and it returns:
9, 6, 2, 4, 140725969483488, 4197851, 9, 6,
9, 6, 2, 4197851, 9, 6, 2, 4,
9, 6, 2, 4197851, 9, 6, 2, 4,
9, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
6, 2, 4, 4197851, 9, 6, 2, 4,
6, 2, 4, 4197851, 9, 6, 2, 4,
6, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
2, 4, 6, 4197851, 9, 6, 2, 4,
2, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
4, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
1
the number at the very end is what i want the program to output at the end, all the numbers above are me test printing the array to see its contents. Basically I am trying to copy a range of the array(for example (2,3,4) from (1,2,3,4,5,6)) But it gives weird numbers like 140725969483488 and 4197766 when the only numbers I input are 9 6 2 4
Variable length arrays is a C++ extension, not standard C++. If your compiler will allow them, then OK. However standard C++ would use an std::vector container which is dynamically sized at runtime, meaning you can initialise them with any size or numbers at runtime, and add anything you want at runtime.
Also note when passing an array in C++ to functions which take an array argument always (with the exception of explicitly declared sized reference to an array) gets passed as a pointer, so you can't know the size of the array once passed as an argument. So this:
void printa(long array[])
{
for (int i = 0 ; i < sizeof(array); i++) {}
// At this point of the code the sizeof(array) will return the size of
// a pointer, usually 4 or 8 bytes.
// It's a quirk that this happens, and is a holdover from C.
}
By taking an argument of std::vector you can know the size of the array. You can take the argument by value or by reference or pointer.
void printa(const std::vector<long>& array)
{
for (int i = 0 ; i < array.size(); i++)
{
cout << array[i] << ", ";
cout << "\n";
}
}
This is the better way to do it. If you want to use a C array or raw array the way you did, you will have to pass both the array and the size of the array as separate arguments.
Also, about the variable length array extension feature, I'm not sure whether it is reliable or not because I've never used the extension. Again, standard C++ requires that size of arrays are constant values, (known at compile time). Edit: actually (known at compile-time) is a bad description because:
int main()
{
int num = 6;
int myarray[num]; // In standard C++ this won't compile
//but
const int num = 6;
int myarray[num]; // Will
}
And one last thing, as SolutionMill pointed out, even if the sizeof(array) does give the right size and not the size of a pointer, it is the size given in bytes, not the number of elements, which was not you were wanting in:
for (int i = 0 ; i < sizeof(array); i++)
If the array is of 2 elements of 32 bit int, then the sizeof() operator will return size 8. A common but by no means pretty way to get the number of elements in an array is something like sizeof(array) / sizeof(array[0])
My question is that if you were print out the resulting *(ary + i), which I know is another way to say ary[i] value, would the following output be a hexadecimal/garbage data or would that specific index be assigned a new value based on the result computed from *ary + i? This whole pointer stuff still throwing me off.
int ary[] = [7, 5, 3, 1, 2, 4, 6, 8];
for (int i = 0; i < 8; i++)
{
*(ary + i) = *ary + i;
}
ary decays to a pointer in the expressions you posted. And since it always produces the same address (the first element), *ary will evaluate to 7 at every iteration.
Since you understand that *(ary + i) is equivalent to ary[i], you should now gather that your loop body is akin to this:
ary[i] = 7 + i;
int ary[] = [7, 5, 3, 1, 2, 4, 6, 8]; is wrong assignment method,
one must use { } to assign values to array.
So, correct way to define is:
int ary[] = {7, 5, 3, 1, 2, 4, 6, 8};
Here *(ary + i) is equivalent to ary [i] , and *ary + i is equivalent to ary [0] + i.
Addressing your question, no it won't throw hex or garbage, you have dereferenced a pointer, so it will give the data stored at that location.
Code:
#include <iostream>
int main ()
{
int ary[] = {7, 5, 3, 1, 2, 4, 6, 8};
for (int i = 0; i < 8; i++)
{
*(ary + i) = *ary + i;
}
for (int j=0;j <8;j++)
{
std::cout <<ary [j];
}
}
Output:
7891011121314
Hope you draw the correlation.
if this helps great, if it doesnot, indicate so in comments, willing to edit