I'm trying to solve the "knapsack" problem using Java and recursion - java

This is for a school assignment and the professor stipulates that recursion must be used, and it must take a single line input in a gui box where the first number is the max capacity (weight) the knapsack can hold and the rest are item weights. This doesn't include the value, just weight.
It is partially working, as it is following the tree properly and indicating how many solutions there are (via debugging output) but I am having trouble being able to record the valid solutions. It seems to work fine on returns from recursive calls when at the ends of the branches due to storing and removing the items from the sack[] array.
As far as I can tell from stepping through the code a million times is that it fails when returning somewhere else. This leaves stray items sitting in the sack that shouldn't be there. Hopefully someone will be able to see where I am doing something dumb and help me go in the correct direction. I have deleted and rewritten the code in this so many times that I am about to throw my computer out of a window. lol
I know this is a lot, but I couldn't think of how to properly describe what I am having trouble with other than just posting the entire program. Thanks in advance for any help anyone might be able to provide.
import javax.swing.*;
import java.util.Arrays;
// Main Program
class n00868494 {
static int itemCount = 0; // total number of items
static int pos = 0; // position indicator in the "sack" array
static int sack[] = new int[25]; // sack to hold items on right branches
public static void main(String[] args) {
String sinput[] = new String[25]; // temp string array to hold parameters before converting to integers
int items[] = new int[25]; // array to hold the items
int capacity = 0; // knapsack capacity
String s = null; // temp string to hold user input
while (true) { // infinite loop
// Use a JOptionPane dialog to get the user's input
s = JOptionPane.showInputDialog(new JFrame("Input Params"), "Please enter total weight, followed a list of item weights)","Run Parameters",JOptionPane.QUESTION_MESSAGE);
if ((s == null) || (s.equals(""))) { // user pressed X, cancel or left it blank.
System.exit(0); // exit cleanly
}
sinput = s.split(" "); // split the parameters on the whitespace
for (int i = 0; i < sinput.length; i++) { // iterate through the array and copy the elements to the correct variables
if (i == 0) {
capacity = Integer.parseInt(sinput[i], 10); // knapsack weight in the first position
} else {
items[i-1] = Integer.parseInt(sinput[i], 10); // the rest are item weights
}
}
items = Arrays.copyOfRange(items, 0, sinput.length - 1); // truncate the items array to remove empty elements at the end
knapSack(capacity, items); // call the knapsack method that will in turn call the recursive function
}
}
public static void knapSack(int capacity, int[] items) {
itemCount = items.length; // keep track of original number of items
recknapSack(capacity, items, 0); // start recursive calls
}
/*
recursive knapsack method: called repeatedly to find the correct combinations of items such that their weights
total to the max capacity that the knapsack can hold
capacity: knapsack capacity
items: array of items (weights)
branch: flag indicating whether the call is a left branch (item not included) or right branch (item included)
0 - initial call, non recursive
1 - left branch, weight not included
2 - right branch, weight included
*/
public static void recknapSack(int capacity, int[] items, int branch) {
System.out.print("\nCap: " + capacity + " Items: " + Arrays.toString(items)); // recursive call tracking debugging
if (capacity == 0){ // debugging - for breaking at certain points in the tree
assert Boolean.TRUE; // set breakpoint on this line
}
// base cases - ends of the branches
if (capacity == 0){ // sack is exactly full, item weights = total weight
System.out.print("\t -> good tree"); // debugging
//JOptionPane.showMessageDialog(new JFrame("Results"), "The valid combinations are: ");
Arrays.fill(sack, 0); // clear the sack, this was a successful branch, will start again for another solution
return;
} else if (capacity < 0) { // bag overloaded
System.out.print("\t -> overload tree"); // debugging
if (branch == 2) // if this is an "included" branch
sack[--pos] = 0; // remove the last item placed in the sack
return;
} else if (items.length == 0){ // out of items and/or capacity not reached
System.out.print("\t -> empty src tree"); // debugging
if (branch == 2)
sack[--pos] = 0;
return;
} else {
int firstItem; // this the first item, it will either be discarded (not included) or placed in the sack array (included)
firstItem = items[0];
items = Arrays.copyOfRange(items, 1, items.length); // for either recursive branch: remove the first item from the list
recknapSack(capacity, items, 1); // call recursive function, left branch, where item is discarded and not placed in sack
// prepare for right branch, where item is placed in sack
capacity -= firstItem; // subtract the left most item weight from from capacity
sack[pos++] = firstItem; // place the item in the sack
recknapSack(capacity, items, 2); // recursive right branch call, item is placed in sack, weight subtracted from capacity
}
return;
}
}

What is happening in your code is that when it gets to the last else statement, it is not removing the initial value that was put in. I made a small change to your code that may get you the results you are looking for. First, I had the recursive function return an int, which would be the capacity:
public static int recknapSack(int capacity, int[] items, int branch) {
I changed every return statement to:
return capacity;
Then inside of the else statement, I added the following:
else {
int firstItem; // this the first item, it will either be discarded (not included) or placed in the sack array (included)
firstItem = items[0];
items = Arrays.copyOfRange(items, 1, items.length); // for either recursive branch: remove the first item from the list
recknapSack(capacity, items, 1); // call recursive function, left branch, where item is discarded and not placed in sack
// prepare for right branch, where item is placed in sack
capacity -= firstItem; // subtract the left most item weight from from capacity
int temp = pos;
sack[pos++] = firstItem; // place the item in the sack
System.out.println("First item " + firstItem);
int ret = recknapSack(capacity, items, 2); // recursive right branch call, item is placed in sack, weight subtracted from capacity
if(ret != 0)
{
System.out.println("Removing " + sack[temp] + " at position " + (temp));
sack[temp] = 0;
pos = temp;
}
}
This will keep the sack the same unless the capacity were not 0. You are still removing everything from the sack if you find it to be 0, so if you need to store that information, I would suggest that in the situation where it does work, you store the sack into an ArrayList of arrays that will contain all of the perfect solutions. If you need solutions in a situation where there is no perfect solution, you can also store every solution in there and have it ordered by the lowest capacity.
Hope that helps.

Related

Finding the element with the lowest difference in an ArrayList when compared to a constant

I am trying to have this code determine which element has the closest value to a constant.
In this code the variable boxes = 5, any element that has boxCapacity >= boxes is added to an ArrayList. From that list, the one with the closest boxCapacity to boxes should be used. I am able to select those greater than boxes, but unable to pick that with the closest boxCapacity.
public void deliver(double miles, int boxes) {
for (int i = 0; i < cars.size(); i++){
if (cars.get(i).getBoxCapacity() >= boxes){
deliveryCars = new ArrayList<Car>();
deliveryCars.add(cars.get(i));
smallest = deliveryCars.get(0).getBoxCapacity();
for(j = 0; j < deliveryCars.size(); j++){
if (deliveryCars.get(j).getBoxCapacity() < smallest) {
smallest = deliveryCars.get(j).getBoxCapacity();
k++;
}
}
}
}
System.out.println("Delivering with " + deliveryCars.get(k).getPlate());
}
I tried to make a new list, but it has not been working out.
You can simplify your code to something that looks like that
public void deliver(double miles, int boxes){
// check if there are cars availible
if (!cars.isEmpty()) {
// assume that first car in a list is best for delivery
int smallest = cars.get(0).getBoxCapacity();
Car deliveryCar = cars.get(0);
// iterating over all cars in a list
// but still compares to the first car in a list
for (Car car : cars) {
if (car.getBoxCapacity() >= boxes
&& car.getBoxCapacity() < smallest) {
deliveryCar = car;
}
}
System.out.println("Delivering with " + deliveryCar.getPlate());
}
}
Using Java 8 streams...
Car deliveryVehicle = cars
.stream()
.filter(c -> c.getBoxCapacity() > boxes)
.min(Comparator.comparingInt(Car::getBoxCapacity))
.orElse(null);
Assuming your cars was an iterable/streamable collection, this creates a stream, filters it to extract all instances where the capacity is greater than boxes, finds the element with the smallest capacity, and returns it, or null if there were no cars with more than boxes capacity.
You can then do whatever you want with the returned Car object, like call getPlate(). Remember to check for null for the case where no acceptable car was found.
This answer builds from the clarifications that #DataDino provided, namely that the goal is to find the car with the lowest boxCapacity that is greater than the targetCapacity.
Given the list of cars, you can filter out any car with a boxCapacity smaller than the target, and then select the minimum boxCapacity from what is left.
List<Car> cars = List.of(new Car(8), new Car(3), new Car(5), new Car(6));
int suggestedCapacity = 4;
Optional<Car> bestFit = cars.stream()
.filter(car -> car.getBoxCapacity() >= suggestedCapacity)
.min(Comparator.comparing(Car::getBoxCapacity));
if (bestFit.isPresent()) {
System.out.println("found car with capacity " + bestFit.get().getBoxCapacity());
} else {
System.out.println("No suitable car found");
}
The Streams api takes care of the list manipulation and keeping track of the internal state of the minimum for you.
You do not need a new list. The task you've outlined is a sequential search through an unordered list, and unless I misunderstand your goal, you only need a single for loop -- that is, you only need to iterate through the list one time. Since you are looking for a single item and you don't need to look at more than one item at a time to see if it's the best one so far, you only need one variable to keep track of its location in the list.
Here's a working sample. Notice the variable names describe the purpose (e.g. "mimimumBoxCapacity" instead of the ambiguous "boxes"). This helps me better understand what my code is doing.
// print the plate number of the car with the smallest boxCapacity
// greater than a specified minimum
public void deliver(List<Car> cars, double miles, int minimumBoxCapacity)
{
if ((cars != null) && (cars.size() > 0))
{
int indexOfBestMatch = -1; // negative index means no match yet
for (int i = 0; i < cars.size(); i++)
{
if (cars.get(i).getBoxCapacity() > minimumBoxCapacity)
{
if (indexOfBestMatch < 0)
{
// this is the only match seen so far; remember it
indexOfBestMatch = i;
}
else
{
// found a better match; replace the old best match
if (cars.get(i).getBoxCapacity() < cars.get(indexOfBestMatch).getBoxCapacity())
{
indexOfBestMatch = i;
}
}
}
}
if (indexOfBestMatch >= 0)
{
System.out.println("Delivering with " + cars.get(indexOfBestMatch).getPlate());
}
}
}
This code illustrates how your algorithm would need to change to do what you want. DataDino's answer using a Car variable to keep track of the best fit is even clearer, especially where the method returns a Car result and lets the calling logic decide what to do with that result.
(Your original code didn't compile, because variables like "smallest" and "deliveryCars" weren't defined before they were used. It would be helpful in the future if you post code that compiles, even if it doesn't yet do what you want it to do.)
So I think what you're saying is that you have of list of values say [0, 1, 2, 3, 4, 5, 6] and then you are given another number say 4, and what you want to do is to select the number from the list that is the smallest of all the numbers greater than 4, so in this case you'd want to choose 5, right?
Well, there are a ton of ways to do that. But the fastest way to do it is to go through the list one time and keep track of the smallest number greater than your 'targetNumber':
...
public Integer getNextBiggest(List<Integer> numbers, int targetNumber)
{
// Set the default 'nextInt' to the largest possible value.
int nextInt = Integer.MAX_VALUE;
for (int i = 0; i < numbers.length; i++) {
// If the current number is greater than our targetNumber.
if (sortedList.get(i) > targetNumber) {
// Set the nextInt variable to the MINIMUM of current number
// and the current nextInt value.
nextInt = Math.min(nextInt, sortedList.get(i));
}
}
return nextInt;
}
...
So that would work, but your list is a bit more complicated since you're using Objects and not integers, that said, it's a simple conversion:
First some assumptions:
cars is a List.
Car object has a getBoxCapacity() method that returns an int.
Car object has a getPlate() method that returns a String.
Ok so it might look like this:
...
public Car getBestFitCar(List<Car> cars, int targetBoxCapacity)
{
// Default best fit is null. No best first yet.
Car bestFit = null;
for (int i = 0; i < cars.length; i++) {
Car current = cars.get(i);
// If the current Car box capacity is greater than our target box capacity.
if (current.getBoxCapacity() > targetBoxCapacity) {
// Set the bestFit variable to the Car that has the MINIMUM
// 'box capacity' between the current Car and the bestFit Car.
if (bestFit == null || bestFit.getBoxCapacity() > current.getBoxCapacity()) {
bestFit = current;
}
}
}
return bestFit;
}
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
// add some cars here...
int targetBoxCapacity = 5;
Car bestFit = getBestFitCar(cars, targetBoxCapacity);
if (bestFit != null) {
System.out.println("Best fit car is: " + bestFit.getPlate());
} else {
System.out.println("No car can fit " + targetBoxCapacity + " boxes.");
}
}
Update:
I've seen some nice responses using streams, but I'd to add some caution. Streams make writing the code faster/more readable but would end up being less efficient in time/space than a solution with simple loops. This solution only uses O(1) extra space, and O(n) time in the worst case.
I'd figure the stream answers would use O(n) extra space, and O(n * n log n) time in the worst case.
So, if you have a tiny list I'd say go with the simple really cool streams solutions, but you have a list of a lot of elements that you'll be better off with a more traditional approach.

How i can decide need nextPage or not for my listItems

questiton about pagination. My "StubServer" has method ->
readAll(int limit, int offset). This method return sublist. Ok.
Question is how i can know hasNextPage or not.
I have to decide need or not next page WITHOUT knowledge about size of the list of all the elements.
Short answer:
If your result list has less than your limit then you have reached the end of list and shouldn't call the method any more.
int limit = 100;
int offset = 0;
do {
list = readAll(limit, offset);
int resultSize = list.count(); // Assuming some logic to count
// do something with list
// Check for list size vs requested items
if(resultSize < limit) {
// Exit loop when number of result retrieved was less than requested items
break;
}
// Else just move on to next batch
offset += limit;
} while (expression);

Optimal render draw-order function with specified z-index values

I found recently the default renderable sort function in LibGDX wasn't quite up to my needs. (see; Draw order changes strangely as camera moves? )
Essentially a few objects rendered in front when they should render behind.
Fortunately, the renderables in question always have a guarantied relationship. The objects are attached to eachother so when one moves the other moves. One object can be seen as being literally "pinned" to the other, so always in front.
This gave me the idea that if I specified a "z-index" (int) and "groupname" (String) for each object, I could manually take over the draw order, and for things with the same groupname, ensure they are positioned next to eachother in the list, in the order specified by the z-index. (low to high)
//For example an array of renderables like
0."testgroup2",11
1."testgroup",20
2."testgroup2",10
3.(no zindex attribute)
4."testgroup",50
//Should sort to become
0."testgroup",20
1."testgroup",50
2.(no zindex attribute)
3."testgroup2",10
4."testgroup2",11
// assuming the object2 in testgroup2 are closer to the camera, the one without a index second closest, and the rest furthest<br>
//(It is assumed that things within the same group wont be drastically different distances)
I implemented a sort system in libgdx to do this as followed;
/**
* The goal of this sorter is to sort the renderables the same way LibGDX would do normally (in DefaultRenderableSorter)<br>
* except if they have a ZIndex Attribute.<br>
* A Zindex attribute provides a groupname string and a number.<br>
* Renderables with the attribute are placed next to others of the same group, with the order within the group determined by the number<br>
*
* For example an array of renderables like;<br><br>
* 0."testgroup",20<br>
* 1."testgroup2",10<br>
* 2.(no zindex attribute)<br>
* 3."testgroup",50<br>
* <br>Should become;<br><br>
* 0."testgroup",20<br>
* 1."testgroup",50<br>
* 2.(no zindex attribute)<br>
* 3."testgroup2",10<br>
* <br>
* assuming the object in testgroup2 is closer to the camera, the one without a index second closest, and the rest furthest<br>
* (It is assumed that things within the same group wont be drastically different distances)<br>
*
* #param camera - the camera in use to determine normal sort order when we cant place in a existing group
* #param resultList - an array of renderables to change the order of
*/
private void customSorter(Camera camera, Array<Renderable> resultList) {
//make a copy of the list to sort. (This is probably a bad start)
Array <Renderable> renderables = new Array <Renderable> (resultList);
//we work by clearing and rebuilding the Renderables array (probably not a good method)
resultList.clear();
//loop over the copy we made
for (Renderable o1 : renderables) {
//depending of if the Renderable as a ZIndexAttribute or not, we sort it differently
//if it has one we do the following....
if (o1.material.has(ZIndexAttribute.ID)){
//get the index and index group name of it.
int o1Index = ((ZIndexAttribute)o1.material.get(ZIndexAttribute.ID)).zIndex;
String o1GroupName = ((ZIndexAttribute)o1.material.get(ZIndexAttribute.ID)).group;
//setup some variables
boolean placementFound = false; //Determines if a placement was found for this renderable (this happens if it comes across another with the same groupname)
int defaultPosition = -1; //if it doesn't find another renderable with the same groupname, this will be its position in the list. Consider this the "natural" position based on distance from camera
//start looping over all objects so far in the results (urg, told you this was probably not a good method)
for (int i = 0; i < resultList.size; i++) {
//first get the renderable and its ZIndexAttribute (null if none found)
Renderable o2 = resultList.get(i);
ZIndexAttribute o2szindex = ((ZIndexAttribute)o2.material.get(ZIndexAttribute.ID));
if (o2szindex!=null){
//if the renderable we are comparing too has a zindex, then we get its information
int o2index = o2szindex.zIndex;
String o2groupname = o2szindex.group;
//if its in the same group as o1, then we start the processing of placing them nexto eachother
if (o2groupname.equals(o1GroupName)){
//we either place it in front or behind based on zindex
if (o1Index<o2index){
//if lower z-index then behind it
resultList.insert(i, o1);
placementFound = true;
break;
}
if (o1Index>o2index){
//if higher z-index then it should go in front UNLESS there is another of this group already there too
//in which case we just continue (which will cause this to fire again on the next renderable in the inner loop)
if (resultList.size>(i+1)){
Renderable o3 = resultList.get(i+1);
ZIndexAttribute o3szindex = ((ZIndexAttribute)o3.material.get(ZIndexAttribute.ID));
if (o3szindex!=null){
String o3groupname = o3szindex.group;
if (o3groupname!=null && o3groupname.equals(o1GroupName)){
//the next element is also a renderable with the same groupname, so we loop and test that one instead
continue;
}
}
}
// Gdx.app.log("zindex", "__..placeing at:"+(i+1));
//else we place after the current one
resultList.insert(i+1, o1);
placementFound = true;
break;
}
}
}
//if no matching groupname found we need to work out a default placement.
int placement = normalcompare(o1, o2); //normal compare is the compare function in DefaultRenderableSorter.
if (placement>0){
//after then we skip
//(we are waiting till we are either under something or at the end
} else {
//if placement is before, then we remember this position as the default (but keep looking as there still might be matching groupname, which should take priority)
defaultPosition = i;
//break; //break out the loop
}
}
//if we have checked all the renderables positioned in the results list, and none were found with matching groupname
//then we use the defaultposition to insert it
if (!placementFound){
//Gdx.app.log("zindex", "__no placement found using default which is:"+defaultPosition);
if (defaultPosition>-1){
resultList.insert(defaultPosition, o1);
} else {
resultList.add(o1);
}
}
continue;
}
//...(breath out)...
//ok NOW we do placement for things that have no got a ZIndexSpecified
boolean placementFound = false;
//again, loop over all the elements in results
for (int i = 0; i < resultList.size; i++) {
Renderable o2 = resultList.get(i);
//if not we compare by default to place before/after
int placement = normalcompare(o1, o2);
if (placement>0){
//after then we skip
//(we are waiting till we are either under something or at the end)
continue;
} else {
//before
resultList.insert(i, o1);
placementFound = true;
break; //break out the loop
}
}
//if no placement found we go at the end by default
if (!placementFound){
resultList.add(o1);
};
} //go back to check the next element in the incomeing list of renderables (that is, the copy we made at the start)
//done
}
//Copy of the default sorters compare function
//;
private Camera camera;
private final Vector3 tmpV1 = new Vector3();
private final Vector3 tmpV2 = new Vector3();
public int normalcompare (final Renderable o1, final Renderable o2) {
final boolean b1 = o1.material.has(BlendingAttribute.Type) && ((BlendingAttribute)o1.material.get(BlendingAttribute.Type)).blended;
final boolean b2 = o2.material.has(BlendingAttribute.Type) && ((BlendingAttribute)o2.material.get(BlendingAttribute.Type)).blended;
if (b1 != b2) return b1 ? 1 : -1;
// FIXME implement better sorting algorithm
// final boolean same = o1.shader == o2.shader && o1.mesh == o2.mesh && (o1.lights == null) == (o2.lights == null) &&
// o1.material.equals(o2.material);
o1.worldTransform.getTranslation(tmpV1);
o2.worldTransform.getTranslation(tmpV2);
final float dst = (int)(1000f * camera.position.dst2(tmpV1)) - (int)(1000f * camera.position.dst2(tmpV2));
final int result = dst < 0 ? -1 : (dst > 0 ? 1 : 0);
return b1 ? -result : result;
}
As far as I can tell my customSorter function produces the order I want - the renderables now look like they are drawn in the right order.
However, this also seems like a hackjob, and I am sure my sorting algorithm is horrendously inefficient.
I would like advice on how to either;
a) Improve my own algorithm, especially in regards to any quirks to bare in mind when doing cross-platform LibGDX development (ie, array types, memory management in regards to android/web etc)
b) Alternative more efficient solutions having a similar "z index override" of the normal draw-order sorting.
Notes;
. The grouping is necessary. This is because while things are firmly stuck relatively to eachother within a group, groups themselves can also move about in front/behind eachother. (but not between). This makes it tricky to do a "global" override of the draw order, rather then a local one per group.
. If it helps, I can add/change the zindexattribute object in any way.
. I am thinking somehow "pre-storeing" each group of objects in a array could help things, but not 100% sure how.
First of all do never copy a list if not needed. The list with renderables could be really huge since it also could contain resources. Copying will be very very slow. If you need something local and you need performance try to make it final since it can improve the performance.
So a simple approach would be the default sorting of Java. You need to implement a Comperator for your class for example the Class with z index could look like this:
public class MyRenderable {
private float z_index;
public MyRenderable(float i)
{
z_index = i;
}
public float getZ_index() {
return z_index;
}
public void setZ_index(float z_index) {
this.z_index = z_index;
}
}
If you want a faster sort since your list wont change that much on runtime you could implement a insertion sort since it does a faster job if the list is kind of presorted. If it is not pre sorted it does take longer but in general it should only be the first sort call where it is alot disordered in your case.
private void sortList(ArrayList<MyRenderable> array) {
// double starttime = System.nanoTime();
for (int i = 1; i < array.size(); i++) {
final MyRenderable temp = array.get(i);
int j = i - 1;
while (j >= 0 && array.get(j).getZ_index() < temp.getZ_index()) {
array.set(j + 1, array.get(j));
j--;
}
array.set(j + 1, temp);
}
// System.out.println("Time taken: " + (System.nanoTime() - starttime));
}
To use this method you simply call it with your Array
sortList(renderbales);
In your case you need to take care of the ones that do not have a Z index. Maybe you could give them a 0 since they'll get sorted at the right position(i guess). Else you can use the given methods in z case and the regular in no z case as you do already.
After the conversation in the comments. I dont think it is a good idea to push everything into one list. It's hard to sort and would be very slow. A better approach would be a list of groups. Since you want to have groups, programm a group. Do not use String names, use IDs or types (way more easy to sort and it doesn't really matter). So a simple group would be this:
public class Group{
//think about privates and getters or methods to add things which also checks some conditions and so on
public int groupType;
public ArrayList<MyRenderable> renderables;
}
And now all your groups into a list. (this contains all your renderbales then)
ArrayList<Group> allRenderables = new ArrayList<>();
Last but not least sort the groups and sort the renderables. Since i dont think that your group ids/names will change on runtime, sort them once or even use a SortedSet instead of a ArrayList. But basically the whole sorting looks like this:
for(Group g: allRenderables)
sortRenderables(g.renderables); //now every group is sorted
//now sort by group names
sortGroup(allRenderables);
With the following insertionsorts as shown above
public static void sortRenderables(ArrayList<MyRenderable> array) {
for (int i = 1; i < array.size(); i++) {
final MyRenderable temp = array.get(i);
int j = i - 1;
while (j >= 0 && array.get(j).getZ_index() < temp.getZ_index()) {
array.set(j + 1, array.get(j));
j--;
}
array.set(j + 1, temp);
}
}
public static void sortGroup(ArrayList<Group> array) {
for (int i = 1; i < array.size(); i++) {
final Group temp = array.get(i);
int j = i - 1;
while (j >= 0 && array.get(j).groupType < temp.groupType) {
array.set(j + 1, array.get(j));
j--;
}
array.set(j + 1, temp);
}
}

Jim and the Skyscrapers - data structures Questn - solved using stack - but not efficient

Problem link :https://www.hackerrank.com/challenges/jim-and-the-skyscrapers
Problem Statement
Let us describe the problem in one dimensional space. We have in total N skyscrapers aligned from left to right. The ith skyscraper has a height of hi. A flying route can be described as (i,j) with i≠j, which means, Jim starts his HZ42 at the top of the skyscraper i and lands on the skyscraper j. Since HZ42 can only fly horizontally, Jim will remain at the height hi only. Thus the path (i,j) can be valid, only if each of the skyscrapers i,i+1,...,j−1,j is not strictly greater than hi and if the height of the skyscraper he starts from and arrives on have the same height. Formally, (i,j) is valid iff ∄k∈[i,j]:hk>hi and hi=hj.
My Approach :
I have used stack. If next integer is lesser than top of stack, it is pushed into the stack. If it is greater, top of stack (first top) is popped and compared with the top of stack. If they are equal counter is increased and again top is popped and new top is compared with previous top of stack (first top). Process is repeated till top of stack (first top) is not equal to the top of stack.
Finally If stack is not empty, I am again counting duplicate element.
This counters of a specific element are stored in an array list on the fly.
Is this a good approach? Is stack the right choice? Can my code be improvised to speed up?
My code is correct but few test cases are terminated due to timeout.
Input Format
The first line contains N, the number of skyscrapers. The next line contains N space separated integers representing the heights of the skyscrapers.
Output Format
Print an integer that denotes the number of valid routes.
My Code:
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
// method to calculate nCr
public static long choose(long total, long choose){
if(total < choose)
return 0;
if(choose == 0 || choose == total)
return 1;
return choose(total-1,choose-1)+choose(total-1,choose);
}
public static void main(String[] args) {
/* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
int count = 1;
long x = 0;
Stack s = new Stack();
ArrayList<Integer> alist = new ArrayList<Integer>();
for(int i=0 ; i<t ; i++){
int a = sc.nextInt();
if(s.isEmpty() || ((int)s.peek()>= a) ){
s.push(a);
} else {
while(!(s.isEmpty()) && a > (int)s.peek() ){
int top = (int)s.pop();
while(!(s.isEmpty()) && top == (int)s.peek()){
count++;
s.pop();
}
if(count>1){
alist.add(count);
count=1;
}
}
s.push(a);
}
}
while(!(s.isEmpty()) ){
int tp = (int)s.pop();
while(!(s.isEmpty()) && tp == (int)s.peek()){
count++;
s.pop();
}
if(count>1){
alist.add(count);
count=1;
}
}
for(Integer n : alist){
x += choose(n,2);
}
System.out.println(2*x);
}
}
your approach seems to me somewhat complicated and (consequently) time-consuming.
Here's an alternative which I doubt will ever use any relevant amount of time - in VB; I'm sure you can translate it in whatever language you'd like.
I present only the "heart" of the method (without handling of input and output)
Dim result As New SortedDictionary(Of Integer, List(Of Flight)) 'key: index of skyscraper where the flight starts.
Dim flightsWithSameStart As List(Of Flight) = Nothing 'placeholder
Dim hValue As Integer
Dim openFlights As New List(Of Flight)(hValues.Count) 'hValues is a list of (integer) skyscraper heights, provided by the user.
For indx As Integer = 0 To hValues.Count - 1
hValue = hValues(indx)
Dim n As Integer = openFlights.Count
For k As Integer = n - 1 To 0 Step -1
Dim fl As Flight = openFlights(k)
If hValue > fl.height Then
' Remove the Flight: it cannot continue and (apparently) it hasn't landed.
openFlights.RemoveAt(k)
ElseIf hValue = fl.height Then
' This flight will branch:
' a) it can stop here, landing at this height.
' b) it can also continue.
' We achieve this by storing a CLONE of the current flight and NOT removing this current flight from the open flights.
Dim flCopy As Flight = fl.Clone
flCopy.last = indx
If Not result.TryGetValue(flCopy.first, flightsWithSameStart) Then
flightsWithSameStart = New List(Of Flight)
result.Add(flCopy.first, flightsWithSameStart)
End If
flightsWithSameStart.Add(flCopy)
Else
Exit For
End If
Next
' At each skyscraper we hopefully launch another flight.
Dim flNew As New Flight
flNew.first = indx
flNew.height = hValue
openFlights.Add(flNew)
Next
' Discard any remaining open flights: they cannot land.
' (just ignore whatever is left in 'openFlights')
A simple helper class Flight is used:
Private Class Flight
Public first As Integer
Public last As Integer
Public height As Integer
Public Function Clone() As Flight
Dim copy As Flight = CType(Me.MemberwiseClone, Flight)
Return copy
End Function
End Class
Apologize if I made errors (or maybe misunderstood the problem) - just ran a few testcases and they seemed ok to me.
Regards
(forgot to mention that whenever i=>j is a valid path/flight, then so is j=>i, so it suffices to compute the cases with j>i, as in my code (and then reversing them, if you like, to add their mirrors).

Find Survivor when n people are sitting in a circle

Hi I am across this problem and trying to solve this
Take a second to imagine that you are in a room with 100 chairs arranged in a circle. These chairs are numbered sequentially from One to One Hundred.
At some point in time, the person in chair #1 will be told to leave the room. The person in chair #2 will be skipped, and the person in chair #3 will be told to leave. Next to go is person in chair #6. In other words, 1 person will be skipped initially, and then 2, 3, 4.. and so on. This pattern of skipping will keep going around the circle until there is only one person remaining.. the survivor. Note that the chair is removed when the person leaves the room.Write a program to figure out which chair the survivor is sitting in.
I made good progress but stuck with a issue, after the count reaches 100 and not sure how to iterate from here, can any one help me, this is my code
import java.util.ArrayList;
public class FindSurvivor {
public static void main(String[] args) {
System.out.println(getSurvivorNumber(10));
}
private static int getSurvivorNumber(int numChairs) {
// Handle bad input
if (numChairs < 1) {
return -1;
}
// Populate chair array list
ArrayList<Integer> chairs = new ArrayList<Integer>();
for (int i = 0; i < numChairs; i++) {
chairs.add(i + 1);
}
int chairIndex = 0;
int lr =0;
while (chairs.size() > 1) {
chairs.remove(lr);
chairIndex+=1;
System.out.println(lr+" lr, size "+chairs.size()+" index "+chairIndex);
if(lr==chairs.size()||lr==chairs.size()-1)
lr=0;
lr = lr+chairIndex;
printChair(chairs);
System.out.println();
}
return chairs.get(0);
}
public static void printChair(ArrayList<Integer> chairs){
for(int i : chairs){
System.out.print(i);
}
}
}
The answer is 31. Here are three different implementations
var lastSurvivor = function(skip, count, chairs) {
//base case checks to see if there is a lone survivor
if (chairs.length === 1)
return chairs[0];
//remove chairs when they are left/become dead
chairs.splice(skip, 1);
//increment the skip count so we know which chair
//to leave next.
skip = (skip + 1 + count) % chairs.length;
count++;
//recursive call
return lastSurvivor(skip, count, chairs);
};
/** TESTS *******************************************************************
----------------------------------------------------------------------------*/
var result = lastSurvivor(0, 0, chairs);
console.log('The lone survivor is located in chair #', result);
// The lone survivor is located in chair # 31
/** ALTERNATE IMPLEMENTATIONS ***********************************************
-----------------------------------------------------------------------------
/* Implemenation 2
-----------------*/
var lastSurvivor2 = function(chairs, skip) {
skip++;
if (chairs === 1)
return 1;
else
return ((lastSurvivor2(chairs - 1, skip) + skip - 1) % chairs) + 1;
};
/** Tests 2 *******************************************************************/
var result = lastSurvivor2(100, 0);
console.log('The lone survivor is located in chair #', result);
// The lone survivor is located in chair # 31
/* Implemenation 3
------------------*/
var chairs2 = [];
for (var i = 1; i <= 100; i++)
chairs2.push(i);
var lastSurvivor3 = function(chairs, skip) {
var count = 0;
while (chairs.length > 1) {
chairs.splice(skip, 1);
skip = (skip + 1 + count) % chairs.length;
count++;
}
return chairs[0];
};
/** Tests 3 *******************************************************************/
var result = lastSurvivor3(chairs2, 0);
console.log('The lone survivor is located in chair #', result);
// The lone survivor is located in chair # 31
I'm not sure what your removal pattern is but I'd probably implement this as a circular linked list where the 100th seat holder will connect back to the 1st seat holder. If you use an array, you will have to worry about re-organizing the seats after every removal.
There is elegant analytical solution:
Let's change numbering of people: #2 -> #1, #3 -> #2, ..., #1 -> #100 (in the end we just need to substract 1 to "fix" the result). Now first person remains instead or leaving. Suppose that there is only 64 people in circle. It's easy to see that after first elimination pass 32 people in circle will remain and numbering will start again from #1. So in the end only #1 will remain.
We have 100 people. After 36 people will leave the circle we will end up with 64 people - and we know how to solve this. For each person that leaves the room one person remains, so circle with 64 people will start from 1 + 2*36 = #73 (new #1). Because of changing indexes on first step final answer will be #72.
In general case res = 2*(N - closest_smaller_pow_2) = 2*N - closest_larger_pow_2. The code is trivial:
public static long remaining(long total) {
long pow2 = 1;
while (pow2 < total) {
pow2 *= 2;
}
return 2*total - pow2;
}
Also this algorithm has O(log(N)) complexity instead of O(N), so it's possible to calculate function for huge inputs (it can be easily adapted to use BigInteger instead of long).
First, let's assume the chairs are numbered from 0. We'll switch the numbering back at the end -- but usually things are simpler when items are enumerated from 0 rather than 1.
Now, if you've got n people and you start eliminating at chair x (x is 0 or 1) then in a single pass through you're going to eliminate half the people. Then you've got a problem of roughly half the size (possibly plus one), and if you solve that, you can construct the solution to the original problem by multiplying that sub-result by 2 and maybe adding one.
To code this, it's simply a matter of getting the 4 cases (n odd or even vs x 0 or 1) right. Here's a version that gets the 4 cases right by using bitwise trickery.
public static long j2(long n, long x) {
if (n == 1) return 0;
return j2(n/2 + (n&x), (n&1)^x) + 1-x;
}
A solution with chairs numbered from 1 and without the extra argument can now be written:
public static long remaining(long n) {
return 1 + j2(n, 0);
}
This runs in O(log n) time and uses O(log n) memory.
If your step is incremental you can you use the following code:
int cur = 0;
int step = 1;
while (chairs.size() > 1) {
chairs.remove(cur);
cur += ++step;
cur %= chairs.size();
}
return chairs.get(0);
If your step is fixed to 1 then based on explanation provided by #Jarlax you can solve the problem with one-line of code in O(log n) time:
//for long values
public static long remaining(long numChairs) {
return (numChairs << 1) - (long)Math.pow(2,Long.SIZE - Long.numberOfLeadingZeros(numChairs));
}
//for BigInteger values
public static BigInteger remaining(BigInteger numChairs) {
return numChairs.shiftLeft(1).subtract(new BigInteger("2").pow(numChairs.bitLength()));
}
However, if you stick with ArrayLists no extra variables are required to your code. Always remove the first element and remove-then-add the next at the end of the list. This is however O(n).
while (chairs.size() > 1) {
chairs.remove(0);
chairs.add(chairs.remove(0));
}
return chairs.get(0);

Categories