Let's assume we've got a sequence of integers of given length n. We want to delete some elements (maybe none), so that the sequence is increasing and decreasing by turns in result. It means, that every element should have neighbouring elements either both bigger or both smaller than itself.
For example 1 3 2 7 6 and 5 1 4 2 10 are both sequences increasing and decreasing by turns.
We want to delete some elements to transform our sequence that way, but we also want to maximize the sum of elements left. So, for example, from sequence 2 18 6 7 8 2 10 we want to delete 6 and make it 2 18 7 8 2 10.
I am looking for an effective solution to that problem. Example above shows that the most naive greedy algorithm (delete every first element that breaks the sequence) won't work - it would delete 7 instead of 6, which would not maximize the sum of elements left.
Any ideas how to solve that effectively (O(n) or O(n log n) probably) and correctly?
For every element of the sequence with index i we will calculate F(i, high) and F(i, low), where F(i, high) equals to the biggest sum of the subsequence with wanted characteristics that ends with the i-th element and this element is a "high peak". (I'll explain mainly the "high" part, the "low" part can be done similarly). We can calculate these functions using the following relations:
The answer is maximal among all F(i, high) and F(i, low) values.
That gives us a rather simple dynamic programming solution with O(n^2) time complexity. But we can go further.
We can optimize a calculation of max(F(j,low)) part. What we need to do is to find the biggest value among previously calculated F(j, low) with the condition that a[j] < a[i]. This can be done with segment trees.
First of all, we'll "squeeze" our initial sequence. We need the real value of the element a[i] only when calculating the sum. But we need only the relative order of the elements when checking that a[j] is less than a[i]. So we'll map every element to its index in the sorted elements array without duplicates. For example, sequence a = 2 18 6 7 8 2 10 will be translated to b = 0 5 1 2 3 0 4. This can be done in O(n*log(n)).
The biggest element of b will be less than n, as a result, we can build a segment tree on the segment [0, n] with every node containing the biggest sum within the segment (we need two segment trees for "high" and "low" part accordingly). Now let's describe the step i of the algorithm:
Find the biggest sum max_low on the segment [0, b[i]-1] using the "low" segment tree (initially all nodes of the tree contain zero).
F(i, high) is equal to max_low + a[i].
Find the biggest sum max_high on the segment [b[i]+1, n] using the "high" segment tree.
F(i, low) is equal to max_high + a[i].
Update the [b[i], b[i]] segment of the "high" segment tree with F(i, high) value recalculating maximums of the parent nodes (and [b[i], b[i]] node itself).
Do the same for "low" segment tree and F(i, low).
Complexity analysis: b sequence calculation is O(n*log(n)). Segment tree max/update operations have O(log(n)) complexity and there are O(n) of them. The overall complexity of this algorithm is O(n*log(n)).
Related
Question:
Given an array of N numbers contain a permutation of N. You have 2 types of swaps:
Swap any 2 numbers of the array (you can only do this once)
Swap adjacent numbers (you can do this many times)
What is the least number of swap to sort the array?
Example:
arr[] = {5, 3, 4, 2, 1}
answer: 3
Explaination:
- Swap 5 and 1
- Swap 4 and 2
- Swap 3 and 2
P/S:
I think that we need to use the "free swap" first and then use merge sort. But I don't know how to use the the "free swap" so that the merge sort is minimum.
I think you can just swap the number that is most left from where it should be with the one that is most right from where it should be.
So left would be index i where arr[i] - i is the maximum. And right would be index j where arr[j] - j is the minimum. Then just swap element i with j. This is O(n).
Afterwards you can count the number of swaps you have to do for bubble sort. For this you count all elements which are smaller and to the right of the current element. You can do this in O(n logn) by going from right to left and then for each element you insert it in a balanced sorted tree where you also store the number of nodes in the subtree for each edge (e.g. modified AVL tree). This allows you to count the number of elements which are smaller and to the right of the current one in O(logn).
Say we have an array A that contains N integers. The problem is that we want to minimize the cost of some increasing subsequence(not necessarily strictly increasing) starting at position 1 and ending at position N. The total cost of a subsequence is the total cost of transitioning between elements in the subsequence. When building the subsequence, the cost of transitioning from position j to position i, where i >= j can be found in the matrix COST[i][j]. It is guaranteed that some increasing subsequence exists in which we start from position 1 and reach position N. Values in the array may be very large.
For example:
N = 5
A = [0,3,2,3,3]
Cost =
[[0,INF,INF,INF,INF],
[3,0,INF,INF,INF],
[3,INF,0,INF,INF],
[5,2,2,0,INF],
[6,0,3,1,0]]
The least-cost increasing subsequence is (A[1], A[2], A[5]) or (0,3,3).
The cost
is COST[2][1] + COST[5][2] = 3 + 0 = 3.
So far I have been able to modify the traditional O(n^2) dp solution by initializing dp[i] to infinity and dp[1] to 0 and subsequently looping over all previous values to extend the subsequence. While iterating through previous values I simply maintain the minimum cost.
Now I want to improve this solution and make it o(nlogn). I know the regular LIS problem can be solved using arrays and binary search, but I have been unable to modify such an approach to fit this problem.
I want to maximize number of zigzag sequence in an array(without reordering).
I've a main array of random sequence of integers.I want a sub-array of index of main array that has zigzag pattern.
A sequence of integers is called zigzag sequence if each of its elements is either strictly less or strictly greater than its neighbors(and two adjacent of neighbors).
Example : The sequence 4 2 3 1 5 2 forms a zigzag, but 7 3 5 5 2 and 3 8 6 4 5
and 4 2 3 1 5 3 don't.
For a given array of integers we need to find (contiguous) sub-array of indexes that forms a zigzag sequence.
Can this be done in O(N) ?
Yes, this would seem to be solvable in O(n) time. I'll describe the algorithm as a dynamic program.
Setup
Let the array containing potential zig-zags be called Z.
Let U be an array such that len(U) == len(Z), and U[i] is an integer representing the largest contiguous left-to-right subsequence starting at i that is a zig-zag such that Z[i] < Z[i+1] (it zigs up).
Let D be similar to U, except that D[i] is an integer representing the largest contiguous left-to-right subsequence starting at i that is a zig-zag such that Z[i] > Z[i+1] (it zags down).
Subproblem
The subproblem is to find both U[i] and D[i] at each i. This can be done as follows:
U[i] = {
1 + D[i+1] if i < i+1
0 otherwise
}
L[i] = {
1 + U[i+1] if i > i+1
0 otherwise
}
The top version says that if we're looking for the largest sequence beginning with an up-zig, we see if the next element is larger (goes up), and then add a single zig to the size of the next down-zag sequence. The next one is the reverse.
Base Cases
If i == len(Z) (it is the last element), U[i] = L[i] = 0. The last element cannot have a left-to-right sequence after it because there is nothing after it.
Solution
To get the solution, first we find max(U[i]) and max(L[i]) for every i. Then get the maximum of those two values, store i, and store the length of this largest zig-zag (in a variable called length). The sequence begins at index i and ends at index i + length.
Runtime
There are n indexes, so there are 2n subproblems between U and L. Each subproblem takes O(1) time to solve, given that solutions to previously solved subproblems are memoized. Finally, iterating through U and L to get the final answer takes O(2n) time.
We thus have O(2n) + O(2n) time, or O(n).
This may be an overly complex solution, but it demonstrates that it can be done in O(n).
Given n pairs of numbers, select k pairs so that the difference between the minimum value and the maximum value is minimal. Note that 2 numbers in 1 pair cannot be separated. Example (n=5, k=3):
INPUT OUTPUT (return the index of the pairs)
5 4 1 2 4
1 5
9 8
1 0
2 7
In this case, choosing (5,4) (1,5) (1,0) will give a difference of 5 (max is 5, min is 0). I'm looking for an efficient way (n log n) of doing this since the input will be pretty large and I don't want to go through every possible case.
Thank you.
NOTE: No code is needed. An explanation of the solution is enough.
Here's a method with O(n log n) time complexity:
First sort the array according to the smaller number in the pair. Now iterate back from the last element in the sorted array (the pair with the highest minimum).
As we go backwards, the elements already visited will necessarily have an equal or higher minimum than the current element. Store the visited pairs in a max heap according to the maximal number in the visited pair. If the heap size is smaller than k-1, keep adding to the heap.
Once the heap size equals k-1, begin recording and comparing the best interval so far. If the heap size exceeds k-1, pop the maximal element off. The heap is guaranteed to contain the first k-1 pairs where the minimal number is greater than or equal to the current minimal number and the maximal is smallest (since we keep popping off the maximal element when the heap size exceeds k-1).
Total time O(n log n) for sorting + O(n log n) to iterate and maintain the heap = O(n log n) in total.
Example:
5 4
1 5
9 8
1 0
2 7
k = 3
Sort pairs by the smaller number in each pair:
[(1,0),(1,5),(2,7),(5,4),(9,8)]
Iterate from end to start:
i = 4; Insert (9,8) into heap
i = 3; Insert (5,4) into heap
i = 2; Range = 2-9
i = 1; Pop (9,8) from heap; Range = 1-7
i = 0; Pop (2,7) from heap; Range = 0-5
Minimal interval [0,5] (find k matching indices in O(n) time)
Lets keep to sorted arrays: one which sorted according to minimal number in pair and other to maximal. Lets iterate over first array and fix minimal number in answer. We can keep pointer on k-th number in second array. When we go to next pair we remove all pairs with less minimal value from second array and forward pointer if needed. To find position in log n time in second array we can keep additional map between pair and position.
Two integers N<=10^5 and K<=N are given, where N is the size of array A[] and K is the length of continuous subsequence we can choose in our process.Each element A[i]<=10^9. Now suppose initially all the elements of array are unmarked. In each step we'll choose any subsequence of length K and if this subsequence has unmarked elements then we will mark all the unmarked elements which are minimum in susequence. Now how to calculate minimum number of steps to mark all the elements?
For better understanding of problem see this example--
N=5 K=3
A[]=40 30 40 30 40
Step 1- Select interval [1,3] and mark A[1] and A[3]
Step2- Select interval [0,2] and mark A[0] and A[2]
Step 3- Select interval [2,4] and mark A[4]
Hence minimum number of steps here is 3.
My approach(which is not fast enough to pass)-
I am starting from first element of array and marking all the unmarked elements equal to it at distance <=K and incrementing steps by 1.
First consider how you'd answer the question for K == N (i.e. without any effective restriction on the length of subsequences). Your answer should be that the minimum number of steps is the number of distinct values in the array.
Then consider how this changes as K decreases; all that matters is how many copies of a K-length interval you need to cover the selection set {i: A[i] == n} for each value n present in A. The naive algorithm of walking a K-length interval along A, halting at each position A[i] not yet covered for that value of n is perfectly adequate.
As we see minimum number of steps = N/k or N/k+1 and maximum number of steps =(n+k-1).
We have to optimize the total number of steps and which depend on past history of choices we made which refers to dynamic solution.
For dynamic theory tutorial see http://www.quora.com/Dynamic-Programming/How-do-I-get-better-at-DP-Are-there-some-good-resources-or-tutorials-on-it-like-the-TopCoder-tutorial-on-DP/answer/Michal-Danil%C3%A1k
Can be solved in O(n) as follows:
Trace each element a[i]. If a[i] wasn't traced before then map the number and its index and increase counter.If the number was traced previously then check whether its (last index-curr_index)>=K if yes update the index and increase count. Print count.
Map STL will be beneficial.