Number of increasing subsequences in sequence of [0-9] elements - algorithm

In the case a sequence of unknown range value elements, the question Number of all increasing subsequences in given sequence give us a solution in O(n^2).
I've heard of a solution in O(9*n) in the case of a sequence composed of elements in the interval [0,9] only. If you know this algorithm please let me know about that.

Here is an algorithm:
1)Let's call dp[i] = the number of increasing subsequences which have a last element i(0 <= i <= 9). Initially it is filled with zeros.
2)Now we can iterate over the sequence and compute dp in the following way:
Let's assume that the current element is d(0 <= d <= 9). Then dp can be updated like this:
for prev = 0...d - 1
dp[d] += dp[prev] //continue one of the previous sequences.
dp[d] += 1 //start a new sequence that consists of only one element.
3)After iterating over all the elements of the sequence, the answer is just the sum of dp[i] for 0 <= i <= 9.
Note that this algorithm has desired complexity only under assumption that arithmetic operations have O(1) time complexity(that might not be the case because the number of increasing subsequences can be very large).

Altering the algorithm linked to in the question, I believe this shall also fulfill the complexity requirement:
input[i] = input array
n = size of input
dp[i] = number of increasing subsequences with i as the last element (same size as input)
initialize dp[i] = 0 for all 0 <= i < n
//Every possible input can be appended on to one previously found
// increasing subsequence
for (j = 0; j <= 9; j++) {
//Running total of increasing subsequences that occur earlier in the input using
// smaller numbers than j
int smallerSum = 0;
for (i = 0; i < n; i++) {
//This spot in dp was tallied already, need to add it to the running total
if (input[i] < j) {
smallerSum += dp[i]
//Add 1 to the running total, this should be the final answer for this spot in dp
} else if (input[i] == j) {
dp[i] = smallerSum + 1;
}
}
}
return the sum of all elements of dp
Normally a nested for-loop is a dead giveaway of O(n^2) but in this case we're looping over a constant, making it O(n).
In the general case this algorithm would be O(n*k), where n is the size of the input array and k is the number of possible input values.

Related

Minimum Swaps required to bring all the number greater than or equal to K together

Given an array of N numbers and a number K. Find the minimum number of swaps required to bring all the numbers greater than or equal to K together.
Input Format:
First line contains an integer N, denoting the number of elements in the array
Second line contains N space-separated integers, denoting the elements of an array.
Sample Input: Sample Output:
5 3 1
5 2 1 3 4
Answer is already correct but I would like to provide the logic for why that program works:
Underline principle: minimum swaps will be required in the smallest subarray where maximum number of elements greater than or equal to k are present.
What should be the size of smallest subarray? that should be the total no of elements greater than or equal to k. It makes sense because suppose all the elements greater than or equal to k are together, your subarray size cannot be smaller than this.
Within the given array whichever subarray has minimum no of elements violating the condition is our subarray and the no of elements violating the condition is the answer because these violations needs to be swapped with correct ones
You can do this as follows:
Count the number of values >= K, call it C
Count how many values are < K in the first C elements of the array: this represents the number of values to be swapped if we aim to group all values >= K at the far left of the array
Drop the left most value from that window and add the next one at the right of it, keeping the window size at C. Adjust the number of swaps accordingly.
Keep moving the window to the right and keep track what was the minimum number of swaps in any of these configurations.
Here is an interactive implementation in JavaScript:
function solve(a, k) {
let count, i, swaps, leastSwaps;
// 1. Count number of elements >= k:
count = 0;
for (i = 0; i < a.length; i++) {
if (a[i] >= k) count++;
}
// 2. Count number of elements < k in first "window":
// These would need to be swapped.
swaps = 0;
for (i = 0; i < count; i++) {
if (a[i] < k) swaps++;
}
leastSwaps = swaps;
// 3. Slide window to the right minimising number of swaps
for (i = 0; i < a.length - count; i++) {
if (a[i] < k) swaps--;
if (a[i+count] < k) swaps++;
if (swaps < leastSwaps) leastSwaps = swaps;
}
return leastSwaps;
}
// I/O management
function process() {
const a = arrayInput.value.match(/\d+/g).map(Number),
k = +pivotInput.value;
result.textContent = solve(a, k);
}
arrayInput.oninput = pivotInput.oninput = process;
// Launch on page load
process();
<table>
<tr><td>Numbers:</td><td><input id="arrayInput" size="40" value="5 2 1 3 4" ></td></tr>
<tr><td>K:</td><td><input id="pivotInput" size="4" value="3"></td></tr>
<tr><td>Swaps:</td><td><span id="result">?</span></td></tr>
</table>
Find count of all elements which are less than or equals to ‘k’. Let’s say the count is ‘cnt’
Using two pointer technique for window of length ‘cnt’, each time keep track of how many elements in this range are greater than ‘k’. Let’s say the total count is ‘var1’.
Repeat step 2, for every window of length ‘cnt’ and take minimum of count ‘var1’ among them. This will be the final answer.

Time Complexity Analysis : better explaination?

I came across the following code to find triplets that satisfy Triangle sum property.
// Function to count all possible triangles with arr[]
// elements
static int findNumberOfTriangles(int arr[])
{
int n = arr.length;
// Sort the array elements in non-decreasing order
Arrays.sort(arr);
// Initialize count of triangles
int count = 0;
// Fix the first element. We need to run till n-3 as
// the other two elements are selected from arr[i+1...n-1]
for (int i = 0; i < n-2; ++i)
{
// Initialize index of the rightmost third element
int k = i + 2;
// Fix the second element
for (int j = i+1; j < n; ++j)
{
/* Find the rightmost element which is smaller
than the sum of two fixed elements
The important thing to note here is, we use
the previous value of k. If value of arr[i] +
arr[j-1] was greater than arr[k], then arr[i] +
arr[j] must be greater than k, because the
array is sorted. */
while (k < n && arr[i] + arr[j] > arr[k])
++k;
/* Total number of possible triangles that can be
formed with the two fixed elements is k - j - 1.
The two fixed elements are arr[i] and arr[j]. All
elements between arr[j+1] to arr[k-1] can form a
triangle with arr[i] and arr[j]. One is subtracted
from k because k is incremented one extra in above
while loop. k will always be greater than j. If j
becomes equal to k, then above loop will increment
k, because arr[k] + arr[i] is always/ greater than
arr[k] */
count += k - j - 1;
}
}
return count;
}
Can someone give a better explanation as to why the time complexity of this solution is O(n^2) and not O(n^3) ? My understanding is that for every i and j, k varies too.
The time complexity of the above solution is O(n^2) as you can see the value of k is initialised before the second for loop. In the second for
loop the value of k is increasing in while condition. Once the while condition terminates, for loop will run for the next value of j and the
value of k remains the same as it was terminated in the while loop before.
Once the value of k becomes equal to n then it will not run for any value of j after that.
So the second for loop is running only from k=i+2 to n. Hence the complexity is O(n^2).
The only statement that could get executed more than O(n^2) times is the most nested ++k statement.
But k never exceeds n, and is reset (to a non-negative number) n-2 times. That proves that the ++k statement is executed at most n(n-2) = O(n^2) times.

Insertion sort comparison?

How to count number of comparisons in insertion sort in less than O(n^2) ?
When we're inserting an element, we alternate comparisons and swaps until either (1) the element compares not less than the element to its right (2) we hit the beginning of the array. In case (1), there is one comparison not paired with a swap. In case (2), every comparison is paired with a swap. The upward adjustment for number of comparisons can be computed by counting the number of successive minima from left to right (or however your insertion sort works), in time O(n).
num_comparisons = num_swaps
min_so_far = array[0]
for i in range(1, len(array)):
if array[i] < min_so_far:
min_so_far = array[i]
else:
num_comparisons += 1
As commented, to do it in less than O(n^2) is hard, maybe impossible if you must pay the price for sorting. If you already know the number of comparisons done at each external iteration then it would be possible in O(n), but the price for sorting was payed sometime before.
Here is a way for counting the comparisons inside the method (in pseudo C++):
void insertion_sort(int p[], const size_t n, size_t & count)
{
for (long i = 1, j; i < n; ++i)
{
auto tmp = p[i];
for (j = i - 1; j >= 0 and p[j] > tmp; --j) // insert a gap where put tmp
p[j + 1] = p[j];
count += i - j; // i - j is the number of comparisons done in this iteration
p[j + 1] = tmp;
}
}
n is the number of elements and count the comparisons counter which must receive a variable set to zero.
If I remember correctly, this is how insertion sort works:
A = unsorted input array
B := []; //sorted output array
while(A is not empty) {
remove first element from A and add it to B, preserving B's sorting
}
If the insertion to B is implemented by linear search from the left until you find a greater element, then the number of comparisons is the number of pairs (i,j) such that i < j and A[i] >= A[j] (I'm considering the stable variant).
In other words, for each element x, count the number of elements before x that have less or equal value. That can be done by scanning A from the left, adding it's element to some balanced binary search tree, that also remembers the number of elements under each node. In such tree, you can find number of elements lesser or equal to a certain value in O(log n). Total time: O(n log n).

Sample an index of a maximal number in an array, with a probability of 1/(number of maximal numbers)

This is one of the recent interview question that I faced. Program to return the index of the maximum number in the array [ To Note : the array may or may not contain multiple copies of maximum number ] such that each index ( which contains the maximum numbers ) have the probability of 1/no of max numbers to be returned.
Examples:
[-1 3 2 3 3], each of positions [1,3,4] have the probability 1/3 to be returned (the three 3s)
[ 2 4 6 6 3 1 6 6 ], each of [2,3,6,7] have the probability of 1/4 to be returned (corresponding to the position of the 6s).
First, I gave O(n) time and O(n) space algorithm where I collect the set of max-indexes and then return a random number from the set. But he asked for a O(n) time and O(1) complexity program and then I came up with this.
int find_maxIndex(vector<int> a)
{
max = a[0];
max_index = 0;
count = 0;
for(i = 1 to a.size())
{
if(max < a[i])
{
max = a[i];
count = 0;
}
if(max == a[i])
{
count++;
if(rand < 1/count) //rand = a random number in the range of [0,1]
max_index = i;
}
}
return max_index;
}
I gave him this solution. But my doubt is if this procedure would select one of the indexes of max numbers with equal probability. Hope I am clear.Is there any other method to do this ?
What you have is Reservoir sampling! There is another easy to understand solution, but requires two passes.
int find_maxIndex(vector<int> a){
int count = 1;
int maxElement = a[0];
for(int i = 1; i < a.size(); i++){
if(a[i] == maxElement){
count ++;
} else if(a[i] > maxElement){
count = 1;
maxElement = a[i];
}
}
int occurrence = rand() % count + 1;
int occur = 0;
for(int i = 0; i < a.size(); i++){
if(a[i] == maxElement){
occur++;
if(occur == occurrence) return i;
}
}
}
The algorithm is pretty simple, first find the number of times the max element occurs in the first pass. And choose a random occurrence and return the index of that occurrence. It takes two passes though, but very easy to understand.
Your algorithm works fine, and you can prove it via induction.
That is, assuming it works for any array of size N, prove it works for any array of size N+1.
So, given an array of size N+1, think of it as a sub-array of size N followed a new element at the end. By assumption, your algorithm uniformly selects one of the max elements of the sub-array... And then it behaves as follows:
If the new element is larger than the max of the sub-array, return that element. This is obviously correct.
If the new element is less than the max of the sub-array, return the result of the algorithm on the sub-array. Also obviously correct.
The only slightly tricky part is when the new element equals the max element of the sub-array. In this case, let the number of max elements in the sub-array be k. Then, by hypothesis, your algorithm selected one of them with probability 1/k. By keeping that same element with probability k/(k+1), you make the overall probability of selecting that same element equal 1/k * k /(k+1) == 1/(k+1), as desired. You also select the last element with the same probability, so we are done.
To complete the inductive proof, just verify the algorithm works on an array of size 1. Also, for quality of implementation purposes, fix it not to crash on arrays of size zero :-)
[Update]
Incidentally, this algorithm and its proof are closely related to the Fisher-Yates shuffle (which I always thought was "Knuth's card-shuffling algorithm", but Wikipedia says I am behind the times).
The idea is sound, but the devil is in the details.
First off, what language are you using? It might make a difference. The rand() from C and C++ will return an integer, which isn't likely to be less than 1/count unless it returns 0. Even then, if 1/count is an integer division, that result is always going to be 0.
Also your count is off by 1. It starts as 1 when you get a new max, but you immediately increment it in the next if statement.

Calculate majority element in an array

Last week I appeared in an interview. I was given the following question:
Given an array of 2n elements, and out of this n elements are same, and the remaining are all different. Find the element that repeats n times.
There is no restriction on the range of the elements.
Can someone please give me an efficient algorithm to solve this?
"Array of 2n elements is given, and out of this n elements are same, and remaining are all different. Find the element that repeats n time."
This can be done in O(n) with the following algorithm:
1) Iterate over the array, checking to see if any elements [i] and [i+1] are the same.
2) Iterate over the array, checking to see if any elements [i] and [i+2] are the same.
3) If n = 2 (and thus length = 4), check if 0 and 3 are the same.
Explanation:
Call the matching elements m and the non-matching elements r.
For n = 2, we can construct mmrr, mrmr and mrrm - so we must check for gap size 0, 1 and the only place we can have gap size 2.
For n > 2, we cannot construct the array with no gaps of size 0 or 1. For example for n = 3, you have to start like this: mrrmr... but then you must place an m. Similarly for n = 4, mrrmrrmm - having no gaps of size 0 or 1 would require ms to be outnumbered by rs by more and more as n increases. Proving this is easy.
You just need to find two elements that are the same.
One idea would be:
Get one element from the 2n elements.
If it is not in the a Set, put it in.
Repeat until you find one that is in that set.
Well if complexity doesn't matter, one naive way would be to use two loops, which is for the worst case O(n^2).
for(int i = 0; i < array.size(); i++){
for(int j = i + 1; j < array.size(); j++){
if(array[i] == array[j]){
// element found
}
}
If the first four elements are all distinct then the array must contain a consecutive pair of the target element...
int find(int A[n])
{
// check first four elements (10 iterations = O(1))
for (int i = 0; i < 4; i++)
for (int j = i+1; j < 4; j++)
if (A[i] == A[j])
return A[i];
// find the consecutive pair (n-4 iterations = O(n))
for (int i = 3; i < n-1; i++)
if (A[i] == A[i+1])
return A[i];
// unreachable if input matches preconditions
throw invald_input;
}
This is optimally O(n) time with a single pass and O(1) space.
If you find one element twice, that is the element as the questions says : Array of 2n elements is given, and out of this n elements are same, and remaining are all different. Find the element that repeats n time.
You have array of 2n element and half are same and remaining are different so , consider following case,
ARRAY[2n] = {N,10,N,878,85778,N......};
or
Array[2n] = {10,N,10,N,44,N......};
And so on now simple case in for loop like,
if(ARRAY[i] == ARRAY[i+1])
{
//Your similar element :)
}
I think that the problem should be "find the element that appears at least n+1 times", if it appears only n times they can be two.
Assuming that there is such an element in the input the following algorithm can be used.
input array of 2*n elements;
int candidate = input[0];
int count = 1;
for (int i = 1; i < 2*n; ++i) {
if (input[i] == candidate) {
count++;
} else {
count --;
if (count == 0) candidate = input[i];
}
}
return candidate;
if the request is to find if there is an element present n+1 times another traversal is required to find if the element found at previous step appears n + 1 times.
Edit:
It has been suggested that the n elements with the same value are contiguous.
If this is the case just use the above algorithm and stop when count reaches n.

Resources