How to return an empty array Java - arrays

Hi, how are you? =)
I'm new to Java, currently, I'm learning arrays and loops, and I'm really struggling with them at the moment.
Here is my homework:
Write a public method int[] findMinMaxPrices(int[] price).
It takes an array of prices and returns a new array.
Empty, if the array is empty.
Returns only one element, if the maximum and minimum prices in the prices array are the same.
Returns only two elements if the price array contains both the minimum and maximum prices. The minimum price should go first, then the maximum.
Only for loop can be used.
I would use some help here:
How to return an empty array in this case?
I made it many times in draft, unfortunately, it doesn't work here.
How can I use a for loop here?
Can you give me some hints or advice?
Thank you in advance!)
import java.util.Arrays;
public class QuadraticEquationSolver {
public int[] findMinMaxPrices(int[] prices) { // I know it's a mess, but I'm just learning =)
Arrays.sort(prices);
int empty [] = {};
int first [] = Arrays.copyOf(prices, 1);
int a = prices[0];
int b = prices[prices.length-1];
int second [] = new int[] {a,b};
if(prices[0] == prices[prices.length-1]) {
return first;
}
else if(prices[0] < prices[prices.length-1]) {
return second;
}else{
return empty;
//return new int[0]; I tried to use this here, didn't work =(
}
}
public static void main(String[] args) {
QuadraticEquationSolver shop = new QuadraticEquationSolver();
//Should be [50, 1500]
int[] prices = new int[] {100, 1500, 300, 50};
int[] minMax = shop.findMinMaxPrices(prices);
System.out.println(Arrays.toString(minMax));
//findMaxPrices(new int[] {10, 50, 3, 1550}), returns [3, 1550]
//findMaxPrices(new int[] {}), returns []
//findMaxPrices(new int[] {50, 50}), returns [50]
}
}

You return an empty array the same way you create an empty array when you call findMaxPrices(new int[]{}), just use new int[]{}.
For your requirement you don't need to sort the array, because you can store the minimum and maximum value in a local variable and just add minimum before maximum to the array that you return.
One essential thing you are missing is checking for the array length of prices. Using prices.length you get how many values are in the array. Always check the length of an array before you try to access it using an index, otherwise you risk getting an IndexOutOfBounds exception. Using this you can immediately return when prices.length == 0 because then there are no values in the array and you need to return an empty array. If prices.length == 1 we only have one value in the array. This value must be minimum and maximum so we can return an array containing this value. In all other cases we can use a for loop to loop over all elements in the array. If we find a value that is smaller/ greater than the current minimum/ maximum we set that as new maximum. For this to work we need to initialize minimum and maximum to the biggest/ smallest possible value first. Java has the constants Integer.MAX_VALUE and Integer.MIN_VALUE for this kind of thing. Last but not least we need to check if maximum and minimum are the same. In that case we only return one element, otherwise we return both, but minimum before maximum.
public class Application {
public static void main(String[] args) {
System.out.println(Arrays.toString(findMinMaxPrices(new int[]{100, 1500, 300, 50})));
System.out.println(Arrays.toString(findMinMaxPrices(new int[]{})));
System.out.println(Arrays.toString(findMinMaxPrices(new int[]{50, 50})));
}
public static int[] findMinMaxPrices(int[] prices) {
// we can simply check the array length. If it is zero we return an empty array
if(prices.length == 0) return new int[]{};
else if(prices.length == 1) return new int[prices[0]]; // if we only have one element that one element must be the minimum and maximum value
// array length is not zero or one -> we need to find minimum and maximum
int min = Integer.MAX_VALUE; // set to maximal possible int value
int max = Integer.MIN_VALUE; // set to minimal possible int value
for (int i = 0; i < prices.length; i++) {
int currentPrice = prices[i];
if(currentPrice < min) min = currentPrice;
if(currentPrice > max) max = currentPrice;
}
// now we have minimum and a maxium value
// if they are the same only return one value
if(min == max) return new int[]{max};
// otherwise return both, but minumum first
return new int[]{min, max};
}
}
Expected output:
[50, 1500]
[]
[50]

Related

Speed efficiency in rebuilding an array

If I have two arrays of ints e.g. [100, 50, 32, 23] and [40, 30, 32, 125] and a number 50 then the numbers in the first array that is greater than this number should be removed along with its corresponding index pair in the 2nd array.
If i did this manually for every element value and rebuilding the int array each time as I go along over 10,000 elements wouldn't this be incredibly inefficient/slow?
input 50:
new array changes:
[50, 32, 23]
[30, 32, 125]
pseudo code so far:
for each value in array one that is greater than input, remove it and rebuild both arrays, continue
Not sure how I can learn where or what direction I should go in finding a more efficient/faster way of doing this.
Here is an O(n) implementation. It goes through the arrays once to find out how many elements will be retained, creates new arrays too hold the result, then copies the integers that should lower or equal to the limit into the new arrays. I assume the two arrays are held together in an int[][] because that is the most efficient way to pass them around.
public static int[][] removeGreaterThan(int[][] arrays, int limit) {
int retained = 0;
for (int i = 0; i < arrays[0].length; i++) {
if (arrays[0][i] <= limit) retained++;
}
int[][] result = new int[][] {new int[retained], new int[retained]};
int j = 0;
for (int i = 0; i < arrays[0].length; i++) {
if (arrays[0][i] <= limit) {
result[0][j] = arrays[0][i];
result[1][j] = arrays[1][i];
j++;
}
}
return result;
}
Use it like this.
int[][] arrays = new int[][] {{100, 50, 32, 23}, {40, 30, 32, 125}};
int[][] result = removeGreaterThan(arrays, 50);
// you can check to make sure the values are correct
System.out.println(Arrays.asList(result[0]);
System.out.println(Arrays.asList(result[1]);
I would create a SortedMap of your 2 arrays and then extract the pairs with a key smaller than or equal to your input parameter:
Suppose your arrays are like this:
int[] array_1;
int[] array_2;
Convert these arrays into a map:
NavigableMap<Integer, Integer> my_map = new TreeMap();
int index;
for (index = 0; index < array_1.length; index++)
my_map.put(array_1[index], array_2[index]);
Now get all pairs with a key value not greater than the one you specify:
NavigableMap<Integer, Integer> result;
result = my_map.headMap(50, true);
Convert result into new arrays:
array_1 = new int[result.size()];
array_2 = new int[array_1.length];
Iterator<Integer> it = result.keySet().iterator();
index = 0;
Integer key;
while (it.hasNext())
{
key = it.next();
array_1[index] = key;
array_2[index] = result.get(key);
index++;
}
Of course, the final result would be sorted. Not sure if that's a problem.
So, your result would be [23, 32, 50] [125, 32, 30].
Furthermore, it supposes that the keys (the elements in the first array) are unique.
One way to improve on your pseudocode is:
for each iteration
find indexes of first array which are greater than the number.
store indexes in a list.
remove all the elements of the first array using index list. // I can tell you more here but you should give it a try.
remove all the elements of the second array.

How to get middle element of array if we don't know size of array

I was asked question in interview ,write an algorithm to find middle element of array when you don't know size of array.
Is it cheating to count the elements yourself?
Java:
Object [] mysteriousArray = getMysteriousArray();
int count = 0;
for (Object value: mysteriousArray) {
count++;
}
Object middle = mysteriousArray[count/2];
For Java:
int[] array = new int[/*mystery value*/];
The statement array[(int)((array.length-1)/2)] will return the middle value, rounding down.

Two different numbers in an array which their sum equals to a given value

Given an array that we know its size and the range of numbers that can be in it.Find two elements in the array that sum up to a given value.There is a classic version of algorithm which
has O(n) as complexity of time and O(K) as the complexity of space using the hash map (K is the range of the integers).What if we want to find DIFFERENT elements
that sum up to that given number(for identical elements it does not work).Plus,the program just checks if there is at least
one combination and it does not need to find all the possible combinations.
BST should work.
Sort the array into a BST.
While (current node is not root, perform inorder traversal)
For current node, check:
If the sum is greater than the current value
If there is an item in the array that satisfies the sum criteria
Make the next item in inorder traversal the current node
Step 1 is O(nlogn)
Step 2 is O(n/2 logn)
Here is O(n) solution for finding the first pair of indices of array which sums to the expected target. The solution will stop when it finds the first 2 indices that sum to target, if you need all the pairs that add up to target then instead of using int[] result, you can use ArrayList or even a Map, process the complete array and return it with all the pairs of indices. There is an obvious assumption that the Map's hashcode function is really good and there are not much collisions so that map operations perform in O(1) time.
Adding condition that values of both the indices is not same should provide you solution with different numbers in pair.
import java.util.*;
public class Solution {
public static void main(String[] args) {
int[] array = new int[] {1,2,4,7,12,67,12,5,9,1,10};
System.out.println(Arrays.toString(sum(array, 68)));
}
public static int[] sum(int[] array, int target) {
int[] result = new int[2];
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
// n iterations
for (int index = 0; index < array.length; index++) {
// constant
if (map.containsKey(target - array[index])
&& array[index] != array[map.get(target - array[index])]) {
result[1] = index;
// constant
result[0] = map.get(target - array[index]);
return result;
}
// constant
map.put(array[index], index);
}
return result;
}
}
Search and print the given number sum of elements in array with indexes using python
list1 = [1,2,3,5]
tmp = list1.copy()
print(tmp)
inp = int(input("enter value equal to sum"))
for i in list1:
for j in tmp:
add = i+j
if add == inp:
print (list1.index(i)) #printing the index first val
print (tmp.index(j)) #printing the index second val
print ("value found",add,i,j)
break
#if add ==inp: '''if uncomment this when it found the first occurance it breaks'''
# print("out")
# break

Calculate all possibilities to get N using values from a given set [duplicate]

This question already has answers here:
Algorithm to find elements best fitting in a particular amount
(5 answers)
how do you calculate the minimum-coin change for transaction?
(3 answers)
Closed 9 years ago.
So here is the problem:
Given input = [100 80 66 25 4 2 1], I need to find the best combination to give me 50.
Looking at this, the best would be 25+25 = 50, so I need 2 elements from the array.
Other combinations include 25+4+4+4+4+4+4+1 and 25+4+4+4+4+4+2+2+1.. etc etc
I need to find all the possibilities which gives me the sum on a value I want.
EDIT: As well as the best possibility (one with least number of terms)
Here is what I have done thus far:
First build a new array (simple for loop which cycles through all elements and stores in a new temp array), check for all elements higher than my array (so for input 50, the elements 100,80,66 are higher, so discard them and then my new array is [25 4 2 1]). Then, from this, I need to check combinations.
The first thing I do is a simple if statement checking if any array elements EXACTLY match the number I want. So if I want 50, I check if 50 is in the array, if not, I need to find combinations.
My problem is, I'm not entirely sure how to find every single combination. I have been struggling trying to come up with an algorithm for a while but I always just end up getting stumped.
Any help/tips would be much appreciated.
PS - we can assume the array is always sorted in order from LARGEST to SMALLEST value.
This is the kind of problem that dynamic programming is meant to solve.
Create an array with with indices, 1 to 50. Set each entry to -1. For each element that is in your input array, set that element in the array to 0. Then, for each integer n = 2 to 50, find all possible ways to sum to n. The number of sums required is the minimum of the two addends plus 1. At the end, get the element at index 50.
Edit: Due to a misinterpretation of the question, I first answered with an efficient way to calculate the number of possibilities (instead of the possibilities themself) to get N using values from a given set. That solution can be found at the bottom of this post as a reference for other people, but first I'll give a proper answer to your questions.
Generate all possibilities, count them and give the shortest one
When generating a solution, you consider each element from the input array and ask yourself "should I use this in my solution or not?". Since we don't know the answer until after the calculation, we'll just have to try out both using it and not using it, as can be seen in the recursion step in the code below.
Now, to avoid duplicates and misses, we need to be a bit careful with the parameters for the recursive call. If we use the current element, we should also allow it to be used in the next step, because the element may be used as many times as possible. Therefore, the first parameter in this recursive call is i. However, if we decide to not use the element, we should not allow it to be used in the next step, because that would be a duplicate of the current step. Therefore, the first parameter in this recursive call is i+1.
I added an optional bound (from "branch and bound") to the algorithm, that will stop expanding the current partial solution if it is known that this solution will never be shorter then the shortest solution found so far.
package otherproblems;
import java.util.Deque;
import java.util.LinkedList;
public class GeneratePossibilities
{
// Input
private static int n = 50;
// If the input array is sorted ascending, the shortest solution is
// likely to be found somewhere at the end.
// If the input array is sorted descending, the shortest solution is
// likely to be found somewhere in the beginning.
private static int[] input = {100, 80, 66, 25, 4, 2, 1};
// Shortest possibility
private static Deque<Integer> shortest;
// Number of possibilities
private static int numberOfPossibilities;
public static void main(String[] args)
{
calculate(0, n, new LinkedList<Integer>());
System.out.println("\nAbove you can see all " + numberOfPossibilities +
" possible solutions,\nbut this one's the shortest: " + shortest);
}
public static void calculate(int i, int left, Deque<Integer> partialSolution)
{
// If there's nothing left, we reached our target
if (left == 0)
{
System.out.println(partialSolution);
if (shortest == null || partialSolution.size() < shortest.size())
shortest = new LinkedList<Integer>(partialSolution);
numberOfPossibilities++;
return;
}
// If we overshot our target, by definition we didn't reach it
// Note that this could also be checked before making the
// recursive call, but IMHO this gives a cleaner recursion step.
if (left < 0)
return;
// If there are no values remaining, we didn't reach our target
if (i == input.length)
return;
// Uncomment the next two lines if you don't want to keep generating
// possibilities when you know it can never be a better solution then
// the one you have now.
// if (shortest != null && partialSolution.size() >= shortest.size())
// return;
// Pick value i. Note that we are allowed to pick it again,
// so the argument to calculate(...) is i, not i+1.
partialSolution.addLast(input[i]);
calculate(i, left-input[i], partialSolution);
// Don't pick value i. Note that we are not allowed to pick it after
// all, so the argument to calculate(...) is i+1, not i.
partialSolution.removeLast();
calculate(i+1, left, partialSolution);
}
}
Calculate the number of possibilities efficiently
This is a nice example of dynamic programming. What you need to do is figure out how many possibilities there are to form the number x, using value y as the last addition and using only values smaller than or equal to y. This gives you a recursive formula that you can easily translate to a solution using dynamic programming. I'm not quite sure how to write down the mathematics here, but since you weren't interested in them anyway, here's the code to solve your question :)
import java.util.Arrays;
public class Possibilities
{
public static void main(String[] args)
{
// Input
int[] input = {100, 80, 66, 25, 4, 2, 1};
int n = 50;
// Prepare input
Arrays.sort(input);
// Allocate storage space
long[][] m = new long[n+1][input.length];
for (int i = 1; i <= n; i++)
for (int j = 0; j < input.length; j++)
{
// input[j] cannot be the last value used to compose i
if (i < input[j])
m[i][j] = 0;
// If input[j] is the last value used to compose i,
// it must be the only value used in the composition.
else if (i == input[j])
m[i][j] = 1;
// If input[j] is the last value used to compose i,
// we need to know the number of possibilities in which
// i - input[j] can be composed, which is the sum of all
// entries in column m[i-input[j]].
// However, to avoid counting duplicates, we only take
// combinations that are composed of values equal or smaller
// to input[j].
else
for (int k = 0; k <= j; k++)
m[i][j] += m[i-input[j]][k];
}
// Nice output of intermediate values:
int digits = 3;
System.out.printf(" %"+digits+"s", "");
for (int i = 1; i <= n; i++)
System.out.printf(" %"+digits+"d", i);
System.out.println();
for (int j = 0; j < input.length; j++)
{
System.out.printf(" %"+digits+"d", input[j]);
for (int i = 1; i <= n; i++)
System.out.printf(" %"+digits+"d", m[i][j]);
System.out.println();
}
// Answer:
long answer = 0;
for (int i = 0; i < input.length; i++)
answer += m[n][i];
System.out.println("\nThe number of possibilities to form "+n+
" using the numbers "+Arrays.toString(input)+" is "+answer);
}
}
This is the integer knapsack problem, which is one your most common NP-complete problems out there; if you are into algorithm design/study check those out. To find the best I think you have no choice but to compute them all and keep the smallest one.
For the correct solution there is a recursive algorithm that is pretty simple to put together.
import org.apache.commons.lang.ArrayUtils;
import java.util.*;
public class Stuff {
private final int target;
private final int[] steps;
public Stuff(int N, int[] steps) {
this.target = N;
this.steps = Arrays.copyOf(steps, steps.length);
Arrays.sort(this.steps);
ArrayUtils.reverse(this.steps);
this.memoize = new HashMap<Integer, List<Integer>>(N);
}
public List<Integer> solve() {
return solveForN(target);
}
private List<Integer> solveForN(int N) {
if (N == 0) {
return new ArrayList<Integer>();
} else if (N > 0) {
List<Integer> temp, min = null;
for (int i = 0; i < steps.length; i++) {
temp = solveForN(N - steps[i]);
if (temp != null) {
temp.add(steps[i]);
if (min == null || min.size() > temp.size()) {
min = temp;
}
}
}
return min;
} else {
return null;
}
}
}
It is based off the fact that to "get to N" you to have come from N - steps[0], or N - steps1, ...
Thus you start from your target total N and subtract one of the possible steps, and do it again until you are at 0 (return a List to specify that this is a valid path) or below (return null so that you cannot return an invalid path).
The complexity of this correct solution is exponential! Which is REALLY bad! Something like O(k^M) where M is the size of the steps array and k a constant.
To get a solution to this problem in less time than that you will have to use a heuristic (approximation) and you will always have a certain probability to have the wrong answer.
You can make your own implementation faster by memorizing the shortest combination seen so far for all targets (so you do not need to recompute recur(N, _, steps) if you already did). This approach is called Dynamic Programming. I will let you do that on your own (very fun stuff and really not that complicated).
Constraints of this solution : You will only find the solution if you guarantee that the input array (steps) is sorted in descending order and that you go through it in that order.
Here is a link to the general Knapsack problem if you also want to look approximation solutions: http://en.wikipedia.org/wiki/Knapsack_problem
You need to solve each sub-problem and store the solution. For example:
1 can only be 1. 2 can be 2 or 1+1. 4 can be 4 or 2+2 or 2+1+1 or 1+1+1+1. So you take each sub-solution and store it, so when you see 25=4+4+4+4+4+4+1, you already know that each 4 can also be represented as one of the 3 combinations.
Then you have to sort the digits and check to avoid duplicate patterns since, for example, (2+2)+(2+2)+(2+2)+(1+1+1+1)+(1+1+1+1)+(1+1+1+1) == (2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1)+(2+1+1). Six 2's and twelve 1's in both cases.
Does that make sense?
Recursion should be the easiest way to solve this (Assuming you really want to find all the solutions to the problem). The nice thing about this approach is, if you want to just find the shortest solution, you can add a check on the recursion and find just that, saving time and space :)
Assuming an element i of your array is part of the solution, you can solve the subproblem of finding the elements that sums to n-i. If we add an ordering to our solution, for example the numbers in the sum must be from the greater to the smallest, we have a way to find unique solutions.
This is a recursive solution in C#, it should be easy to translate it in java.
public static void RecursiveSum(int n, int index, List<int> lst, List<int> solution)
{
for (int i = index; i < lst.Count; i++)
{
if (n == 0)
{
Console.WriteLine("");
foreach (int j in solution)
{
Console.Write(j + " ");
}
}
if (n - lst[i] >= 0)
{
List<int> tmp = new List<int>(solution);
tmp.Add(lst[i]);
RecursiveSum(n - lst[i], i, lst, tmp);
}
}
}
You call it with
RecursiveSum(N,0,list,new List<int>());
where N is the sum you are looking for, 0 shouldn't be changed, list is your list of allowed numbers, and the last parameter shouldn't be changed either.
The problem you pose is interesting but very complex. I'd approach this by using something like OptaPlanner(formerly Drools Planner). It's difficult to describe a full solution to this problem without spending significant time, but with optaplanner you can also get "closest fit" type answers and can have incremental "moves" that would make solving your problem more efficient. Good luck.
This is a solution in python: Ideone link
# Start of tsum function
def tsum(currentSum,total,input,record,n):
if total == N :
for i in range(0,n):
if record[i]:
print input[i]
i = i+1
for i in range(i,n):
if record[i]:
print input[i]
print ""
return
i=currentSum
for i in range(i,n):
if total+input[i]>sum :
continue
if i>0 and input[i]==input[i-1] and not record[i-1] :
continue
record[i]=1
tsum(i+1,total+input[i],input,record,l)
record[i]=0
# end of function
# Below portion will be main() in Java
record = []
N = 5
input = [3, 2, 2, 1, 1]
temp = list(set(input))
newlist = input
for i in range(0, len(list(set(input)))):
val = N/temp[i]
for j in range(0, val-input.count(temp[i])):
newlist.append(temp[i])
# above logic was to create a newlist/input i.e [3, 2, 2, 1, 1, 1, 1, 1]
# This new list contains the maximum number of elements <= N
# for e.g appended three 1's as sum of new three 1's + existing two 1's <= N(5) where as
# did not append another 2 as 2+2+2 > N(5) or 3 as 3+3 > N(5)
l = len(input)
for i in range(0,l):
record.append(0)
print "all possibilities to get N using values from a given set:"
tsum(0,0,input,record,l)
OUTPUT: for set [3, 2, 2, 1, 1] taking small set and small N for demo purpose. But works well for higher N value as well.
For N = 5
all possibilities to get N using values from a given set:
3
2
3
1
1
2
2
1
2
1
1
1
1
1
1
1
1
For N = 3
all possibilities to get N using values from a given set:
3
2
1
1
1
1
Isn't this just a search problem? If so, just search breadth-first.
abstract class Numbers {
abstract int total();
public static Numbers breadthFirst(int[] numbers, int total) {
List<Numbers> stack = new LinkedList<Numbers>();
if (total == 0) { return new Empty(); }
stack.add(new Empty());
while (!stack.isEmpty()) {
Numbers nums = stack.remove(0);
for (int i : numbers) {
if (i > 0 && total - nums.total() >= i) {
Numbers more = new SomeNumbers(i, nums);
if (more.total() == total) { return more; }
stack.add(more);
}
}
}
return null; // No answer.
}
}
class Empty extends Numbers {
int total() { return 0; }
public String toString() { return "empty"; }
}
class SomeNumbers extends Numbers {
final int total;
final Numbers prev;
SomeNumbers(int n, Numbers prev) {
this.total = n + prev.total();
this.prev = prev;
}
int total() { return total; }
public String toString() {
if (prev.getClass() == Empty.class) { return "" + total; }
return prev + "," + (total - prev.total());
}
}
What about using the greedy algorithm n times (n is the number of elements in your array), each time popping the largest element off the list. E.g. (in some random pseudo-code language):
array = [70 30 25 4 2 1]
value = 50
sort(array, descending)
solutions = [] // array of arrays
while length of array is non-zero:
tmpValue = value
thisSolution = []
for each i in array:
while tmpValue >= i:
tmpValue -= i
thisSolution.append(i)
solutions.append(thisSolution)
array.pop_first() // remove the largest entry from the array
If run with the set [70 30 25 4 2 1] and 50, it should give you a solutions array like this:
[[30 4 4 4 4 4]
[30 4 4 4 4 4]
[25 25]
[4 4 4 4 4 4 4 4 4 4 4 4 2]
[2 ... ]
[1 ... ]]
Then simply pick the element from the solutions array with the smallest length.
Update: The comment is correct that this does not generate the correct answer in all cases. The reason is that greedy isn't always right. The following recursive algorithm should always work:
array = [70, 30, 25, 4, 3, 1]
def findSmallest(value, array):
minSolution = []
tmpArray = list(array)
while len(tmpArray):
elem = tmpArray.pop(0)
tmpValue = value
cnt = 0
while tmpValue >= elem:
cnt += 1
tmpValue -= elem
subSolution = findSmallest(tmpValue, tmpArray)
if tmpValue == 0 or subSolution:
if not minSolution or len(subSolution) + cnt < len(minSolution):
minSolution = subSolution + [elem] * cnt
return minSolution
print findSmallest(10, array)
print findSmallest(50, array)
print findSmallest(49, array)
print findSmallest(55, array)
Prints:
[3, 3, 4]
[25, 25]
[3, 4, 4, 4, 4, 30]
[30, 25]
The invariant is that the function returns either the smallest set for the value passed in, or an empty set. It can then be used recursively with all possible values of the previous numbers in the list. Note that this is O(n!) in complexity, so it's going to be slow for large values. Also note that there are numerous optimization potentials here.
I made a small program to help with one solution. Personally, I believe the best would be a deterministic mathematical solution, but right now I lack the caffeine to even think on how to implement it. =)
Instead, I went with a SAR approach. Stop and Reverse is a technique used on stock trading (http://daytrading.about.com/od/stou/g/SAR.htm), and is heavily used to calculate optimal curves with a minimal of inference. The Wikipedia entry for parabolical SAR goes like this:
'The Parabolic SAR is calculated almost independently for each trend
in the price. When the price is in an uptrend, the SAR emerges below
the price and converges upwards towards it. Similarly, on a
downtrend, the SAR emerges above the price and converges
downwards.'
I adapted it to your problem. I start with a random value from your series. Then the code enters a finite number of iterations.
I pick another random value from the series stack.
If the new value plus the stack sum is inferior to the target, then the value is added; if superior, then decreased.
I can go on for as much as I want until I satisfy the condition (stack sum = target), or abort if the cycle can't find a valid solution.
If successful, I record the stack and the number of iterations. Then I redo everything.
An EXTREMELY crude code follows. Please forgive the hastiness. Oh, and It's in C#. =)
Again, It does not guarantee that you'll obtain the optimal path; it's a brute force approach. It can be refined; detect if there's a perfect match for a target hit, for example.
public static class SAR
{
//I'm considering Optimal as the smallest signature (number of members).
// Once set, all future signatures must be same or smaller.
private static Random _seed = new Random();
private static List<int> _domain = new List<int>() { 100, 80, 66, 24, 4, 2, 1 };
public static void SetDomain(string domain)
{
_domain = domain.Split(',').ToList<string>().ConvertAll<int>(a => Convert.ToInt32(a));
_domain.Sort();
}
public static void FindOptimalSAR(int value)
{
// I'll skip some obvious tests. For example:
// If there is no odd number in domain, then
// it's impossible to find a path to an odd
// value.
//Determining a max path run. If the count goes
// over this, it's useless to continue.
int _maxCycle = 10;
//Determining a maximum number of runs.
int _maxRun = 1000000;
int _run = 0;
int _domainCount = _domain.Count;
List<int> _currentOptimalSig = new List<int>();
List<String> _currentOptimalOps = new List<string>();
do
{
List<int> currSig = new List<int>();
List<string> currOps = new List<string>();
int _cycle = 0;
int _cycleTot = 0;
bool _OptimalFound = false;
do
{
int _cursor = _seed.Next(_domainCount);
currSig.Add(_cursor);
if (_cycleTot < value)
{
currOps.Add("+");
_cycleTot += _domain[_cursor];
}
else
{
// Your situation doesn't allow for negative
// numbers. Otherwise, just enable the two following lines.
// currOps.Add("-");
// _cycleTot -= _domain[_cursor];
}
if (_cycleTot == value)
{
_OptimalFound = true;
break;
}
_cycle++;
} while (_cycle < _maxCycle);
if (_OptimalFound)
{
_maxCycle = _cycle;
_currentOptimalOps = currOps;
_currentOptimalSig = currSig;
Console.Write("Optimal found: ");
for (int i = 0; i < currSig.Count; i++)
{
Console.Write(currOps[i]);
Console.Write(_domain[currSig[i]]);
}
Console.WriteLine(".");
}
_run++;
} while (_run < _maxRun);
}
}
And this is the caller:
String _Domain = "100, 80, 66, 25, 4, 2, 1";
SAR.SetDomain(_Domain);
Console.WriteLine("SAR for Domain {" + _Domain + "}");
do
{
Console.Write("Input target value: ");
int _parm = (Convert.ToInt32(Console.ReadLine()));
SAR.FindOptimalSAR(_parm);
Console.WriteLine("Done.");
} while (true);
This is my result after 100k iterations for a few targets, given a slightly modified series (I switched 25 for 24 for testing purposes):
SAR for Domain {100, 80, 66, 24, 4, 2, 1}
Input target value: 50
Optimal found: +24+24+2.
Done.
Input target value: 29
Optimal found: +4+1+24.
Done.
Input target value: 75
Optimal found: +2+2+1+66+4.
Optimal found: +4+66+4+1.
Done.
Now with your original series:
SAR for Domain {100, 80, 66, 25, 4, 2, 1}
Input target value: 50
Optimal found: +25+25.
Done.
Input target value: 75
Optimal found: +25+25+25.
Done.
Input target value: 512
Optimal found: +80+80+66+100+1+80+25+80.
Optimal found: +66+100+80+100+100+66.
Done.
Input target value: 1024
Optimal found: +100+1+80+80+100+2+100+2+2+2+25+2+100+66+25+66+100+80+25+66.
Optimal found: +4+25+100+80+100+1+80+1+100+4+2+1+100+1+100+100+100+25+100.
Optimal found: +80+80+25+1+100+66+80+80+80+100+25+66+66+4+100+4+1+66.
Optimal found: +1+100+100+100+2+66+25+100+66+100+80+4+100+80+100.
Optimal found: +66+100+100+100+100+100+100+100+66+66+25+1+100.
Optimal found: +100+66+80+66+100+66+80+66+100+100+100+100.
Done.
Cons: It is worth mentioning again: This algorithm does not guarantee that you will find the optimal values. It makes a brute-force approximation.
Pros: Fast. 100k iterations may initially seem a lot, but the algorithm starts ignoring long paths after it detects more and more optimized paths, since it lessens the maximum allowed number of cycles.

Sorting an Array without changing it C

Hey guys I have been working on this for 3 days and have come up with nothing from everywere I have looked.
I am trying to take an Array of around 250 floats and find the Kth largest value without changing the array in anyway or making a new array.
I can change it or create a new one because other functions need the placing of the data in the correct order and my Arduino cant hold any more values in its memory space so the 2 easiest options are out.
The values in the Array can ( and probably will ) have duplicates in them.
As an EG : if you have the array ::: 1,36,2,54,11,9,22,9,1,36,0,11;
from Max to min would be ::
1) 54
2) 36
3) 36
4) 22
5) 11
6) 11
7) 9
8) 9
9) 2
10) 1
11) 1
12) 0
Any help would be great.
It may be to much to ask for a function that would do this nicely for me :) hahaha
here is the code I have so far but I have not even tried to get the duplicates working yet
and it for some reason only gives me one answer for some reason that's 2 ,,, no clue why though
void setup()
{
Serial.begin(9600);
}
void loop ()
{
int Array[] = {1,2,3,4,5,6,7,8,9,10};
int Kth = 6; //// just for testing putting the value as a constant
int tr = 0; /// traking threw the array to find the MAX
for (int y=0;y<10;y++) //////////// finding the MAX first so I have somewhere to start
{
if (Array[y]>Array[tr])
{
tr = y;
}
}
Serial.print("The max number is ");
int F = Array[tr];
Serial.println(F); // Prints the MAX ,,, mostly just for error checking this is done
///////////////////////////////////////////////////////// got MAX
for ( int x = 1; x<Kth;x++) //// run the below Kth times and each time lowering the "Max" making the loop run Kth times
{
for(int P=0;P<10;P++) // run threw every element
{
if (Array[P]<F)
{
for(int r=0;r<10;r++) //and then test that element against every other element to make sure
//its is bigger then all the rest but small then MAX
{
Serial.println(r);
if(r=tr) /////////////////// done so the max dosent clash with the number being tested
{
r++;
Serial.println("Max's Placeing !!!!");
}
if(Array[P]>Array[r])
{
F=Array[P]; ////// if its bigger then all others and smaller then the MAx then make that the Max
Serial.print(F);
Serial.println(" on the ");
}
}}}}
Serial.println(F); /// ment to give me the Kth largest number
delay(1000);
}
If speed isn't an issue you can take this approach (pseudocode):
current=inf,0
for i in [0,k):
max=-inf,0
for j in [0,n):
item=x[j],j
if item<current and item>max:
max=item
current=max
current will then contain the kth largest item, where an item is a pair of value and index.
The idea is simple. To find the first largest item, you just find the largest item. To find the second largest item, you find the largest item that isn't greater than your first largest item. To find the third largest item, you find the largest item that isn't greater than your second largest item. etc.
The only trick here is that since there can be duplicates, the items need to include both a value and an index to make them unique.
Here is how it might be implemented in C:
void loop()
{
int array[] = {1,2,3,4,5,6,7,8,9,10};
int n = 10;
int k = 6; //// just for testing putting the value as a constant
int c = n; // start with current index being past the end of the array
// to indicate that there is no current index.
for (int x = 1; x<=k; x++) {
int m = -1; // start with the max index being before the beginning of
// the array to indicate there is no max index
for (int p=0; p<n; p++) {
int ap = array[p];
// if this item is less than current
if (c==n || ap<array[c] || (ap==array[c] && p<c)) {
// if this item is greater than max
if (m<0 || ap>array[m] || (ap==array[m] && p>m)) {
// make this item be the new max
m = p;
}
}
}
// update current to be the max
c = m;
}
Serial.println(array[c]); /// ment to give me the Kth largest number
delay(1000);
}
In the C version, I just keep track of the current and max indices, since I can always get the current and max values by looking in the array.

Resources