Number of monotonus subvectors in one vector - c++

I need to find a number of monotonus subvectors or arrays in my vector, or arrays, it doesn't mater. For example , I have vector 1234421257843, and here i have 4 monotonus subvectors...
1. 1 2 3 4 4
2. 4 4 2 1
3. 1 2 5 7 8
4. 8 4 3, and number is 4.
I tried something like this ,but doesn't work...
int num(std::vector<int> v){
int p(1),q(1);
for(int i(0);i<v.size()-1;i++){
if (v[i] > v[i+1] ) continue;
else if(v[i] < v[i+1]) continue;
else p++;
} return p;
}

I believe this will help you to find number of monotonus subvectors in one vector:
int num(const std::vector<int>& v) {
int p = 0;
for (int i = 0; i + 1 < v.size(); ) {
p += (v[i+1] >= v[i]);
for (++i; (i + 1 < v.size()) && (v[i+1] >= v[i]); ++i) {
}
if (i + 1 == v.size())
return p;
p += (v[i+1] <= v[i]);
for (++i; (i + 1 < v.size()) && (v[i+1] <= v[i]); ++i) {
}
}
return p;
}
But if you want to find largest monotonus subvector you don't need this. The task can be solved with the help of DP (Dynamic programming): you need two additional vectors a(n) and d(n), where a(i) / d(i) - is the length of longest ascending / descending subvector ending at position i: starting with a[0] = 1 you can easily calculate a[i + 1] = a[i] + 1 if v[i+1] > v[i] or 1 otherwise

Related

how to update the elements of an array with the sum of previous two and next two elements?

how to update the elements of an array with the sum of previous two and next two elements ? given that for the first element the sum would be the sum of next two elements as there is no previous element and same is the case for last element.
for example given an array {1,2,3} the array will be updated as {5,4,3}
explanation: for 1 there is no previous element so it will be udated as 2+3=5, for 2 there is only 1 previous and only 1 next element so it will be updated as 1+3=4, similarly for 3 it will be 1+2=3.
i tried doing this with if else loops but that seems too confusing and lengthy is there any other way to solve this?
for(int i=0;i<n;i++){
if(i==0){
sum=arr[1]+arr[2];
}
if(i==1){
sum=arr[0]+arr[2]+arr[3];
}
if(i==n-1){
sum=arr[n-2]+arr[n-3];
}
if(i==n-2){
sum=arr[n-1]+arr[n-3]+arr[n-4];
}
}
the above code does not work for n==3 because element at i==1 will be same as n-2 , also this code is so lengthy. how should i solve this question?
You need to create a temporary array to store the initial value of arr to prevent calculating the new value of arr[i] using new values (post-update) of arr[i - 1], arr[i - 2], etc.
std::vector<int> initial_value(arr, arr + n);
for (int i = 0; i < n; ++i) {
int updated_value = 0;
if (i - 2 >= 0) {
updated_value += initial_value[i - 2];
}
if (i - 1 >= 0) {
updated_value += initial_value[i - 1];
}
if (i + 1 < n) {
updated_value += initial_value[i + 1];
}
if (i + 2 < n) {
updated_value += initial_value[i + 2];
}
arr[i] = updated_value;
}
You could use some logic like this if u are looking for minimal code
Psuedo code
for(int i=0;i<sizeof(arr);i++){
int sum = 0;
int startIndex = (i+2) > sizeof(arr) ? sizeof(arr) : (i+2) ;
while(startIndex > (i - 2) && startIndex > 0)
{
if(startIndex == i) continue;
sum = sum + arrCopy[startIndex];
startIndex --;
}
arr[i] = sum;
}

Min sum of distances (absolute differences) between array element and set of k array elements

I need to find the minimum sum of the distances between an element in the array and the set of k-elements of the array, not including that index.
For example:
arr = {5, 7, 4, 9}
k = 2
min_sum(5) = |5-4| + |5-7| = 3
min_sum(7) = |7-9| + |7-5| = 4
min_sum(4) = |4-5| + |4-7| = 4
min_sum(9) = |9-7| + |9-5| = 6
So, a naive solution would be to subtract the i-th element from each element of the array, then sort the array and calculate the sum of the first k elements in the sorted array. But it takes too long... I believe this is a dp-problem or something like that (maybe treaps).
Input:
n - number of array elements
k - number of elements in a set
array
Constraints:
2 <= n <= 350 000
1 <= k < n
1 <= a[i] <= 10^9
time limit: 2 seconds
Input:
4
2
5 7 4 9
Output:
3 4 4 6
What is the most efficient way to solve this problem? How to optimize the search for the minimum sum?
This is my code in C++, and it works about 3 mins for n = 350 000, k = 150 000:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, tp;
unsigned long long temp;
cin >> n >> k;
vector<unsigned int> org;
vector<unsigned int> a;
vector<unsigned long long> cum(n, 0);
//unordered_map <int, long long> ans;
unordered_map <int, long long> mp;
for (int i = 0; i < n; i++){
cin >> tp;
org.push_back(tp);
a.push_back(tp);
}
/*
srand(time(0));
for (int i = 0; i < n; i++){
org.push_back(rand());
a.push_back(org[i]);
}
*/
sort(a.begin(), a.end());
partial_sum(a.begin(), a.end(), cum.begin());
mp[a[0]] = cum[k] - cum[0] - a[0] * k;
//ans[a[0]] = mp[a[0]];
for (int i = 1; i <= k; i++) {
mp[a[i]] = a[i] * i - cum[i-1] + cum[k] - cum[i] - a[i] * (k-i);
}
for (int i = 1; i < n-k; i++){
for (int j = 0; j <= k; j++){
//if (ans.find(a[i+j]) != ans.end()) {continue;}
temp = ( (a[i+j] * j) - (cum[i+j-1] - cum[i-1]) ) + ( cum[i+k] - cum[i+j] - a[i+j] * (k-j) );
if (mp.find(a[i+j]) == mp.end()) { mp[a[i+j]] = temp; }
else if (mp[a[i+j]] > temp) { mp[a[i+j]] = temp; }
//else { ans[a[i+j]] = mp[a[i+j]]; }
}
}
for (int i = 0; i < n; i++) {
cout << mp[org[i]] << " ";
}
return 0;
}
We can solve this problem efficiently by taking the sliding window approach.
It seems safe to assume that there are no duplicates in the array. If it contains duplicates, then we can simply discard them with the help of HashSet.
The next step is to sort the array to guarantee that the closest k elements will be within the window [i - k; i + k] for each index i.
We will keep three variables for the window: left, right and currentSum. They will be adjusted accordingly at each iteration. Initially, left = 0 and right = k(since the element at index 0 doesn't have elements to its left) and currentSum = result for index 0.
The key consideration is that the variables left and right are unlikely to change 'significantly' during the iteration. To be more precise, at each iteration we should attempt to move the window to the right by comparing the distances nums[i + right + 1] - nums[i] vs nums[i] - nums[i - left]. (You can prove mathematically that there is no point in trying to move the window to the left.) If the former is less than the latter, we increment right and decrement left while updating currentSum at the same time.
In order to recalculate currentSum, I would suggest writing down expressions for two adjacent iterations and looking closer at the difference between them.
For instance, if
result[i] = nums[i + 1] + ... + nums[i + right] - (nums[i - 1] + ... + nums[i - left]) + (left - right) * nums[i], then
result[i] = nums[i + 2] + ... + nums[i + right] - (nums[i] + ... + nums[i - left]) + (left - right + 2) * nums[i + 1].
As we can see, these expressions are quite similar. The time complexity of this solution is O(n * log(n)). (my solution in Java for n ~ 500_000 and k ~ 400_000 works within 300 ms) I hope this together with the consideration above will help you.
Assuming that we have sorted the original array nums and computed the mapping element->its index in the sorted array(for instance, through binary search), we can proceed with finding the distances.
public long[] findMinDistances(int[] nums, int k) {
long[] result = new long[nums.length];
long currentSum = 0;
for (int i = 1; i <= k; i++) {
currentSum += nums[i];
}
result[0] = currentSum - (long) k * nums[0];
int left = 0;
int right = k;
currentSum = result[0];
for (int i = 1; i < nums.length; i++) {
int current = nums[i];
int previous = nums[i - 1];
currentSum -= (long) (left - right) * previous;
currentSum -= previous;
if (right >= 1) {
currentSum -= current;
left++;
right--;
} else {
currentSum += nums[i - 1 - left];
}
currentSum += (long) (left - right) * current;
while (i + right + 1 < nums.length && i - left >= 0 &&
nums[i + right + 1] - current < current - nums[i - left]) {
currentSum += nums[i + right + 1] - current;
currentSum -= current - nums[i - left];
right++;
left--;
}
result[i] = currentSum;
}
return result;
}
For every element e in the original array its minimal sum of distances will be result[mapping.get(e)].
I think this one is better:
Sort the array first then you can know that fact -
For every element i in the array the k minimum distances of it with other elemets will be the distances with the ones that in k places around it in the array.
(of course it's maybe to the right or to the left or from both sides).
So for every element i to calculate min_sum(a[i]) do that:
First, min_sum(a[i]) = 0.
Then, go with two indexes, let's mark them r (to the right of i) and l (to the left of i)
and compare the distance (a[i]-a[r]) with the distance (a[i]-a[l]).
You will add the smallest to min_sum(a[i]) and if it was the right one then
increas index r, and if it was the left one then decrease index l.
Of course if the left got to 0 or the right one got to n you will most take the distaces with elemets from the other side.
Anyway you do that till you sum k elemets and that's it.
This way you didn't sort any thing but the main array.

Coursera DSA Algorithmic toolbox week 4 2nd question- Partitioning Souvenirs

Problem Statement-
You and two of your friends have just returned back home after visiting various countries. Now you would
like to evenly split all the souvenirs that all three of you bought.
Problem Description
Input Format- The first line contains an integer ... The second line contains integers v1, v2, . . . ,vn separated by spaces.
Constraints- 1 . .. . 20, 1 . .... . 30 for all ...
Output Format- Output 1, if it possible to partition 𝑣1, 𝑣2, . . . , 𝑣𝑛 into three subsets with equal sums, and
0 otherwise.
What's Wrong with this solution? I am getting wrong answer when I submit(#12/75) I am solving it using Knapsack without repetition taking SUm/3 as my Weight. I back track my solution to replace them with 0. Test cases run correctly on my PC.
Although I did it using OR logic, taking a boolean array but IDK whats wrong with this one??
Example- 11
17 59 34 57 17 23 67 1 18 2 59
(67 34 17)are replaced with 0s. So that they dont interfare in the next sum of elements (18 1 23 17 59). Coz both of them equal to 118(sum/3) Print 1.
#include <iostream>
#include <vector>
using namespace std;
int partition3(vector<int> &w, int W)
{
int N = w.size();
//using DP to find out the sum/3 that acts as the Weight for a Knapsack problem
vector<vector<int>> arr(N + 1, vector<int>(W + 1));
for (int k = 0; k <= 1; k++)
{
//This loop runs twice coz if 2x I get sum/3 then that ensures that left elements will make up sum/3 too
for (int i = 0; i < N + 1; i++)
{
for (int j = 0; j < W + 1; j++)
{
if (i == 0 || j == 0)
arr[i][j] = 0;
else if (w[i - 1] <= j)
{
arr[i][j] = ((arr[i - 1][j] > (arr[i - 1][j - w[i - 1]] + w[i - 1])) ? arr[i - 1][j] : (arr[i - 1][j - w[i - 1]] + w[i - 1]));
}
else
{
arr[i][j] = arr[i - 1][j];
}
}
}
if (arr[N][W] != W)
return 0;
else
{
//backtrack the elements that make the sum/3 and = them to 0 so that they don't contribute to the next //elements that make sum/3
int res = arr[N][W];
int wt = W;
for (int i = N; i > 0 && res > 0; i--)
{
if (res == arr[i - 1][wt])
continue;
else
{
std::cout << w[i - 1] << " ";
res = res - w[i - 1];
wt = wt - w[i - 1];
w[i - 1] = 0;
}
}
}
}
if (arr[N][W] == W)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
int n;
std::cin >> n;
vector<int> A(n);
int sum = 0;
for (size_t i = 0; i < A.size(); ++i)
{
int k;
std::cin >> k;
A[i] = k;
sum += k;
}
if (sum % 3 == 0)
std::cout << partition3(A, sum / 3) << '\n';
else
std::cout << 0;
}
Sum/3 can be achieved by multiple ways!!!! So backtracking might remove a subset that has an element that should have been a part of some other subset
8 1 6 is 15 as well as 8 2 5 makes 15 so better is u check this
if(partition3(A, sum / 3) == sum / 3 && partition3(A, 2 * (sum / 3)) == 2 * sum / 3 && sum == partition3(A, sum))

How to remove every multiple of 2 element in a vector by index

I am trying to remove every 2nd element from an integer vector in C++
int n = 10001;
std::vector<int> sieve;
for (int i = 2; i <= n; ++i)
sieve.push_back(i);
for (int i = 2; i < sieve.size(); i += 2)
sieve.erase(sieve.begin() + i);
I want to remove every 2nd element from the vector ( which would be multiples of 2 in range from 2-10001). The output is this:
// index, value
0 2
1 3
2 5
3 6
4 8
5 9
6 11
7 12
8 14
9 15
10 17
....
So it removes the 4, 10, and 16 as expected. However there are still many multiples of 2 still in there, ie 6, 8, 12, 14
EDIT Solved using method #Retired Ninja posted in comments. (Do it in reverse)
for (int i = 2; i <= n; i++)
sieve.push_back(i);
for (int i = sieve.size(); i >= p; i -= p)
sieve.erase(sieve.end() - i);
When you are erasing second element the iterator of next element decrease 1.
So increasing 1 time of loop variable is ok.
int n = 100;
std::vector<int> sieve;
for (int i = 2; i <= n; ++i)
sieve.push_back(i);
for (int i = 2; i < sieve.size(); i += 1)
sieve.erase(sieve.begin() + i);
And another way in case of erasing pth element:
int cnt=0;
int l=sieve.size();
for (int i = 2; i < l; i += p){
sieve.erase(sieve.begin() + (i-cnt));
cnt++;
}
How about this? This removes every nth element starting at start from vec.
It's performed in-place, involves only a single array resize, and each element not erased is moved exactly once.
void remove(std::size_t nth, std::size_t start, std::vector<int> &vec)
{
std::size_t step;
for (step = 1; start < vec.size(); ++step, start += nth)
{
for (std::size_t i = 1; i < nth && start + i < vec.size(); ++i)
{
vec[start + i - step] = vec[start + i];
}
}
vec.resize(vec.size() - (step - 1));
}

Finding regional maximum elements by iterative method

Assumed that I'd find regional maximum elements in the following matrix. The regional maximum are 8-connected elements with the same value t, whose external boundary all have a value less than t. In this case, the results expected are one element that equals 8 and five elements that equal 9.
1 1 1 1 1 1 1 1 1 1
1 2 2 2 2 2 2 1 1 1
1 1 2 8 2 2 2 9 1 1
1 1 1 1 2 2 9 9 9 1
1 2 2 2 2 2 2 9 1 1
1 1 1 1 1 1 1 1 1 1
For the first situation, it is very easy to pick 8 from its 8-connected neighbors because 8 is the greatest among them. The pseudo code:
for (i = 0; i < 10; i++) {
for (j = 0; j < 6; j++) {
if element(i, j) > AllOfNeighbors(i, j)
RecordMaxElementIndex(i, j);
}
}
But for the second situation, I get confused. This time 9 is greater than some of its neighbors and equals to the other neighbors. The pseudo code would be:
for (i = 0; i < 10; i++) {
for (j = 0; j < 6; j++) {
// Start iteration
if element(i, j) > AllOfNeighbors(i, j)
RecordMaxElementIndex(i, j);
else if element(i, j) > SomeOfNeighbors(i, j) &&
element(i, j) == TheOtherNeighbors(i, j)
RecordTheOtherNeighborsIndex(i, j);
// Jump to the start now
}
}
For example, when (i, j) is (7, 2), elements at (6, 3), (7, 3) and (8, 3) will be recorded for the next iterative round. I'm not sure whether using iterative method is proper here but I think TheOtherNeighbors(ii, jj) could be treated as element(i, j) and repeat the same process to find the regional maximum. Moreover, (6, 3) cannot be compared to (7, 2), (7, 3) and (8, 3)again in case endless loop. So how to implement the iterative method? Any guide would be helpful.
As I understand, you may create the connected components using Disjoint-set_data_structure and mark component that are not maximal...
Pseudo code:
DisjointSet disjointSet[10][6]
// Init disjointSet
for (i = 0; i < 10; i++) {
for (j = 0; j < 6; j++) {
disjointSet[i][j].MakeSet({i, j});
disjointSet[i][j].MarkAsMaximal(); // extra flag for your case
}
}
// Create Connected component and mark as not maximal
for (i = 0; i < 10; i++) {
for (j = 0; j < 6; j++) {
for (auto neighborDisjointSet : NeighborsWithSameValue(i, j)) {
Union(disjointSet[i][j], neighborDisjointSet);
}
if (element(i, j) < AnyOfNeighbors(i, j)) {
disjointSet[i][j].MarkAsNotMaximal();
}
for (auto neighborDisjointSet : NeighborsWithSmallValue(i, j) {
neighborDisjointSet.MarkAsNotMaximal();
}
}
}
// Collect result.
std::set<DisjointSet> maximumRegions;
for (i = 0; i < 10; i++) {
for (j = 0; j < 6; j++) {
if (disjointSet[i][j].IsMarkAsMaximal) {
maximumRegions.insert(disjointSet[i][j]);
}
}
}