count distinct slices in an array - c++

I was trying to solve this problem.
An integer M and a non-empty zero-indexed array A consisting of N
non-negative integers are given. All integers in array A are less than
or equal to M.
A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice
of array A. The slice consists of the elements A[P], A[P + 1], ...,
A[Q]. A distinct slice is a slice consisting of only unique numbers.
That is, no individual number occurs more than once in the slice.
For example, consider integer M = 6 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 5
A[3] = 5
A[4] = 2
There are exactly nine distinct slices: (0, 0), (0, 1), (0, 2), (1,
1), (1,2), (2, 2), (3, 3), (3, 4) and (4, 4).
The goal is to calculate the number of distinct slices.
Thanks in advance.
#include <algorithm>
#include <cstring>
#include <cmath>
#define MAX 100002
// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;
using namespace std;
bool check[MAX];
int solution(int M, vector<int> &A) {
memset(check, false, sizeof(check));
int base = 0;
int fibot = 0;
int sum = 0;
while(fibot < A.size()){
if(check[A[fibot]]){
base = fibot;
}
check[A[fibot]] = true;
sum += fibot - base + 1;
fibot += 1;
}
return min(sum, 1000000000);
}

The solution is not correct because your algorithm is wrong.
First of all, let me show you a counter example. Let A = {2, 1, 2}. The first iteration: base = 0, fibot = 0, sum += 1. That's right. The second one: base = 0, fibot = 1, sum += 2. That's correct, too. The last step: fibot = 2, check[A[fibot]] is true, thus, base = 2. But it should be 1. So your code returns1 + 2 + 1 = 4 while the right answer 1 + 2 + 2 = 5.
The right way to do it could be like this: start with L = 0. For each R from 0 to n - 1, keep moving the L to the right until the subarray contais only distinct values (you can maintain the number of occurrences of each value in an array and use the fact that A[R] is the only element that can occur more than once).
There is one more issue with your code: the sum variable may overflow if int is 32-bit type on the testing platform (for instance, if all elements of A are distinct).
As for the question WHY your algorithm is incorrect, I have no idea why it should be correct in the first place. Can you prove it? The base = fibot assignment looks quite arbitrary to me.

I would like to share the explanation of the algorithm that I have implemented in C++ followed by the actual implementation.
Notice that the minimum amount of distinct slices is N because each element is a distinct one-item slice.
Start the back index from the first element.
Start the front index from the first element.
Advance the front until we find a duplicate in the sequence.
In each iteration, increment the counter with the necessary amount, this is the difference between front and back.
If we reach the maximum counts at any iteration, just return immediately for slight optimisation.
In each iteration of the sequence, record the elements that have occurred.
Once we have found a duplicate, advance the back index one ahead of the duplicate.
While we advance the back index, clear all the occurred elements since we start a new slice beyond those elements.
The runtime complexity of this solution is O(N) since we go through each
element.
The space complexity of this solution is O(M) because we have a hash to store
the occurred elements in the sequences. The maximum element of this hash is M.
int solution(int M, vector<int> &A)
{
int N = A.size();
int distinct_slices = N;
vector<bool> seq_hash(M + 1, false);
for (int back = 0, front = 0; front < N; ++back) {
while (front < N and !seq_hash[A[front]]) { distinct_slices += front - back; if (distinct_slices > 1000000000) return 1000000000; seq_hash[A[front++]] = true; }
while (front < N and back < N and A[back] != A[front]) seq_hash[A[back++]] = false;
seq_hash[A[back]] = false;
}
return distinct_slices;
}

100% python solution that helped me, thanks to https://www.martinkysel.com/codility-countdistinctslices-solution/
def solution(M, A):
the_sum = 0
front = back = 0
seen = [False] * (M+1)
while (front < len(A) and back < len(A)):
while (front < len(A) and seen[A[front]] != True):
the_sum += (front-back+1)
seen[A[front]] = True
front += 1
else:
while front < len(A) and back < len(A) and A[back] != A[front]:
seen[A[back]] = False
back += 1
seen[A[back]] = False
back += 1
return min(the_sum, 1000000000)

Solution with 100% using Ruby
LIMIT = 1_000_000_000
def solution(_m, a)
a.each_with_index.inject([0, {}]) do |(result, slice), (back, i)|
return LIMIT if result >= LIMIT
slice[back] = true
a[(i + slice.size)..-1].each do |front|
break if slice[front]
slice[front] = true
end
slice.delete back
[result + slice.size, slice]
end.first + a.size
end

Using Caterpillar algorithm and the formula that S(n+1) = S(n) + n + 1 where S(n) is count of slices for n-element array java solution could be:
public int solution(int top, int[] numbers) {
int len = numbers.length;
long count = 0;
if (len == 1) return 1;
int front = 0;
int[] counter = new int[top + 1];
for (int i = 0; i < len; i++) {
while(front < len && counter[numbers[front]] == 0 ) {
count += front - i + 1;
counter[numbers[front++]] = 1;
}
while(front < len && numbers[i] != numbers[front] && i < front) {
counter[numbers[i++]] = 0;
}
counter[numbers[i]] = 0;
if (count > 1_000_000_000) {
return 1_000_000_000;
}
}
return count;
}

Related

Minimize the maximum difference between the heights

Given heights of n towers and a value k. We need to either increase or decrease height of every tower by k (only once) where k > 0. The task is to minimize the difference between the heights of the longest and the shortest tower after modifications, and output this difference.
I get the intuition behind the solution but I can not comment on the correctness of the solution below.
// C++ program to find the minimum possible
// difference between maximum and minimum
// elements when we have to add/subtract
// every number by k
#include <bits/stdc++.h>
using namespace std;
// Modifies the array by subtracting/adding
// k to every element such that the difference
// between maximum and minimum is minimized
int getMinDiff(int arr[], int n, int k)
{
if (n == 1)
return 0;
// Sort all elements
sort(arr, arr+n);
// Initialize result
int ans = arr[n-1] - arr[0];
// Handle corner elements
int small = arr[0] + k;
int big = arr[n-1] - k;
if (small > big)
swap(small, big);
// Traverse middle elements
for (int i = 1; i < n-1; i ++)
{
int subtract = arr[i] - k;
int add = arr[i] + k;
// If both subtraction and addition
// do not change diff
if (subtract >= small || add <= big)
continue;
// Either subtraction causes a smaller
// number or addition causes a greater
// number. Update small or big using
// greedy approach (If big - subtract
// causes smaller diff, update small
// Else update big)
if (big - subtract <= add - small)
small = subtract;
else
big = add;
}
return min(ans, big - small);
}
// Driver function to test the above function
int main()
{
int arr[] = {4, 6};
int n = sizeof(arr)/sizeof(arr[0]);
int k = 10;
cout << "\nMaximum difference is "
<< getMinDiff(arr, n, k);
return 0;
}
Can anyone help me provide the correct solution to this problem?
The codes above work, however I don't find much explanation so I'll try to add some in order to help develop intuition.
For any given tower, you have two choices, you can either increase its height or decrease it.
Now if you decide to increase its height from say Hi to Hi + K, then you can also increase the height of all shorter towers as that won't affect the maximum. Similarly, if you decide to decrease the height of a tower from Hi to Hi − K, then you can also decrease the heights of all taller towers.
We will make use of this, we have n buildings, and we'll try to make each of the building the highest and see making which building the highest gives us the least range of heights(which is our answer). Let me explain:
So what we want to do is - 1) We first sort the array(you will soon see why).
2) Then for every building from i = 0 to n-2[1] , we try to make it the highest (by adding K to the building, adding K to the buildings on its left and subtracting K from the buildings on its right).
So say we're at building Hi, we've added K to it and the buildings before it and subtracted K from the buildings after it. So the minimum height of the buildings will now be min(H0 + K, Hi+1 - K), i.e. min(1st building + K, next building on right - K).
(Note: This is because we sorted the array. Convince yourself by taking a few examples.)
Likewise, the maximum height of the buildings will be max(Hi + K, Hn-1 - K), i.e. max(current building + K, last building on right - K).
3) max - min gives you the range.
[1]Note that when i = n-1. In this case, there is no building after the current building, so we're adding K to every building, so the range will merely be
height[n-1] - height[0] since K is added to everything, so it cancels out.
Here's a Java implementation based on the idea above:
class Solution {
int getMinDiff(int[] arr, int n, int k) {
Arrays.sort(arr);
int ans = arr[n-1] - arr[0];
int smallest = arr[0] + k, largest = arr[n-1]-k;
for(int i = 0; i < n-1; i++){
int min = Math.min(smallest, arr[i+1]-k);
int max = Math.max(largest, arr[i]+k);
if (min < 0) continue;
ans = Math.min(ans, max-min);
}
return ans;
}
}
int getMinDiff(int a[], int n, int k) {
sort(a,a+n);
int i,mx,mn,ans;
ans = a[n-1]-a[0]; // this can be one possible solution
for(i=0;i<n;i++)
{
if(a[i]>=k) // since height of tower can't be -ve so taking only +ve heights
{
mn = min(a[0]+k, a[i]-k);
mx = max(a[n-1]-k, a[i-1]+k);
ans = min(ans, mx-mn);
}
}
return ans;
}
This is C++ code, it passed all the test cases.
This python code might be of some help to you. Code is self explanatory.
def getMinDiff(arr, n, k):
arr = sorted(arr)
ans = arr[-1]-arr[0] #this case occurs when either we subtract k or add k to all elements of the array
for i in range(n):
mn=min(arr[0]+k, arr[i]-k) #after sorting, arr[0] is minimum. so adding k pushes it towards maximum. We subtract k from arr[i] to get any other worse (smaller) minimum. worse means increasing the diff b/w mn and mx
mx=max(arr[n-1]-k, arr[i]+k) # after sorting, arr[n-1] is maximum. so subtracting k pushes it towards minimum. We add k to arr[i] to get any other worse (bigger) maximum. worse means increasing the diff b/w mn and mx
ans = min(ans, mx-mn)
return ans
Here's a solution:-
But before jumping on to the solution, here's some info that is required to understand it. In the best case scenario, the minimum difference would be zero. This could happen only in two cases - (1) the array contain duplicates or (2) for an element, lets say 'x', there exists another element in the array which has the value 'x + 2*k'.
The idea is pretty simple.
First we would sort the array.
Next, we will try to find either the optimum value (for which the answer would come out to be zero) or at least the closest number to the optimum value using Binary Search
Here's a Javascript implementation of the algorithm:-
function minDiffTower(arr, k) {
arr = arr.sort((a,b) => a-b);
let minDiff = Infinity;
let prev = null;
for (let i=0; i<arr.length; i++) {
let el = arr[i];
// Handling case when the array have duplicates
if (el == prev) {
minDiff = 0;
break;
}
prev = el;
let targetNum = el + 2*k; // Lets say we have an element 10. The difference would be zero when there exists an element with value 10+2*k (this is the 'optimum value' as discussed in the explaination
let closestMatchDiff = Infinity; // It's not necessary that there would exist 'targetNum' in the array, so we try to find the closest to this number using Binary Search
let lb = i+1;
let ub = arr.length-1;
while (lb<=ub) {
let mid = lb + ((ub-lb)>>1);
let currMidDiff = arr[mid] > targetNum ? arr[mid] - targetNum : targetNum - arr[mid];
closestMatchDiff = Math.min(closestMatchDiff, currMidDiff);
if (arr[mid] == targetNum) break; // in this case the answer would be simply zero, no need to proceed further
else if (arr[mid] < targetNum) lb = mid+1;
else ub = mid-1;
}
minDiff = Math.min(minDiff, closestMatchDiff);
}
return minDiff;
}
Here is the C++ code, I have continued from where you left. The code is self-explanatory.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int minDiff(int arr[], int n, int k)
{
// If the array has only one element.
if (n == 1)
{
return 0;
}
//sort all elements
sort(arr, arr + n);
//initialise result
int ans = arr[n - 1] - arr[0];
//Handle corner elements
int small = arr[0] + k;
int big = arr[n - 1] - k;
if (small > big)
{
// Swap the elements to keep the array sorted.
int temp = small;
small = big;
big = temp;
}
//traverse middle elements
for (int i = 0; i < n - 1; i++)
{
int subtract = arr[i] - k;
int add = arr[i] + k;
// If both subtraction and addition do not change the diff.
// Subtraction does not give new minimum.
// Addition does not give new maximum.
if (subtract >= small or add <= big)
{
continue;
}
// Either subtraction causes a smaller number or addition causes a greater number.
//Update small or big using greedy approach.
// if big-subtract causes smaller diff, update small Else update big
if (big - subtract <= add - small)
{
small = subtract;
}
else
{
big = add;
}
}
return min(ans, big - small);
}
int main(void)
{
int arr[] = {1, 5, 15, 10};
int n = sizeof(arr) / sizeof(arr[0]);
int k = 3;
cout << "\nMaximum difference is: " << minDiff(arr, n, k) << endl;
return 0;
}
class Solution {
public:
int getMinDiff(int arr[], int n, int k) {
sort(arr, arr+n);
int diff = arr[n-1]-arr[0];
int mine, maxe;
for(int i = 0; i < n; i++)
arr[i]+=k;
mine = arr[0];
maxe = arr[n-1]-2*k;
for(int i = n-1; i > 0; i--){
if(arr[i]-2*k < 0)
break;
mine = min(mine, arr[i]-2*k);
maxe = max(arr[i-1], arr[n-1]-2*k);
diff = min(diff, maxe-mine);
}
return diff;
}
};
class Solution:
def getMinDiff(self, arr, n, k):
# code here
arr.sort()
res = arr[-1]-arr[0]
for i in range(1, n):
if arr[i]>=k:
# at a time we can increase or decrease one number only.
# Hence assuming we decrease ith elem, we will increase i-1 th elem.
# using this we basically find which is new_min and new_max possible
# and if the difference is smaller than res, we return the same.
new_min = min(arr[0]+k, arr[i]-k)
new_max = max(arr[-1]-k, arr[i-1]+k)
res = min(res, new_max-new_min)
return res

How to find the nth smallest subarray sum bigger than x in a progression where the first two numbers are given?

I have a progression "a", where the first two numbers are given (a1 and a2) and every next number is the smallest sum of subarray which is bigger than the previous number.
For example if i have a1 = 2 and a2 = 3, so the progression will be
2, 3, 5(=2+3), 8(=3+5), 10(=2+3+5), 13(=5+8), 16(=3+5+8),
18(=2+3+5+8=8+10), 23(=5+8+10=10+13), 26(=3+5+8+10), 28(=2+3+5+8+10), 29(=13+16)...
I need to find the Nth number in this progression. ( Time limit is 0.7 seconds)
(a1 is smaller than a2, a2 is smaller than 1000 and N is smaller than 100000)
I tried priority queue, set, map, https://www.geeksforgeeks.org/find-subarray-with-given-sum/ and some other things.
I though that the priority queue would work, but it exceeds the memory limit (256 MB), so i am pretty much hopeless.
Here's what is performing the best at the moment.
int main(){
int a1, a2, n;
cin>>a1>>a2>>n;
priority_queue< int,vector<int>,greater<int> > pq;
pq.push(a1+a2);
int a[n+1];//contains sum of the progression
a[0]=0;
a[1]=a1;
a[2]=a1+a2;
for(int i=3;i<=n;i++){
while(pq.top()<=a[i-1]-a[i-2])
pq.pop();
a[i]=pq.top()+a[i-1];
pq.pop();
for(int j=1; j<i && a[i]-a[j-1]>a[i]-a[i-1] ;j++)
pq.push(a[i]-a[j-1]);
}
cout<<a[n]-a[n-1];
}
I've been trying to solve this for the last 4 days without any success.
Sorry for the bad english, i am only 14 and not from an english speaking coutry.
SOLUTION (Big thanks to n.m. and גלעד ברקן)
V1 (n.m.'s solution)
using namespace std;
struct sliding_window{
int start_pos;
int end_pos;
int sum;
sliding_window(int new_start_pos,int new_end_pos,int new_sum){
start_pos=new_start_pos;
end_pos=new_end_pos;
sum=new_sum;
}
};
class Compare{
public:
bool operator() (sliding_window &lhs, sliding_window &rhs){
return (lhs.sum>rhs.sum);
}
};
int main(){
int a1, a2, n;
//input
cin>>a1>>a2>>n;
int a[n+1];
a[0]=a1;
a[1]=a2;
queue<sliding_window> leftOut;
priority_queue< sliding_window, vector<sliding_window>, Compare> pq;
//add the first two sliding window positions that will expand with time
pq.push(sliding_window(0,0,a1));
pq.push(sliding_window(1,1,a2));
for(int i=2;i<n;i++){
int target=a[i-1]+1;
//expand the sliding window with the smalest sum
while(pq.top().sum<target){
sliding_window temp = pq.top();
pq.pop();
//if the window can't be expanded, it is added to leftOut queue
if(temp.end_pos+1<i){
temp.end_pos++;
temp.sum+=a[temp.end_pos];
pq.push(temp);
}else{
leftOut.push(temp);
}
}
a[i]=pq.top().sum;
//add the removed sliding windows and new sliding window in to the queue
pq.push(sliding_window(i,i,a[i]));
while(leftOut.empty()==false){
pq.push(leftOut.front());
leftOut.pop();
}
}
//print out the result
cout<<a[n-1];
}
V2 (גלעד ברקן's solution)
int find_index(int target, int ps[], int ptrs[], int n){
int cur=ps[ptrs[n]]-ps[0];
while(cur<target){
ptrs[n]++;
cur=ps[ptrs[n]]-ps[0];
}
return ptrs[n];
}
int find_window(int d, int min, int ps[], int ptrs[]){
int cur=ps[ptrs[d]+d-1]-ps[ptrs[d]-1];
while(cur<=min){
ptrs[d]++;
cur=ps[ptrs[d]+d-1]-ps[ptrs[d]-1];
}
return ptrs[d];
}
int main(void){
int a1, a2, n, i;
int args = scanf("%d %d %d",&a1, &a2, &n);
if (args != 3)
printf("Failed to read input.\n");
int a[n];
a[0]=a1;
a[1]=a2;
int ps[n+1];
ps[0]=0;
ps[1]=a[0];
ps[2]=a[0]+a[1];
for (i=3; i<n+1; i++)
ps[i] = 1000000;
int ptrs[n+1];
for(i=0;i<n+1;i++)
ptrs[i]=1;
for(i=2;i<n;i++){
int target=a[i-1]+1;
int max_len=find_index(target,ps, ptrs, n);
int cur=ps[max_len]-ps[0];
int best=cur;
for(int d=max_len-1;d>1;d--){
int l=find_window(d, a[i-1], ps, ptrs);
int cur=ps[l+d-1]-ps[l-1];
if(cur==target){
best=cur;
break;
}
if(cur>a[i-1]&&cur<best)
best=cur;
}
a[i]=best;
ps[i+1]=a[i]+ps[i];
}
printf("%d",a[n-1]);
}
Your priority queue is too big, you can get away with a much smaller one.
Have a priority queue of subarrays represenred e.g. by triples (lowerIndex, upperIndex, sum), keyed by the sum. Given array A of size N, for each index i from 0 to N-2, there is exactly one subarray in the queue with lowerIndex==i. Its sum is the minimal possible sum greater than the last element.
At each step of the algorithm:
Add the sum from the first element of the queue as the new element of A.
Update the first queue element (and all others with the same sum) by extending its upperIndex and updating sum, so it's greater than the new last element.
Add a new subarray of two elements with indices (N-2, N-1) to the queue.
The complexity is a bit hard to analyse because of the duplicate sums in p.2 above, but I guess there shouldn't be too many of those.
It might be enough to try each relevant subarray length to find the next element. If we binary search on each length for the optimal window, we can have an O(n * log(n) * sqrt(n)) solution.
But we can do better by observing that each subarray length has a low bound index that constantly increases as n does. If we keep a pointer to the lowest index for each subarray length and simply iterate upwards each time, we are guaranteed each pointer will increase at most n times. Since there are O(sqrt n) pointers, we have O(n * sqrt n) total iterations.
A rough draft of the pointer idea follows.
UPDATE
For an actual submission, the find_index function was converted to another increasing pointer for speed. (Submission here, username "turnerware"; C code here.)
let n = 100000
let A = new Array(n)
A[0] = 2
A[1] = 3
let ps = new Array(n + 1)
ps[0] = 0
ps[1] = A[0]
ps[2] = A[0] + A[1]
let ptrs = new Array(n + 1).fill(1)
function find_index(target, ps){
let low = 0
let high = ps.length
while (low != high){
let mid = (high + low) >> 1
let cur = ps[mid] - ps[0]
if (cur <= target)
low = mid + 1
else
high = mid
}
return low
}
function find_window(d, min, ps){
let cur = ps[ptrs[d] + d - 1] - ps[ptrs[d] - 1]
while (cur <= min){
ptrs[d]++
cur = ps[ptrs[d] + d - 1] - ps[ptrs[d] - 1]
}
return ptrs[d]
}
let start = +new Date()
for (let i=2; i<n; i++){
let target = A[i-1] + 1
let max_len = find_index(target, ps)
let cur = ps[max_len] - ps[0]
let best = cur
for (let d=max_len - 1; d>1; d--){
let l = find_window(d, A[i-1], ps)
let cur = ps[l + d - 1] - ps[l - 1]
if (cur == target){
best = cur
break
}
if (cur > A[i-1] && cur < best)
best = cur
}
A[i] = best
ps[i + 1] = A[i] + ps[i]
}
console.log(A[n - 1])
console.log(`${ (new Date - start) / 1000 } seconds`)
Just for fun and reference, this prints the sequence and possible indexed intervals corresponding to the element:
let A = [2, 3]
let n = 200
let is = [[-1], [-1]]
let ps = [A[0], A[0] + A[1]]
ps[-1] = 0
for (let i=2; i<n + 1; i++){
let prev = A[i-1]
let best = Infinity
let idxs
for (let j=0; j<i; j++){
for (let k=-1; k<j; k++){
let c = ps[j] - ps[k]
if (c > prev && c < best){
best = c
idxs = [[k+1,j]]
} else if (c == best)
idxs.push([k+1,j])
}
}
A[i] = best
is.push(idxs)
ps[i] = A[i] + ps[i-1]
}
let str = ''
A.map((x, i) => {
str += `${i}, ${x}, ${JSON.stringify(is[i])}\n`
})
console.log(str)
Looks like a sliding window problem to me.
#include <bits/stdc++.h>
using namespace std;
int main(int argc, char** argv) {
if(argc != 4) {
cout<<"Usage: "<<argv[0]<<" a0 a1 n"<<endl;
exit(-1);
}
int a0 = stoi(argv[1]);
int a1 = stoi(argv[2]);
int n = stoi(argv[3]);
int a[n]; // Create an array of length n
a[0] = a0; // Initialize first element
a[1] = a1; // Initialize second element
for(int i=2; i<n; i++) { // Build array up to nth element
int start = i-2; // Pointer to left edge of "window"
int end = i-1; // Pointer to right edge of "window"
int last = a[i-1]; // Last num calculated
int minSum = INT_MAX; // Var to hold min of sum found
int curSum = a[start] + a[end]; // Sum of all numbers in the window
while(start >= 0) { // Left edge is still inside array
// If current sum is greater than the last number calculated
// than it is a possible candidate for being next in sequence
if(curSum > last) {
if(curSum < minSum) {
// Found a smaller valid sum
minSum = curSum;
}
// Slide right edge of the window to the left
// from window to try to get a smaller sum.
// Decrement curSum by the value of removed element
curSum -= a[end];
end--;
}
else {
// Slide left edge of window to the left
start--;
if(!(start < 0)) {
// Increment curSum by the newly enclosed number
curSum += a[start];
}
}
}
// Add the min sum found to the end of the array.
a[i] = minSum;
}
// Print out the nth element of the array
cout<<a[n-1]<<endl;
return 0;
}

String decode: looking for a better approach

I have worked out a O(n square) solution to the problem. I was wondering about a better solution to this. (this is not a homework/interview problem but something I do out of my own interest, hence sharing here):
If a=1, b=2, c=3,….z=26. Given a string, find all possible codes that string
can generate. example: "1123" shall give:
aabc //a = 1, a = 1, b = 2, c = 3
kbc // since k is 11, b = 2, c= 3
alc // a = 1, l = 12, c = 3
aaw // a= 1, a =1, w= 23
kw // k = 11, w = 23
Here is my code to the problem:
void alpha(int* a, int sz, vector<vector<int>>& strings) {
for (int i = sz - 1; i >= 0; i--) {
if (i == sz - 1) {
vector<int> t;
t.push_back(a[i]);
strings.push_back(t);
} else {
int k = strings.size();
for (int j = 0; j < k; j++) {
vector<int> t = strings[j];
strings[j].insert(strings[j].begin(), a[i]);
if (t[0] < 10) {
int n = a[i] * 10 + t[0];
if (n <= 26) {
t[0] = n;
strings.push_back(t);
}
}
}
}
}
}
Essentially the vector strings will hold the sets of numbers.
This would run in n square. I am trying my head around at least an nlogn solution.
Intuitively tree should help here, but not getting anywhere post that.
Generally, your problem complexity is more like 2^n, not n^2, since your k can increase with every iteration.
This is an alternative recursive solution (note: recursion is bad for very long codes). I didn't focus on optimization, since I'm not up to date with C++X, but I think the recursive solution could be optimized with some moves.
Recursion also makes the complexity a bit more obvious compared to the iterative solution.
// Add the front element to each trailing code sequence. Create a new sequence if none exists
void update_helper(int front, std::vector<std::deque<int>>& intermediate)
{
if (intermediate.empty())
{
intermediate.push_back(std::deque<int>());
}
for (size_t i = 0; i < intermediate.size(); i++)
{
intermediate[i].push_front(front);
}
}
std::vector<std::deque<int>> decode(int digits[], int count)
{
if (count <= 0)
{
return std::vector<std::deque<int>>();
}
std::vector<std::deque<int>> result1 = decode(digits + 1, count - 1);
update_helper(*digits, result1);
if (count > 1 && (digits[0] * 10 + digits[1]) <= 26)
{
std::vector<std::deque<int>> result2 = decode(digits + 2, count - 2);
update_helper(digits[0] * 10 + digits[1], result2);
result1.insert(result1.end(), result2.begin(), result2.end());
}
return result1;
}
Call:
std::vector<std::deque<int>> strings = decode(codes, size);
Edit:
Regarding the complexity of the original code, I'll try to show what would happen in the worst case scenario, where the code sequence consists only of 1 and 2 values.
void alpha(int* a, int sz, vector<vector<int>>& strings)
{
for (int i = sz - 1;
i >= 0;
i--)
{
if (i == sz - 1)
{
vector<int> t;
t.push_back(a[i]);
strings.push_back(t); // strings.size+1
} // if summary: O(1), ignoring capacity change, strings.size+1
else
{
int k = strings.size();
for (int j = 0; j < k; j++)
{
vector<int> t = strings[j]; // O(strings[j].size) vector copy operation
strings[j].insert(strings[j].begin(), a[i]); // strings[j].size+1
// note: strings[j].insert treated as O(1) because other containers could do better than vector
if (t[0] < 10)
{
int n = a[i] * 10 + t[0];
if (n <= 26)
{
t[0] = n;
strings.push_back(t); // strings.size+1
// O(1), ignoring capacity change and copy operation
} // if summary: O(1), strings.size+1
} // if summary: O(1), ignoring capacity change, strings.size+1
} // for summary: O(k * strings[j].size), strings.size+k, strings[j].size+1
} // else summary: O(k * strings[j].size), strings.size+k, strings[j].size+1
} // for summary: O(sum[i from 1 to sz] of (k * strings[j].size))
// k (same as string.size) doubles each iteration => k ends near 2^sz
// string[j].size increases by 1 each iteration
// k * strings[j].size increases by ?? each iteration (its getting huge)
}
Maybe I made a mistake somewhere and if we want to play nice we can treat a vector copy as O(1) instead of O(n) in order to reduce complexity, but the hard fact remains, that the worst case is doubling outer vector size in each iteration (at least every 2nd iteration, considering the exact structure of the if conditions) of the inner loop and the inner loop depends on that growing vector size, which makes the whole story at least O(2^n).
Edit2:
I figured out the result complexity (the best hypothetical algoritm still needs to create every element of the result, so result complexity is like a lower bound to what any algorithm can archieve)
Its actually following the Fibonacci numbers:
For worst case input (like only 1s) of size N+2 you have:
size N has k(N) elements
size N+1 has k(N+1) elements
size N+2 is the combination of codes starting with a followed by the combinations from size N+1 (a takes one element of the source) and the codes starting with k, followed by the combinations from size N (k takes two elements of the source)
size N+2 has k(N) + k(N+1) elements
Starting with size 1 => 1 (a) and size 2 => 2 (aa or k)
Result: still exponential growth ;)
Edit3:
Worked out a dynamic programming solution, somewhat similar to your approach with reverse iteration over the code array and kindof optimized in its vector usage, based on the properties explained in Edit2.
The inner loop (update_helper) is still dominated by the count of results (worst case Fibonacci) and a few outer loop iterations will have a decent count of sub-results, but at least the sub-results are reduced to a pointer to some intermediate node, so copying should be pretty efficient. As a little bonus, I switched the result from numbers to characters.
Another edit: updated code with range 0 - 25 as 'a' - 'z', fixed some errors that led to wrong results.
struct const_node
{
const_node(char content, const_node* next)
: next(next), content(content)
{
}
const_node* const next;
const char content;
};
// put front in front of each existing sub-result
void update_helper(int front, std::vector<const_node*>& intermediate)
{
for (size_t i = 0; i < intermediate.size(); i++)
{
intermediate[i] = new const_node(front + 'a', intermediate[i]);
}
if (intermediate.empty())
{
intermediate.push_back(new const_node(front + 'a', NULL));
}
}
std::vector<const_node*> decode_it(int digits[9], size_t count)
{
int current = 0;
std::vector<const_node*> intermediates[3];
for (size_t i = 0; i < count; i++)
{
current = (current + 1) % 3;
int prev = (current + 2) % 3; // -1
int prevprev = (current + 1) % 3; // -2
size_t index = count - i - 1; // invert direction
// copy from prev
intermediates[current] = intermediates[prev];
// update current (part 1)
update_helper(digits[index], intermediates[current]);
if (index + 1 < count && digits[index] &&
digits[index] * 10 + digits[index + 1] < 26)
{
// update prevprev
update_helper(digits[index] * 10 + digits[index + 1], intermediates[prevprev]);
// add to current (part 2)
intermediates[current].insert(intermediates[current].end(), intermediates[prevprev].begin(), intermediates[prevprev].end());
}
}
return intermediates[current];
}
void cleanupDelete(std::vector<const_node*>& nodes);
int main()
{
int code[] = { 1, 2, 3, 1, 2, 3, 1, 2, 3 };
int size = sizeof(code) / sizeof(int);
std::vector<const_node*> result = decode_it(code, size);
// output
for (size_t i = 0; i < result.size(); i++)
{
std::cout.width(3);
std::cout.flags(std::ios::right);
std::cout << i << ": ";
const_node* item = result[i];
while (item)
{
std::cout << item->content;
item = item->next;
}
std::cout << std::endl;
}
cleanupDelete(result);
}
void fillCleanup(const_node* n, std::set<const_node*>& all_nodes)
{
if (n)
{
all_nodes.insert(n);
fillCleanup(n->next, all_nodes);
}
}
void cleanupDelete(std::vector<const_node*>& nodes)
{
// this is like multiple inverse trees, hard to delete correctly, since multiple next pointers refer to the same target
std::set<const_node*> all_nodes;
for each (auto var in nodes)
{
fillCleanup(var, all_nodes);
}
nodes.clear();
for each (auto var in all_nodes)
{
delete var;
}
all_nodes.clear();
}
A drawback of the dynamically reused structure is the cleanup, since you wanna be careful to delete each node only once.

Maximum value of M digits out of N digits [duplicate]

This question already has answers here:
How to get the least number after deleting k digits from the input number
(11 answers)
Closed 6 years ago.
I am trying to code a program that can do something like this:
in:
5 4
1 9 9 9 0
out:
9990
and i have a problem. It doesnt work on any set of numbers. For example it works for the one above, but it doesnt work for this one:
in:
15 9
2 9 3 6 5 8 8 8 8 7 2 2 8 1 4
out: 988887814
2 9 3 6 5 8 8 8 8 7 2 2 8 1 4
I did this with a vector approach and it works for any set of numbers, but i'm trying to do it a stack for a better complexity.
EDIT ---- MODIFIED FOR STD::STACK
Code for method using stack:
#include <iostream>
#include <fstream>
#include <stack>
using namespace std;
ifstream in("trompeta.in");
ofstream out("trompeta.out");
void reverseStack(stack<char> st) {
if(!st.empty())
{
char x = st.top();
st.pop();
reverseStack(st);
out<<x;
}
return;
}
int main()
{
int n,m,count=1;
stack <char> st;
char x;
in>>n>>m;
in>>x;
st.push(x);
for(int i=1; i<n; i++)
{
in>>x;
if(st.top()<x && count+n-i-1>=m)
{
st.pop();
st.push(x);
}
else
{
st.push(x);
count++;
if (count>m-1) break;
}
};
reverseStack(st);
}
Code for method using vectors:
#include <iostream>
#include <fstream>
using namespace std;
ifstream in ( "trompeta.in" );
ofstream out ( "trompeta.out" );
int main ()
{
int i = 0, N, M, max, j, p = 0, var;
in >> N >> M;
char* v = new char[N];
char* a = new char[M];
in >> v;
var = M;
max = v[0];
for ( i = 0; i < M; i++ )
{
for ( j = p ; j < N-var+1; j++ )
{
if ( v[j] > max )
{
max = v[j];
p = j;
}
}
var--;
a[i] = max;
max = v[p+1];
p = p+1;
}
for ( i = 0; i < M; i++ )
out << a[i]-'0';
}
Can any1 help me to get the STACK code working?
Using the fact that the most significant digit completely trumps all other digets except in place of a tie, I would look at the first (N-M+1) digits, find the largest single digit in that range.
If it occurs once, the first digit is locked in. Discard the digits which occur prior to that position, and you repeat for "maximum value of M-1 numbers of out N-position" to find the remaining digits of the answer. (or N-position-1, if position is zero based)
If it occurs multiple times, then recursively find "maximum value of M-1 numbers out of N-position" for each, then select the largest single result from these. There can be at most N such matches.
I forgot to mention, if N==M, you are also done.
proof of recursion:
Computing the value of the sub-match will always select M-1 digits. When M is 1, you only need to select the largest of a few positions, and have no more recursion. This is true for both cases. Also the "select from" steps always contain no more than N choices, because they are always based on selecting one most significant digit.
------------------ how you might do it with a stack ----------------
An actual implementation using a stack would be based on an object which contains the entire state of the problem, at each step, like so:
struct data { // require: n == digits.size()
int n, m;
std::string digits;
bool operator<(const data &rhs){ return digits < rhs.digits; }
};
The point of this is not just to store the original problem, but to have a way to represent any subproblem, which you can push and pop on a stack. The stack itself is not really important, here, because it is used to pick the one best result within a specific layer. Recursion handles most of the work.
Here is the top level function which hides the data struct:
std::string select_ordered_max(int n, int m, std::string digits) {
if (n < m || (int)digits.size() != n)
return "size wrong";
data d{ n, m, digits };
data answer = select_ordered_max(d);
return answer.digits;
}
and a rough pseudocode of the recursive workhorse
data select_ordered_max(data original){
// check trivial return conditions
// determine char most_significant
// push all subproblems that satisfy most_significant
//(special case where m==1)
// pop subproblems, remembering best
return answer {original.m, original.m, std::string(1, most_significant) + best_submatch.digits };
}
String comparison works on numbers when you only compare strings of the exact same length, which is the case here.
Yes, I know having n and m is redundant with digits.size(), but I didn't want to work too hard. Including it twice simplified some recursion checks. The actual implementation only pushed a candidate to the stack if it passed the max digit check for that level of recursion. This allowed me to get the correct 9 digit answer from 15 digits of input with only 28 candidates pushed to the stack (and them popped during max-select).
Now your code has quite a few issues, but rather than focusing on those lets answer the question. Let's say that your code has been corrected to give us:
const size_t M where M is the number of digits expected in our output
const vector<int> v which is the input set of numbers of size N
You just always want to pick the highest value most significant number remaining. So we'll keep an end iterator to prevent us from picking a digit that wouldn't leave us with enough digits to finish the number, and use max_element to select:
const int pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
auto maximum = 0;
auto end = prev(cend(v), M - 1);
auto it = max_element(cbegin(v), end);
for (auto i = M - 1; i > 0; --i) {
maximum += *it * pow10[i];
advance(end, 1);
it = max_element(next(it), end);
}
maximum += *it;
Live Example
This code depends upon M being greater than 0 and less than N and less than log10(numeric_limits<int>::max())
EDIT: Sad to say this solves the consecutive digits problem, after edits the question wants subsequent digits, but not necessarily consecutive
So the little known numeric library provides inner_product which seems like just the tool for this job. Now your code has quite a few issues, but rather than focusing on those lets answer the question. Let's say that your code has been corrected to give us:
vector<int> foo(M) where M is the number of digits expected in our output
const vector<int> v which is the input set of numbers of size N
We'll use foo in the inner_product, initializing it with decreasing powers of 10:
generate(begin(foo), end(foo), [i=int{1}]() mutable {
auto result = i;
i *= 10;
return result; });
We can then use this in a loop:
auto maximum = 0;
for (auto it = prev(rend(v), size(foo) + 1); it != rbegin(v); advance(it, -1)) {
maximum = max<int>(inner_product(cbegin(foo), cend(foo), it, 0), maximum);
}
maximum = max<int>(inner_product(cbegin(foo), cend(foo), rbegin(v), 0), maximum);
Live Example
To use it's initialization requires that your initial M was smaller than N, so you may want to assert that or something.
--EDITED--
here's my suggestion with STACK based on my previous suggestion using vector
findMaxValueOutOfNDigits(stackInput, M, N)
{
// stackInput = [2, 9, 3, 6, 5, 8, 8, 8, 8, 7, 2, 2, 8, 1, 4]
// *where 4 was the first element to be inserted and 2 was the last to be inserted
// if the sequence is inverted, you can quickly fix it by doing a "for x = 0; x < stack.length; x++ { newStack.push(stack.pop()) }"
currentMaxValue = 0
for i = 0; i < (M - N + 1); i++
{
tempValue = process(stackInput, M, N)
stackInput.pop()
if (tempValue > currentMaxValue)
currentMaxValue = tempValue
}
return currentMaxValue
}
process(stackInput, M, N)
{
tempValue = stackInput.pop() * 10^(N - 1)
*howManyItemsCanILook = (M - N + 1)
for y = (N - 2); y == 0; y++
{
currentHowManyItemsCanILook = *howManyItemsCanILook
tempValue = tempValue + getValue(stackInput, *howManyItemsCanILook) * 10^(y)
*howManyItemsCanILook = *howManyItemsCanILook - 1
for x = 0; x < (currentHowManyItemsCanILook - *howManyItemsCanILook); x++
{
stackInput.pop()
}
}
return tempValue
}
getValue(stackInput, *howManyItemsCanILook)
{
currentMaxValue = stackInput.pop()
if (currentMaxValue == 9)
return 9
else
{
goUntil = *howManyItemsCanILook
for i = 0; i < goUntil; i++
{
*howManyItemsCanILook = *howManyItemsCanILook - 1
tempValue = stackInput.pop()
if (currentMaxValue < tempValue)
{
currentMaxValue = tempValue
if (currentMaxValue == 9)
return currentMaxValue
}
}
return currentMaxValue
}
}
note: where *howManyItemsCanILook is passed by reference
I hope this helps

Finding the balance point in an array

This question is from a great youtube channel, giving problems that can be asked in interviews.
It's basically related to finding the balance point in an array. Here is an example to best explain it;
{1,2,9,4,-1}. In here since sum(1+2)=sum(4+(-1)) making the 9 the balance point. Without checking the answer I've decided to implement the algorithm before wanted to ask whether a more efficient approach could be done;
Sum all the elements in array O(n)
Get the half of the sum O(1)
Start scanning the array, from left, and stop when the sumleft is bigger than half of the general sum. O(n)
Do the same for the right, to obtain sum right. O(n).
If sumleft is equal to sumright return arr[size/2] else return -1
I'm asking because this solution popped into my head without any effort, providing the O(n) running time. Is this solution, if true, could be developed or if not true any alternative methods?
Your algorithm is not good (counter-example: 1 -1 1 0 1 -1 1), the good solution is to compute partial sum of your array (so that you can can compute sumleft and sumright in O(1) for each cell of the array) and then (or in the same time if you already know the global sum) search in your array a cell such that sumleft = sumright which is O(n).
The partial sum of the array A is
[A[0], A[0]+A[1], A[0]+A[1]+A[2], …, A[0]+A[1]+A[2]+…+A[n-1]]
example:
A=[5,2,3,1,4,6]
partial sum = [5,7,10,11,15,21]
With this array you can compute sumleft[i]=partial_sum[i-1] and sumright[i]=partial_sum[n-1]-partial_sum[i]
Improvement:
Computing the global sum first and then only the partial sum for the current index enable you to use only O(1) extra space instead of O(n) extra space if you store all the partial_sum array.
Basically add up all the numbers first. This will be an O(n) operation. Then substract one element from the array at a time starting from the beginning of the array till upper == lower. Thus the total order will be O(n).
int BalancePoint(int a[], int begin, int end) // find index of an array (balance point) such that sum of all elements before the index = sum of all elements after it; else return -1
{
if(!a) return -1;
else if(begin == end) return begin;
long long upper = 0;
long long lower = 0;
for(int i = begin; i <= end; ++i)
{
upper += *(a+i);
}
for(int j = begin; j <= end; ++j)
{
upper -= *(a+j);
if(upper == lower) return j;
lower += *(a+j);
}
return -1;
}
Using STL
int BalancePointSTL( const vector<int> &A ) // find index of an array (balance point) such that sum of all elements before the index = sum of all elements after it; else return -1
{
if(A.empty()) return -1;
long long upper = 0;
long long lower = 0;
for(unsigned int i = 0; i <= A.size(); ++i)
{
upper += A[i];
}
for(unsigned int j = 0; j < A.size(); ++j)
{
upper -= A[j];
if(upper == lower) return j;
lower += A[j];
}
return -1;
}
The following would have a better worst case performance but a couple more if-else comparisons
int BalancePoint2(int a[], int begin, int end) // Better worst case senario by factor of 2
{
if(!a) return -1;
else if(begin == end) return begin;
long long upper = 0;
long long lower = 0;
int mid = (end-begin)/2;
for(int i = begin; i < mid; ++i)
{
lower += *(a+i);
}
for(int i = mid+1; i <= end; ++i)
{
upper += *(a+i);
}
if(upper == lower) return mid;
else if(lower < upper)
{
lower += *(a+mid);
for(int i= mid + 1 ; i <= end ; ++i)
{
upper -= *(a + i);
if(upper == lower) return i;
lower += *(a + i);
}
}
else {
upper += *(a + mid);
for(int i = mid - 1; i >=begin; --i)
{
lower -= *(a + i);
if(upper == lower) return i;
upper += *(a + i);
}
}
return -1;
}
I would actually have 2 start points, one on the leftmost point (leftLoc), and one at the right most point (rightLoc). Hold a sumLeft and sumRight numbers.
leftLoc = 0;
rightLoc = (n - 1);
sumRight = array[rightLoc];
sumLeft = array[leftLoc];
while(leftLoc < rightLoc){
if(sumRight > sumLeft){
leftLoc++;
sumLeft += array[leftLoc];
}else{
rightLoc--;
sumRight += array[rightLoc];
}
}
if( (sumRight + array[rightLoc - 1]) == sumLeft ){
return rightLoc--;
}else if( (sumLeft + array[leftLoc + 1]) == sumRight){
return leftLoc++;
}else{
// return floating point number location in the middle of the 2 locations
}
All the while keeping track of how many total positions have been moved O(n)
You may find that your balance point is a floating point number in the middle of the final points (once they are at the integer locations right next to one another).
This should even work with the negative numbers example. Perhaps I am missing some fine grain details, but some variation on this theme should result you in an O(n) runtime algorithm.
You're looking for the centroid or center of mass. In pure Python:
def centroid(input_list):
idx_val_sum = 0.0
val_sum = 0.0
for idx,val in enumerate(input_list):
idx_val_sum += idx*val
val_sum += val
return idx_val_sum/float(val_sum)
It's O(n) and if non-integer results are ill-formed, you can reject them with a modulo check:
def integer_centroid(input_list):
idx_val_sum = 0.0
val_sum = 0.0
for idx,val in enumerate(input_list):
idx_val_sum += idx*val
val_sum += val
out = idx_val_sum/float(val_sum)
if out%1.0==0.0:
return out
else:
raise ValueError("Input list has non-integer centorid.")
This post should have been a comment replying to trumpetlicks June 14 2012 comment, but I don't have enough reputation. "Order" is implicitly tracked in idx_val_sum, which is the cumulative position sum weighted by value.
Edit:
Matt, thank you for your observation. I assumed this was a pseudocode question, but now I see the C++ tag. Here's some (untested) C++, with comments.
An intuitive example is a simple lever arm problem: if you have a lever with two forces f1 and f2 acting on it at positions x1 and x2, you can prevent the system from rotating by applying a force at position (f1*x1+f2*x2)/(f1+f2). A continuous system requires integration over the product of x and f, but levers with discrete locations and forces are a good analogy for this problem.
// untested code:
float centroid(float * vec, int vec_length){
float idx_val_sum = 0.0;
float val_sum = 0.0;
for (idx = 0; idx < vec_length; idx++){
// keep a running sum of the product of the index and the value
idx_val_sum += float(idx)*vec[idx];
// similarly, keep a running sum of the index
val_sum += vec[idx];
}
// return the quotient of the product-sum and the index sum:
return idx_val_sum/val_sum;
}
A solution that's O(n) and doesn't require more space
def balance_array(arr):
if len(arr) < 3:
return False
for i in range(1, len(arr)+1):
lsum = sum(arr[:i])
rsum = sum(arr[(i+1):])
if lsum == rsum:
return True
return False
Testing
test_arrays = [[5, 3, 7, 0, 9], [5,2,3,1,4,6], [1,0,1], [1,6,5,1,2,3,1], [1,1], [], [1], [1,2,9,4,-1], [5, 4, 7, 0, 9], [1, -1, 1, 0, 1, -1, 1]]
for i in test_arrays:
print(f'{i}\t{balance_array(i)}')
[5, 3, 7, 0, 9] False
[5, 2, 3, 1, 4, 6] True
[1, 0, 1] True
[1, 6, 5, 1, 2, 3, 1] True
[1, 1] False
[] False
[1] False
[1, 2, 9, 4, -1] True
[5, 4, 7, 0, 9] True
[1, -1, 1, 0, 1, -1, 1] True
I believe you are looking for the Center of Mass, here is a solution written in Go:
func centerOfGravity(a []int) float64 {
tot := 0.0
mass := 0.0
for i := range a {
tot += float64(i) * float64(a[i])
mass += float64(a[i])
}
return tot / mass
}
This gives you the index of the center of mass in the array, assuming a 0-based array. It can return a non-integer result since the center of mass can be anywhere in the range of the array.