List value reduction algorithm - algorithm

Forgive me, but I am very confused and I cannot find any sources that are pointing my in the right direction.
Given list of n elements:
[3, 6, 5, 1]
Reduce the values to be no larger than the size of the list while keeping prioritization values relative to one another (In their original order).
Constraints:
Order must be maintained
Elements are >= 0
Distinct values
I am trying to stay away from sorting and creating a new list, but modifying the list in-place.
What my expected outcome should be:
[1, 3, 2, 0]
Is there an algorithm that exists for this problem?

You could do this in O(n^2).
Just go through the list n times, setting the minimum element(while >= i) to i each time, where i starts at 0 and increments to n-1
I suspect you're looking for something better than that, but I'm not sure how much better you can do in-place.
Example:
Input: 3 6 5 1
3 6 5 0*
1* 6 5 0
1 6 2* 0
1 3* 2 0
Note: this assumes elements are >= 0 and distinct

There may be one, but you don't need it if you think about the steps needed to take to solve this problem.
First, you know that each value in the array cannot be greater than 4, since that is the size in this particular example.
You need to go through each number in the array and with a if condition check to see if the number is greater; if it is then you'll need to decrement it until it is meets the correct condition (in this case, that it is less than 4).
Perform these steps for each index of the array. As far as order, don't swap any indices, since you must retain the original order. Hope that helps!

Related

Calculate the number of distinct possible values of the array after the repeated process of absolute difference between any 2 elements

This was a question asked in a mock test. So, I could not find any online evaluator for this.
Basically, you are provided with an array of elements. You can take any 2 elements and add their absolute difference back to the array.
The solution should be the number of distinct values in the array after infinite number of above given step.
Example 1-
Input [2,3,4,5]
Output - 5
Explanation: Since 3-2=1, this can be added to the set. So the total number of distinct values will be 5.
Example 2-
Input [1,100]
Output - 100
Explanation - 100-1 = 99 -> add this back to the set
Then, 99-1 = 98 -> add this back to the set.
After repeating the process, all the numbers from 1 to 100 will be present in the set.
I used a hash set to store the distinct elements to store the initial array elements and used 2 for loops to subtract the store the distinct result to the same array-
But only after submitting my code, i realized, the distinct result should be again used for further subtraction.
Hence my answer was wrong.
Can anyone help me solve this ? Thanks in advance.
Edit : correcting the solution of first example to 5 instead of 6.
Adding explanation for maximum(array)/gcd(array) as pointed out in the comments.
gcd(array) - the greatest common divisor for all the numbers in the array is calculated i.e. the largest number that divides all the values in the array. It is known that division is nothing but repeated subtractions. So, no matter how many times we were to find absolute difference of the numbers in the array, GCD of the numbers is the maximum we can reduce the difference to. For an instance, let's say the array is [2, 10], the array can only be become [2, 4, 6, 8, 10]. Other numbers in this range will never get added, that is, an absolute difference of 1 never occurs.
maximum(array) - we are finding difference here, so at any point, the difference cannot exceed the maximum value.
Therefore, maximum(array)/gcd(array) formula gives the right output for the question.
Hope this helps!

Understanding the difference between these two scaling properties

I need help understanding the following paragraph from a book on algorithms -
Search spaces for natural combinatorial problems tend to grow
exponentially in the size N of the input; if the input size increases
by one, the number of possibilities increases multiplicatively. We’d
like a good algorithm for such a problem to have a better scaling
property: when the input size increases by a constant factor—say, a
factor of 2—the algorithm should only slow down by some constant
factor C.
I don't really get why one is better than the other. If anyone can formulate any examples to aid my understanding, its greatly appreciated.
Let's consider the following problem: you're given a list of numbers, and you want to find the longest subsequence of that list where the numbers are in ascending order. For example, given the sequence
2 7 1 8 3 9 4 5 0 6
you could form the subsequence [2, 7, 8, 9] as follows:
2 7 1 8 3 9 4 5 0 6
^ ^ ^ ^
but there's an even longer one, [1, 3, 4, 5, 6] available here:
2 7 1 8 3 9 4 5 0 6
^ ^ ^ ^ ^
That one happens to be the longest subsequence that's in increasing order, I believe, though please let me know if I'm mistaken.
Now that we have this problem, how would we go about solving it in the general case where you have a list of n numbers? Let's start with a not so great option. One possibility would be to list off all the subsequences of the original list of numbers, then filter out everything that isn't in increasing order, and then to take the longest one out of all the ones we find. For example, given this short list:
2 7 1 8
we'd form all the possible subsequences, which are shown here:
[]
[8]
[1]
[1, 8]
[7]
[7, 8]
[7, 1]
[7, 1, 8]
[2]
[2, 8]
[2, 1]
[2, 1, 8]
[2, 7]
[2, 7, 8]
[2, 7, 1]
[2, 7, 1, 8]
Yikes, that list is pretty long. But by looking at it, we can see that the longest increasing subsequences have length two, and that there are plenty of choices for which one we could pick.
Now, how well is this going to scale as our input list gets longer and longer? Here's something to think about - how many subsequences are there of this new list, which I made by adding 3 to the end of the existing list?
2 7 1 8 3
Well, every existing subsequence is still a perfectly valid subsequence here. But on top of that, we can form a bunch of new subsequences. In fact, we could take any existing subsequence and then tack a 3 onto the end of it. That means that if we had S subsequences for our length-four list, we'll have 2S subsequences for our length-five list.
More generally, you can see that if you take a list and add one more element onto the end of it, you'll double the number of subsequences available. That's a mathematical fact, and it's neither good nor bad by itself, but if we're in the business of listing all those subsequences and checking each one of them to see whether it has some property, we're going to be in trouble because that means there's going to be a ton of subsequences. We already see that there are 16 subsequences of a four-element list. That means there's 32 subsequences of a five-element list, 64 subsequences of a six-element list, and, more generally, 2n subsequences of an n-element list.
With that insight, let's make a quick calculation. How many subsequences are we going to have to check if we have, say, a 300-element list? We'd have to potentially check 2300 of them - a number that's bigger than the number of atoms in the observable universe! Oops. That's going to take way more time than we have.
On the other hand, there's a beautiful algorithm called patience sorting that will always find the longest increasing subsequence, and which does so quite easily. You can do this by playing a little game. You'll place each of the items in the list into one of many piles. To determine what pile to pick, look for the first pile whose top number is bigger than the number in question and place it on top. If you can't find a pile this way, put the number into its own pile on the far right.
For example, given this original list:
2 7 1 8 3 9 4 5 0 6
after playing the game we'd end up with these piles:
0
1 3 4 5
2 7 8 9 6
And here's an amazing fact: the number of piles used equals the length of the longest increasing subsequence. Moreover, you can find that subsequence in the following way: every time you place a number on top of a pile, make a note of the number that was on top of the pile to its left. If we do this with the above numbers, here's what we'll find; the parenthesized number tells us what was on top of the stack to the left at the time we put the number down:
0
1 3 (1) 4 (3) 5 (4)
2 7 (2) 8 (7) 9 (8) 6 (5)
To find the subsequence we want, start with the top of the leftmost pile. Write that number down, then find the number in parentheses and repeat this process. Doing that here gives us 6, 5, 4, 3, 1, which, if reversed, is 1, 3, 4, 5, 6, the longest increasing subsequence! (Wow!) You can prove that this works in all cases, and it's a really beautiful exercise to actually go and do this.
So now the question is how fast this process is. Placing the first number down takes one unit of work - just place it in its own pile. Placing the second number down takes at most two units of work - we have to look at the top of the first pile, and optionally put the number into a second pile. Placing the third number takes at most three units of work - we have to look at up to two piles, and possibly place the number into its own third pile. More generally, placing the kth number down takes k units of work. Overall, this means that the work we're doing is roughly
1 + 2 + 3 + ... + n
if we have n total elements. That's a famous sum called Gauss's sum, and it simplifies to approximately n2 / 2. So we can say that we'll need to do roughly n2 / 2 units of work to solve things this way.
How does that compare to our 2n solution from before? Well, unlike 2n, which grows stupidly fast as a function of n, n2 / 2 is actually a pretty nice function. If we plug in n = 300, which previously in 2n land gave back "the number of atoms in the universe," we get back a more modest 45,000. If that's a number of nanoseconds, that's nothing; that'll take a computer under a second to do. In fact, you have to plug in a pretty big value of n before you're looking at something that's going to take the computer quite a while to complete.
The function n2 / 2 has an interesting property compared with 2n. With 2n, if you increase n by one, as we saw earlier, 2n will double. On the other hand, if you take n2 / 2 and increase n by one, then n2 / 2 will get bigger, but not by much (specifically, by n + 1/2).
By contrast, if you take 2n and then double n, then 2n squares in size - yikes! But if you take n2 / 2 and double n, then n2 / 2 goes up only by a factor of four - not that bad, actually, given that we doubled our input size!
This gets at the heart of what the quote you mentioned is talking about. Algorithms with runtimes like 2n, n!, etc. scale terribly as a function of n, since increasing n by one causes a huge jump in the runtime. On the other hand, functions like n, n log n, n2, etc. have the property that if you double n, the runtime only goes up by some constant term. They therefore scale much more nicely as a function of input.

How to display all ways to give change

As far as I know, counting every way to give change to a set sum and a starting till configuration is a classic Dynamic Programming problem.
I was wondering if there was a way to also display (or store) the actual change structures that could possibly amount to the given sum while preserving the DP complexity.
I have never saw this issue being discussed and I would like some pointers or a brief explanation of how this can be done or why this cannot be done.
DP for change problem has time complexity O(Sum * ValuesCount) and storage complexity O(Sum).
You can prepare extra data for this problem in the same time as DP for change, but you need more storage O(O(Sum*ValuesCount), and a lot of time for output of all variants O(ChangeWaysCount).
To prepare data for way recovery, make the second array B of arrays (or lists). When you incrementing count array A element from some previous element, add used value to corresponding element of B. At the end, unwind all the ways from the last element.
Example: values 1,2,3, sum 4
index 0 1 2 3 4
A 0 1 2 3 4
B - 1 1 2 1 2 3 1 2 3
We start unwinding from B[4] elements:
1-1-1-1 (B[4]-B[3]-B[2]-B[1])
2-1-1 (B[4]-B[2]-B[1])
2-2 (B[4]-B[2])
3-1 (B[4]-B[1])
Note that I have used only ways with non-increasing values to avoid permutation variants (i.e. 1-3 and 3-1)

Sorting an array in minimum cost

I have an array A[] with 4 element A={
8 1 2 4 }. How to sort it with minimized cost. Criteria is defined as follows-
a. It is possible to swap any 2 element.
b. The cost of any swap is sum of the element value , Like if i swap 8 and 4 the cost is 12 an resultant array is look like A={4 1 2 8}, which is still unsorted so more swap needed.
c. Need to find a way to sort the array with minimum cost.
From my observation greedy will not work, like in each step place any element to its sorted position in array with minimum cost. So a DP solution needed.
Can any one help??
Swap 2 and 1, and then 1 and 4, and then 1 and 8? Or is it a general question?
For a more general approach you could try:
Swapping every pair of 2 elements (with the highest sum) if they are perfect swaps (i.e. swapping them will put them both at their right spot). Th
Use the lowest element as a pivot for swaps (by swapping the element whose spot it occupies), until it reaches its final spot
Then, you have two possibilities:
Repeat step 2: use the lowest element not in its final spot as a pivot until it reaches its final spot, then go back to step 3
Or swap the lowest element not in its final spot (l2) with the lowest element (l1), repeat step 2 until l1 reaches the final spot of l2. Then:
Either swap l1 and l2 again, go to step 3.1
Or go to step 3.2 again, with the next lowest element not in its final spot being used.
When all this is done, if some opposite swaps are performed one next to another (for example it could happen from going to step 2. to step 3.2.), remove them.
There are still some things to watch out for, but this is already a pretty good approximation. Step one and two should always work though, step three would be the one to improve in some borderline cases.
Example of the algorithm being used:
With {8 4 5 3 2 7}: (target array {2 3 4 5 7 8})
Step 2: 2 <> 7, 2 <> 8
Array is now {2, 4, 5, 3, 7, 8}
Choice between 3.1 and 3.2:
3.1 gives 3 <> 5, 3 <> 4
3.2 gives 2 <> 3, 2 <> 5, 2 <> 4, 2 <> 3
3 <> 5, 3 <> 4 is the better result
Conclusion: 2 <> 7, 2 <> 8, 3 <> 5, 3 <> 4 is the best answer.
With {1 8 9 7 6} (resulting array {1 6 7 8 9})
You're beginning at step three already
Choice between 3.1 and 3.2:
3.1 gives 6 <> 9, 6 <> 7, 6 <> 8 (total: 42)
3.2 gives 1 <> 6, 1 <> 9, 1 <> 7, 1 <> 8, 1 <> 6 (total: 41)
So 1 <> 6, 1 <> 9, 1 <> 7, 1 <> 8, 1 <> 6 is the best result
This smells like homework. What you need to do is sort the array but doing so while minimizing cost of swaps. So, it's a optimization problem rather than a sorting problem.
A greedy algorithm would despite this work, all you do is that you fix the solution by swapping the cheapest first (figuring out where in the list it belongs). This is however, not necessarily optimal.
As long as you never swap the same element twice a greedy algorithm should be optimal though.
Anyway, back to the dynamic programming stuff, just build your solution tree using recursion and then prune the tree as you find a more optimal solutions. This is pretty basic recursion.
If you a more complicated sorting algorithm you'll have a lot more difficulty puzzling that together with the dynamic programming so I suggest you start out with a simple, slow O(n^2) sort. And build on top of this.
Rather than to provide you with a solution, I'd like to explain how dynamic programming works in my own words.
The first thing you need to do, is to figure out an algorithm that will explore all possible solutions (this can be a really stupid brute force algorithm).
You then implement this using recursion because dynamic programming is based around being able to figure out overlapping sub problems quickly, ergo recursion.
At each recursive call you look up where you are in your solution and check where you've computed this part of the solution tree before, if you have done this, you can test whether the current solution is more optimal, if it is then you continue, otherwise you're done with this branch of the problem.
When you arrive at the final solution you will have solved the problem.
Think of each recursive call as a snapshot of a partial solution. It's your job to figure how each recursive call fits together in the final optimal solution.
This what I recommend you do:
Write a recursive sort algorithm
Add a parameter to your recursive function that maintains the cost of this execution path, as you sort the array, add to this cost. For every possible swap at any given point do another recursive call (this will branch your solution tree)
Whenever you realize that the cost of the solution you are currently exploring exceeds what you already have somewhere else, abort (just return).
To be able to answer the last question you need to maintain shared memory area in which you can index depending on where you are in you're recursive algorithm. If there's a precomputed cost there you just return that value and don't continue processing (this is the pruning, which makes it fast).
Using this method you can even base your solution on a permutation brute force algorithm, it will probably be very slow or memory intensive because it is stupid when it comes to when you branch or prune but you don't really need a specific sort algorithm to make this work, it will just be more efficient to go about it that way.
Good luck!
If you do a high-low selection sort, you can guarantee that the Nth greatest element isn't swapped more than N times. This a simple algorithm with a pretty easy and enticing guarantee... Maybe check this on a few examples and see how it could be tweaked. Note: this may not lead to an optimal answer...
To find the absolute minimal cost you'll have to try all ways to swap and then find the fastest one.
def recsort(l, sort):
if sorted(l2):
if min>cost:
cost=min
bestsort=sort
if(len(sort) > len(l)*len(l)): //or some other criteria
return
for p1 in (0,len(l)):
for p2 in (0,len(l)):
cost += l[p1] + l[p2]
l2 = swap(l, p1,p2)
if cost<min:
recsort(l2, append sort (p1,p2))
An approach that will be pretty good is to recursively place the biggest value at the top.

Algorithm to allocate a list of numbers to N groups under certain condition

Let's say I have a list of numbers:
2,2,3,4,4
Split the numbers into N groups (3 groups here as an example):
A:2,3 sum:5
B:4 sum:4
C:2,4 sum:6
What I want is to minimize the group with the highest sum (6 here) - the group with the smallest sum (4 here).
Does anyone think of an algorithm to achieve this?
Another example:
7,7,8,8,8,9,9,10
The result should be as follows:
A:7,8,8 sum:23
B:7,8,9 sum:24
C:9,10 sum:19
Unfortunately, this problem is NP hard. See references for multiprocessor scheduling or bin packing. You may also be able to find some useful approximation algorithms, if you're interested in that approach.
Considering that even if N is two the problem is NP complete, I can give you a very bad algorithm.
http://mathworld.wolfram.com/NumberPartitioningProblem.html
Zweiterlinde's suggestion to check out bin packing is the way to go.
I went ahead and posted this, having realized it was wrong after I had typed it all.
You want a greedy approach where the largest numbers are used first.
sort the list to achieve an ordering
Begin placing the largest numbers into groups -- as many as will fit to reach the first number
Stop when max number of groups is reached
Sort your groups by sum and repeat by adding the largest number to the smallest group, repeating until done.
This should get you:
from 2,2,3,4,4 ...
group 1 (4): 4
group 2 (6): 4, 2
group 3 (5): 3, 2
and from 7,7,8,8,8,9,9,10 ...
group 1 (18): 10, 8
group 2 (24): 9, 8, 7
group 3 (24): 9, 8, 7
Though I guess the second example could be done as 19, 24, 23 which makes this wrong. Hmph.

Resources