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.
Related
For a sequence of numbers a1, a2,...,an, we say that there is a period if 1≤p<n and if it holds that it is ai=ai+p for all values for which this equality makes sense.
For example, the sequence of numbers 1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3 has period 5, because ai=ai+5 for all values such that both indices i and i+5 are within the allowable range (i.e. for 1 to 7 inclusive). The same sequence also has a period of 10. Next, we say that the sequence of numbers is periodic if it exists at least one number that is the period of that sequence, with the smallest such number being called the base sequence period. If such a number does not exist, the sequence is not periodic. For example, the above the sequence of numbers is periodic with the base period 5, while the sequence of numbers 4, 5, 1, 7, 1, 5 is not periodic.
#include <iostream>
#include <vector>
int period(std::vector<double> vektor) {
int p;
for (int i : vektor) {
for (int j : vektor) {
if (vektor[i] == vektor[j])
p = j;
}
}
return p;
}
int main() {
std::vector<double> vektor{1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3};
std::cout << period(vektor);
return 0;
}
This should be solved using vector.
Could you help me fix this code? This returns 3 as base period of sequence.
For starters it is unclear why you are using a vector with the value type double instead of the type int when all initializers have the type int.
The function period should accept a vector by constant reference.
The variable p is not initialized. As a result the function can return an indeterminate value.
The range based for loop does not return indices in a container as you think
for (int i : vektor) {
It returns stored in the vector objects of the type double.
So the condition in the if statement
if (vektor[i] == vektor[j])
makes no sense.
The function can look the following way as it is shown in the demonstration program below.
#include <iostream>
#include <vector>
size_t period( const std::vector<double> &v )
{
size_t p = 0;
for (size_t i = 1; !p && i < v.size(); i++)
{
size_t j = 0;
while (j < v.size() - i && v[j] == v[j + i]) ++j;
if ( j + i == v.size() ) p = i;
}
return p;
}
int main()
{
std::vector<double> v = { 1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3 };
std::cout << period( v ) << '\n';
}
The program output is
5
I want to divide an array into multiple(or one, maybe zero) arrays like the example below:
array = [0 1 1 2 3 4 0 3 0 3 3 0 5 6 7] -> array1 = [1 1 2 3 4] array2 = [3] array3 = [3 3] array4 = [5 6 7]
my naive approach to do this was first removing zeros from left and right then proceed to use two iterators to find the begin and end of every subarray and by using a vector constructor build the subarrays and pass them to a function. But I know for a fact that my approach is naive and inefficient so I would appreciate some suggestions on how to approach this more efficiently.
Thanks a lot guys!
also this is my code for my approach(a is the mother array):
for(int i = 0; i < a.size(); i++){
if(a[i] != 0)
break;
a.erase(a.begin() + i);
}
for(int i = a.size() - 1; i >= 0; i--){
if(a[i] != 0)
break;
a.erase(a.begin() + i);
}
auto begin = a.begin();
auto end = a.begin() + 1;
for (int i = 0; i < a.size(); i++){
if(a[i] == 0){
vector<int> temp(begin, end);
color(temp);
begin = end + 1;
end = begin + 1;
}
else end++;
}
One of the approach to solve this problem is to create an auxiliary array which contains index of all zero elements (in implementation const_iterator is used rather than index). This problem can be solved without creating such auxiliary array but the advantage of it is, you can find number of sub arrays are going to be created in advance. Approach is as follows,
Iterate input array and put index of zero elements in auxiliary array,
InputArray = [0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7]
Array contains zero elements index = [0, 6, 8, 11]
As you an see above there are four divider (zero index entries) which divides input array into 3 sub arrays and last zero is at index 11 and that is not last element of input array that's why one more sub array will be create so total sub arrays = 4 and for other details please see code,
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using std::cout;
std::vector<std::vector<int>> splitAtZero(const std::vector<int>& arr){
std::vector<std::vector<int>::const_iterator> divider;
divider.reserve(std::max<std::size_t>(arr.size() / 4, 2));
for(std::vector<int>::const_iterator it = arr.cbegin(), endIt = arr.cend(); endIt != it; ++it){
if(0 == *it){
divider.push_back(it);
}
}
if(divider.empty()){
return {arr};
}
if(arr.size() == divider.size()){
return {};
}
std::size_t numOfSubArray = (divider.size() - 1) + (arr.cbegin() != divider.front() ? 1 : 0) +
(arr.cend() != divider.back() ? 1 : 0);
std::vector<std::vector<int>> subArr;
subArr.reserve(numOfSubArray);
std::vector<int>::const_iterator it = arr.cbegin();
for(std::vector<int>::const_iterator divderIt : divider){
if(divderIt - it > 0){
subArr.emplace_back(it, divderIt);
}
it = divderIt + 1;
}
if(arr.cend() != it){
subArr.emplace_back(it, arr.cend());
}
return subArr;
}
int main(){
std::string comma("");
for(std::vector<int>& subArr : splitAtZero({0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7})){
cout<< comma<< "[";
std::copy(subArr.cbegin(), subArr.cbegin() + (subArr.size() - 1), std::ostream_iterator<int>(cout, ", "));
cout<< subArr.back()<< "]";
comma = ", ";
}
cout<< '\n';
}
Output:
[1, 1, 2, 3, 4], [3], [3, 3], [5, 6, 7]
In the following approach that I propose you can retrieve the sub-arrays with a single sequential scan, with no need to exclude zeros at the beginning or at the end:
std::vector<std::vector<int>> arrays;
std::vector<int> currentArray;
for (int i = 0; i < a.size; i++)
{
if (a[i] == 0 || i == a.size - 1)
{
if (currentArray.size() != 0)
{
arrays.push_back(currentArray);
currentArray.clear();
}
}
else
{
currentArray.push_back(a[i]);
}
}
I'm having a trouble for a long time in a problem related to array and loops.
Assume an array like:
int arr[] = {2, 3, 5, 3, 6, 8, 10, 1, 9};
The program should print the expected column as shown (note that the table is an idea for clarification of what I actually want to achieve):
max: expected arr[index] for max
------------------------------------
2 : 3 5 value of: arr[0]
3 : 6, 8, 10 value of: arr[3]
1 : 9 value of: arr[7]
This is what I've tried so far:
#include <iostream>
int main(void) {
int arr[] = {2, 3, 5, 3, 6, 8, 10, 1, 9};
int max = arr[0];
int i = 1, it = i;
for (; i <= max; i++) {
if (i == max) {
std::cout << arr[i] << std::endl;
max = arr[it + 1]; // when loop end has come, increment max to next element value
it = i + 2; // incrementing iterator by 2 next element position (after max)
} else {
std::cout << arr[i] << ' '; // when loop is executing
}
}
return 0;
}
What it actually prints which is unexpected V/S what it should print:
3 5 | 3, 5
3 6 8 | 6, 8, 10
10 1 9 | 1, 9
10 | <nothing>
The program is about to get max value and print the next elements until max value reaches the number of element position.
Where the problem's occurring and how to fix it? Please let me know.
So I rewrote your code, frankly I couldn't follow it, it seems a bit confused with variable names that seem a bit off.
Here's some working code. The two key concepts in the code are the place where each block starts (the variable start) and the size of each block (the variable count). Plus I use the size of the whole array sizeof(arr)/sizeof(arr[0]) to terminate the outer loop. Something that wasn't present in your code. If you are using C++17, you can use std::size(arr) instead of sizeof.
int main(void) {
int arr[] = {2, 3, 5, 3, 6, 8, 10, 1, 9};
size_t start = 0;
while (start < sizeof(arr)/sizeof(arr[0]))
{
int count = arr[start];
for (int i = 0; i < count; ++i)
{
std::cout << arr[start + i + 1] << ' ';
}
std::cout << std::endl;
start += count + 1;
}
}
The output is
3 5
6 8 10
9
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 have an array _data and I'm trying to add a number to the array at a certain position. Every number after the index of position should be shifted one index to the right. I'm having trouble conceptually in doing this.
This is what I have as of now:
void list::add(int num, size_t position)
{
for (int i = 0; i < _size; i++)
{
_data[position + i + 1] = _data[position + i];
}
_data[position] = num;
}
For example, say num = 9 and position = 3 and the given values in the array are {1, 3, 4, 5, 6, 7}. I would want it to be {1, 3, 4, 9, 5, 6, 7}. What ends up happening, though, is that it grabs the number that has already been replaced and puts that back into the array. (ex 1, 3, 4, 9, 5, 5, 5}.
It's depending on type of your variable _data:
If it's an array:
for (std::size_t i = _size - 1; i != position; --i)
{
_data[i] = _data[i - 1];
}
_data[position] = num;
If it's a vector:
_data.insert(_data.begin() + position, num);
Anyway, it's recommended to use a std::vector instead of raw array, and it's NOT recommended to use underscore at the beginning of variable name