Maximum length between two similar elements in an array - c++

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

Related

Find the index of the closest number that is greater than the current number

For each integer in an array of positive integers, find the index of the closest integer that is greater than the current integer. Also, we need to search for the answer only to the left of the current integer.
For example -
Input array - [ 5, 4, 3, 6, 2, 3]
Output array - [ -1, 0, 1, -1, 3, 3]
Assign -1 to those numbers which don't have an answer.
There is a simple O(n^2) method, for each number run a for loop from the previous number to the beginning of the array.
for(int i=0; i<n; ++i)
{
output[i] = -1;
for(int j=i-1; j>=0; --j)
{
if(input[j] > input[i])
{
output[i] = j;
break;
}
}
}
This method is inefficient when 'n' is large. Is there a more efficient way?
I believe one popular O(n) solution is to use a stack, maintaining a descending sequence (hopefully the algorithm is clear enough from the commented code):
function f(A){
let stack = []
let output = []
for (let i=0; i<A.length; i++){
// While there are lower or
// equal elements on top of
// the stack
while (stack.length && A[ stack[stack.length-1] ] <= A[i])
stack.pop();
// The next greater element
// to the left
if (stack.length)
output.push(stack[stack.length-1]);
// There was none
else
output.push(-1);
stack.push(i);
}
return output;
}
var As = [
[5, 4, 3, 6, 2, 3],
[1, 2, 3, 4, 5],
[5, 4, 3, 2, 1],
[0, 3, -1, 5, 4]
];
for (let A of As){
console.log(`${ A }`);
console.log(`${ f(A) }`);
console.log('');
}
The proposed answer is an adaption of : https://www.geeksforgeeks.org/find-the-nearest-smaller-numbers-on-left-side-in-an-array/
The main idea is to use a stack to remember processed value. In the link, they care about the value but it can easily be adapted to output indices.
#include <iostream>
#include <vector>
#include <stack>
std::vector<int> function(std::vector<int> input) {
std::vector<int> output;
output.reserve(input.size());
// Create an empty stack
// first element of the pair is the index. second is the value
std::stack<std::pair<int,int>> S;
// Traverse all array elements
for (int i=0; i<input.size(); i++)
{
// Keep removing top element from S while the top
// element is less than or equal to arr[i]
while (!S.empty() && S.top().second <= input[i])
S.pop();
// If all elements in S were greater than arr[i]
if (S.empty())
output.push_back(-1);
else //Else print the nearest smaller element
output.push_back(S.top().first);
// Push this element
S.push({i, input[i]});
}
return output;
}
int main() {
std::vector<int> input{5, 4, 3, 6, 2, 3};
std::vector<int> output = function(input);
for(int index : output) {
std::cout << index << ' ';
}
return 0;
}
Output:
-1 0 1 -1 3 3
Compiler explorer : https://godbolt.org/z/8W3ecv

Efficient algorithm to compute combinations with repetitions of an array adding up to given sum

So in a personal C++ project I am faced with a problem. I am rephrasing it as follows :
Given an array of n elements (e.g. [1, 3, 5], with n = 3 elements) where the number at the ith position denotes how many possible values the number at ith index can take (e.g here the first element can take 1 value which is 0; the second element can take 3 values from among 0,1,2; the third element can take 5 values from among 0,1,2,3,4).
I need to list all possible such arrays of length n that sum up to less than or equal to a given number k.
Here is an example :
Input 1:
input array = [2,2];
k = 2
Output 1:
[0,0], [0,1], [1,0], [1,1]
Also, for instance :
Input 2:
input array = [2,2];
k = 1
Output 2:
[0,0], [0,1], [1,0]
The issue :
I have coded up a simple recursive and a simple iterative solution, which enumerates all arrays and only keeps those which have sum less than k. The problem with these is that for the case where n is large and k = 1, my code takes very long to run, since it enumerates all the cases and keeps a few.
I cannot see any overlapping sub-problems so I feel DP and memoization isn't applicable. How can I write the required C++ code for this that works?
Here is my code for the iterative version :
// enumerates all arrays which sum up to k
vector<vector<int> > count_all_arrays(vector<int> input_array, int k){
vector<vector<int> > arr;
int n = (int)input_array.size();
// make auxilliary array with elements
for(int i = 0; i < n; i++){
vector<int> temp(input_array[i]);
std::iota(temp.begin(), temp.end(), 0);
arr.push_back(temp);
}
// computes combinations
vector<int> temp(n);
vector<vector<int> > answers;
vector<int> indices(n, 0);
int next;
while(1){
temp.clear();
for (int i = 0; i < n; i++)
temp.push_back(arr[i][indices[i]]);
long long int total = accumulate(temp.begin(), temp.end(), 0);
if(total <= k)
answers.push_back(temp);
next = n - 1;
while (next >= 0 &&
(indices[next] + 1 >= (int)arr[next].size()))
next--;
if (next < 0)
break;
indices[next]++;
for (int i = next + 1; i < n; i++)
indices[i] = 0;
}
return answers;
}
It's a pretty simple recursive task:
#include <bits/stdc++.h>
using namespace std;
int arr[] = {2, 2};
int n = 2;
int k = 2;
void gen(int pos, int sum, string s){
if(pos == n){
cout<<"["<<s<<" ]"<<endl;
return;
}
for(int i = 0; i < arr[pos]; i++){
if(sum + i > k) return;
gen(pos + 1, sum + i, s + " " + to_string(i));
}
}
int main(){
gen(0, 0, "");
return 0;
}
Just generate all possibilities for each slot of the array and for each choice, take the sum to the evaluation of the next slot.
When n is large and k = 1, it's natural that it takes O(n), since you will have:
[0, 0, 0, ..., 0, 0, 1]
[0, 0, 0, ..., 0, 1, 0]
[0, 0, 0, ..., 1, 0, 0]
...
[0, 0, 1, ..., 0, 0, 0]
[0, 1, 0, ..., 0, 0, 0]
[1, 0, 0, ..., 0, 0, 0]
You should use dp to make it fast in everycase. With dp[i][j] mean how many ways you use first j element to create a sum which is less than or equal i.
dp[i][j] = dp[
for (int l = 0; l <= i; l++)
dp[i][j] += dp[l][j] + min(i-l+1, input[j])
The result is dp[k,n]

How to index doubly restricted integer partitions?

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.

Shifting Elements to the Right After a Certain Index

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

Customised sorting of elements in an array [duplicate]

This question already has answers here:
Sorting an array while moving duplicates to the end?
(4 answers)
Closed 9 years ago.
I have heard of sorting techniques like quicksort, bubblesort, mergesort and many others. I have an array like
arr[]={2, 3, 4, 1, 9, 5, 1, 2, 6, 8, 1, 3}
Using bubble sort I can get the sorting done as
arr[]={1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 8, 9}
But I need to sort the given array in this manner
arr[]={1, 2, 3, 4, 5, 6, 8, 9, 1, 1, 2, 3 )
That is, any re-occurances of values need to be moved to end of the array.
My idea is to bubblesort the array first and then using this sorted array, traverse through the array moving any repeated occurrences to end of the array.
Can it be done this way? If yes, what will be the algorithm after getting bubble sorted array.
Or is there a better way to achieve it.
You can conduct bubble sort in two passes.
In the first pass, find the smallest element and put it in the first place. Then find the element that is greater than the last element found but smallest from among the lot and put it in second place.
Do the above till you reach the maximum element.
Once you reach the maximum element, bubble sort on the remaining part of the array normally.
Order of complexity: Exactly as per Bubble sort, since you are just dividing it in two halves.
Full working code in C++:
#include <iostream>
using namespace std;
int main()
{
int arr[] = {2, 3, 4, 1, 9, 5, 1, 2, 6, 8, 1, 3};
int size = 12;
// find max element.
int max = -1;
for ( int I = 0; I < size; I++ ) {
if ( arr[I] > max )
max = arr[I];
}
int begin = 0;
bool maxPlaced = false;
int lastFound = -1;
while ( !maxPlaced ) {
// find the first element from the end,
// that is greater than elements already placed.
int end = size-1;
while ( arr[end] <= lastFound )
end--;
for ( int I = end; I > begin; I-- ) {
// swap if arr[i-1] is higher than arr[i]
// or arr[i-1] is a number that we have already placed.
if ( arr[I] < arr[I-1] || lastFound >= arr[I-1] ) {
int temp = arr[I];
arr[I] = arr[I-1];
arr[I-1] = temp;
}
}
// lastfound is the highest number that we have placed till now.
lastFound = arr[begin];
begin++;
if ( lastFound == max )
maxPlaced = true;
}
//continue bubble sort from begin position.
for ( int I = begin; I < size; I++ ) {
for ( int j = begin; j < size - 1 - (I-begin); j++ ) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for ( int i = 0; i < size; i++ )
cout << arr[i] << " ";
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 1 1 2 3
For input of {4,5,6,1,1,3,3,4,4,4,1,9,9,8,8}
Output:
1 3 4 5 6 8 9 1 1 3 4 4 4 8 9
Keep in mind that bubble-sort is the least efficient sorting algorithm of those 3 you mentioned.
It's O(n2) average case while the others are O(n log n).
Heap-sort
A variation on heap-sort comes to mind as an efficient (O(n log n)) way to do this.
Build a heap of the items.
Have a left and a right iterator into the array, pointing to the left-most and right-most positions respectively.
While the heap is not empty:
Remove the maximum.
If the removed item is the same as the last removed item, insert it at the right iterator and decrease the iterator.
Otherwise insert it at the left iterator and increase the iterator.
Now if the items at the end need to be sorted as well, just reverse their order (they should be in reverse order at the end of the above process).
In-place alternative - selection sort
Selection sort finds the maximum element at each step, so this can easily be modified to skip the applicable elements if they're greater than an already found element.
This can be done in-place (where the above can't), but is again O(n2).
int arr[] = {2, 3, 4, 1, 9, 5, 1, 2, 6, 8, 1, 3};
int arrLength = 12;
for (int i = 0; i < arrLength; i++)
{
int minPos = -1;
for (int j = i; j < arrLength; j++)
// either it's the first element, or it's greater than the last element
// and either it's the first such element we find, or smaller than the best one
if ((i == 0 || arr[j] > arr[i-1]) &&
(minPos == -1 || arr[j] < arr[minPos]))
{
minPos = j;
}
// no more elements to sort
if (minPos == -1)
break;
int temp = arr[i];
arr[i] = arr[minPos];
arr[minPos] = temp;
}
Live demo.
If the repeated elements needs to be sorted as well, this will need to be done additionally (with any sort method).