I've been submitting programs to this problem at ACM. Problem ID=1922 but my solution keeps getting Time Limit Exceeded on test 3.
My idea is to use brute-force but with some branches-cutting-off. The below is my Java code, any faster solutions or improvements would be appreciated... I guess this isn't difficult at all because the difficulty is only 195, but I just can't get it accepted.
Finally got it accepted. The algorithm is to first sort the heroes, and start with the smallest-wish first. Just O(n)..
My Java code is so far the fastest Solution Rank
Many thanks!
public class testtest
{
static boolean[] used;
// length of heros
static int ulen;
// list of heros
static Wish[] w;
// number of possible teams
static int count = 0;
// and output
static StringBuilder str = new StringBuilder();
// add the team
// check if it is a valid team
static boolean check(int len)
{
for (int i = 0; i < ulen; i ++)
{
if (!used[i])
{
// adding another hero makes it reliable, so invalid
if (w[i].wish <= len + 1)
{
return false;
}
}
}
return true;
}
// search the teams, team size = total, current pick = len, start from root + 1
static void search(int root, int total, int len)
{
if (len >= total) // finish picking len heros
{
if (check(total)) // valid
{
print(total); // add to output
}
return;
}
for (int i = root + 1; i < ulen; i ++)
{
if (w[i].wish > len + ulen - i)
{
return; // no enough heros left, so return
}
else
if (w[i].wish <= total) // valid hero for this team
{
used[i] = true;
search(i, total, len + 1); // search next hero
used[i] = false;
}
}
}
public static void main(String[] args) throws IOException
{
BufferedReader rr = new BufferedReader(new InputStreamReader(System.in));
ulen = Integer.parseInt(rr.readLine());
w = new Wish[ulen];
for (int i = 0; i < ulen; i ++)
{
w[i] = new Wish(i + 1, Integer.parseInt(rr.readLine()));
}
Arrays.sort(w);
used = new boolean[ulen];
Arrays.fill(used, false);
for (int i = 1; i <= ulen; i ++)
{
for (int j = 0; j <= ulen - i; j ++)
{
if (w[j].wish <= i) // this hero is valid
{
used[j] = true;
search(j, i, 1);
used[j] = false;
}
}
}
System.out.println(count);
System.out.print(str);
}
}
First, my results (of Java) is the fastest.
http://acm.timus.ru/rating.aspx?space=1&num=1922&lang=java
The fact that I didn't make full use before is that I have sorted list of heroes according to their wishes.
Therefore, the main loop just needs to be changed to O(n) instead of O(n^2)
for (int i = 1; i <= ulen; i ++)
{
if (w[0].wish <= i)
{
used[0] = true;
search(0, i, 1);
used[0] = false;
}
}
Here is what I have that executes for the sample test in ~0.00013 seconds (on my CPU):
import java.io.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Arrays;
/**
* Hero.java
*
* This program solves the Super Hero problem put forth by Timus Online Judge
* http://acm.timus.ru/problem.aspx?space=1&num=1922
*
* #author Hunter McMillen
* #version 1.0 12/29/2012
*/
public class Hero {
private static Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
private static List<Integer> indices = new ArrayList<Integer>();
private static boolean[] used;
/**
* Entry point into the application
*
* #args command line arguments
*/
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int numHeroes, wish;
List<Integer> heroes = new ArrayList<Integer>();
List<List<Integer>> groups;
// read number of heroes
numHeroes = Integer.parseInt(in.readLine());
// read 'numHeroes' wishes from stdin
// filter out heroes that have a minimum required that exceeds
// the number of heroes
for(int i = 0; i < numHeroes; i++) {
wish = Integer.parseInt(in.readLine());
if(wish <= numHeroes)
heroes.add(wish);
}
// split into groups
groups = reliableGroups(heroes);
// output results
System.out.println(groups.size());
for(List<Integer> g : groups) {
System.out.println(g.size() + " " + g.toString().replaceAll("[\\]\\[\\,]", ""));
}
}
/**
* Determines whether a group is effective, meaning that all wishes
* for that group are met
*
* #group The group to evaluate for effectiveness
*/
public static boolean isEffective(List<Integer> group) {
int maxWish = Integer.MIN_VALUE;
int temp;
// find the maximum wish size of all members in group
for(int i = 0; i < group.size(); i++) {
if((temp = indexMap.get(group.get(i))) > maxWish)
maxWish = temp;
}
// make sure that the maximum wish size is respected
return group.size() >= maxWish;
}
/**
* Checks to see if there exists some other superhero
* that when added to this group makes another effective group
*
* #effectiveGroup The current grouping that is effective but might
* not be reliable
*/
public static boolean isReliable(List<Integer> effectiveGroup) {
for(int i = 1; i <= indices.size(); i++) {
if(!used[i]) {
// add another hero to this group to see if it remains effective
effectiveGroup.add(i);
// if it is still effective, then this group is not reliable
if(isEffective(effectiveGroup))
return false;
// remove the hero that was temporarily added
effectiveGroup.remove(effectiveGroup.size()-1);
}
}
// true if adding any unused member to this group made it ineffective
return true;
}
/**
* Separates the List<Integer> of heroes into reliable groups
*
* #heroes The List of heroes
*/
public static List<List<Integer>> reliableGroups(List<Integer> heroes) {
List<List<Integer>> groups = new ArrayList<List<Integer>>();
boolean effective = true;
int h, current;
// create HashMap with mapping between hero wish values and their index
for(int i = 1; i <= heroes.size(); i++) {
indices.add(i);
indexMap.put(i, heroes.get(i-1));
}
// create an array to track which heroes have been used
used = new boolean[indices.size()+1];
Arrays.fill(used, false);
List<int[]> combinations;
List<Integer> tempList;
for(int i = 1; i <= indices.size(); i++) {
h = indexMap.get(i);
combinations = combination(heroes, h);
// iterate over all combinations making sure the wish values are below
// the threshold for this hero at map index `i`
for(int[] aCombination : combinations) {
for(int j = 0; j < aCombination.length; j++) {
current = aCombination[j];
used[current] = true;
if(indexMap.get(current) > h) {
effective = false;
break;
}
}
// create a List from the integer[] combination
tempList = asList(aCombination);
// if the group makeup is reliable, save it
if(effective && !groups.contains(tempList) && isReliable(tempList))
groups.add(new ArrayList<Integer>(tempList));
// reset flags
effective = true;
Arrays.fill(used, false);
}
}
return groups;
}
/**
* Helper method that returns a List<Integer> given
* an array of primitive ints
*
* #array The array to convert to a List<Integer>
*/
public static List<Integer> asList(int[] array) {
List<Integer> boxed = new ArrayList<Integer>();
for(int i = 0; i < array.length; i++) {
boxed.add(array[i]);
}
return boxed;
}
/**
* Generates the intial r combination in ascending order
* i.e [1, 2, 3, 4, ..., r]
*
* #r The size of the intial combination
*/
public static int[] initialCombination(int r) {
int[] indices = new int[r];
for(int i = 0; i < r; i++)
indices[i] = i+1;
return indices;
}
/**
* Generates the next combination given an array of indices
*
* #indicesIn The array of indices
* #n The size of this combination
*/
public static int[] nextCombination(int[] indicesIn, int n) {
int[] indices = (int[])indicesIn.clone();
int r = indices.length;
// find the rightmost index that is not at its final highest value
int i = 0;
for (i = r - 1; i >= 0; i--) {
if (indices[i] != (i + n - r + 1)) {
break;
}
}
// return null if no more combinations exist
if (i == -1)
return null;
// increment rightmost index
indices[i]++;
// reset all the indices to the right of indices[i]
// to their smallest possible value.
for (int j = i + 1; j < r; j++) {
indices[j] = indices[j-1] + 1;
}
return indices;
}
/**
* Generates all r-combinations of the indices array
*
* #heroes The array of heroes wishes
* #r The length of the combination to generate
*/
public static List<int[]> combination(List<Integer> heroes, int r) {
List<int[]> combinations = new ArrayList<int[]>();
int[] indices = initialCombination(r);
while(indices != null) {
combinations.add(indices);
indices = nextCombination(indices, heroes.size());
}
return combinations;
}
}
Related
I've been struggling with a problem which is as follows:
You are given a string of lower-case Latin letters. Let us define a
substring's "occurrence value" as the number of the substring
occurrences in the string multiplied by the length of the substring.
For a given string find the largest occurrence value of palindromic
substrings.
My code works perfectly, however, I need to get the solution in under a second for an input of up to 300 000 characters. My code so far is as follows:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
public class Palindrome {
public static void main(String[] args) {
// initiate a scanner
Scanner in = new Scanner(System.in);
String pal = in.nextLine();
getAllPalindrome(pal);
}
/**
* checks if the given string is a palindrome
*
* #param pal
* #return
*/
public static boolean checkPalindrome(String pal) {
for (int i = 0; i < pal.length() / 2; i++) {
if (pal.charAt(i) != pal.charAt(pal.length() - 1 - i)) {
return false;
}
}
return true;
}
/**
* gets all palindromes
*
* #param pal
*/
public static void getAllPalindrome(String pal) {
// initiate variables
ArrayList<String> pals = new ArrayList<String>();
int count = 0;
// add all palindromes to an arraylist
for (int i = 0; i < pal.length(); i++) {
for (int j = i; j < pal.length(); j++) {
if (checkPalindrome(pal.substring(i, j + 1))) {
pals.add(pal.substring(i, j + 1));
}
}
}
int[] counts = new int[pals.size()];
for (int i = 0; i < pals.size(); i++) {
int lCount = 0;
String j = pals.get(i);
for (int k = 0; k < pals.size(); k++) {
if (j.equals(pals.get(k))) {
lCount += 1;
}
counts[i] = lCount * pals.get(i).length();
}
}
int hov = 0;
for (int i = 0; i < pals.size(); i++) {
if (counts[i] > hov) {
hov = counts[i];
}
}
System.out.println(hov);
}
}
You just have to refactor your code a little bit.
First of all you have to collect all unique palindromes and count how many time each of them occures in the string.
Iterate over the map and miltiply palindrome length and it's occurence (i.e. find total length of each unique palindrome).
Retrieve maximum.
public class Palindrome {
public static void main(String[] args) {
try (Scanner scan = new Scanner(System.in)) {
System.out.println(getMaxOccurrenceValue(scan.nextLine()));
}
}
/** Retrieve maximum occurrence value */
public static int getMaxOccurrenceValue(String pal) {
return getAllPalindromes(pal).entrySet().stream()
.map(entry -> entry.getKey().length() * entry.getValue())
.mapToInt(Integer::intValue)
.max().orElse(0);
}
/** Retrieve all unique palindromes for given str with occurrence amount of each palindrome */
private static Map<String, Integer> getAllPalindromes(String str) {
Map<String, Integer> map = new TreeMap<>();
for (int i = 0; i < str.length(); i++) {
for (int j = i + 1; j < str.length(); j++) {
String sub = str.substring(i, j);
if (isPalindrome(sub))
map.compute(sub, (key, count) -> Optional.ofNullable(count).orElse(0) + 1);
}
}
return map;
}
/** Check is given str palindrome or not */
private static boolean isPalindrome(String str) {
for (int i = 0, j = str.length() - 1; i < j; i++, j--)
if (str.charAt(i) != str.charAt(j))
return false;
return true;
}
}
Here are some suggestions for speed improvement:
you are creating more String objects than you actually need. Every time you call substring you are creating a new String.
you are storing and thus processing scores for more String objects than you need. Instead of an ArrayList you could have a Set... or better yet a Map where the Entry also contains a Score.
consider how finding each palindrome centered at a position might be more efficient than finding each palindrome beginning at a position
Consider how you might eliminate processing for items which could not possibly exceed the current high score. (Hint: using properties of symmetry, as in "Manacher's algorithm").
When your input length is several hundreds of thousands, you can begin to see performance improvement with parallel processing approaches. The java-8 streams provide a simple method of parrallel computation.
I was wondering how to work with negative values and a negative target, right now my program gives index out of bounds errors whenever negative values are given to these variables. I need my hasSum function work with negative values for this project, I can't just assume positive.
import java.util.Stack;
import java.util.Scanner;
public class subsetSum {
static Scanner input = new Scanner(System.in);
static {
System.out.print("Enter the target (T)" + "\n");
}
/** Set a value for target sum */
static int TARGET_SUM = input.nextInt(); //this is the target
/** Store the sum of current elements stored in stack */
static int sumInStack = 0;
Stack<Integer> stack = new Stack<Integer>();
public static void main(String[] args) {
//the size is S
System.out.println("\n" + "Enter the size of the set (S)");
int values = input.nextInt(); //size = "values"
//value of each size entry
System.out.println("\n" + "Enter the value of each entry for S");
int [] numbers = new int[values];
for(int i = 0; i < values; i++) //for reading array
{
numbers[i] = input.nextInt();
}
if(hasSum(numbers, TARGET_SUM)){
System.out.println("\n" + "Can: ");
subsetSum get = new subsetSum(); // encapsulation
get.populateSubset(numbers, 0, numbers.length);
}else{
System.out.println("\n" + "Cannot");
}
}
//method based on dynamic programming O(sum*length)
public static boolean hasSum(int [] array, int sum)
{
int i;
int len = array.length;
boolean[][] table = new boolean[sum + 1][len + 1]; //this has to be changed for negative
//If sum is zero; empty subset always has a sum 0; hence true
for(i = 0; i <= len; i++){
table[0][i] = true;
}
//If set is empty; no way to find the subset with non zero sum; hence false
for(i = 1; i <= sum; i++){
table[i][0] = false;
}
//calculate the table entries in terms of previous values
for(i = 1; i <= sum; i++)
{
for(int j = 1; j <= len; j++)
{
table[i][j] = table[i][j - 1];
if(!table[i][j] && i >= array[j - 1]){
table[i][j] = table[i - array[j - 1]][j - 1];
}
}
}
return table[sum][len]; //this has to be changed for negative
}
public void populateSubset(int[] data, int fromIndex, int endIndex) {
/*
* Check if sum of elements stored in Stack is equal to the expected
* target sum.
*
* If so, call print method to print the candidate satisfied result.
*/
if (sumInStack >= TARGET_SUM) {
if (sumInStack == TARGET_SUM) {
print(stack);
}
// there is no need to continue when we have an answer
// because nothing we add from here on in will make it
// add to anything less than what we have...
return;
}
for (int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++) {
if (sumInStack + data[currentIndex] <= TARGET_SUM) {
stack.push(data[currentIndex]);
sumInStack += data[currentIndex];
/*
* Make the currentIndex +1, and then use recursion to proceed
* further.
*/
populateSubset(data, currentIndex + 1, endIndex);
sumInStack -= (Integer) stack.pop();
}
}
}
/**
* Print satisfied result. i.e. 5 = 1, 4
*/
private void print(Stack<Integer> stack) {
StringBuilder sb = new StringBuilder();
for (Integer i : stack) {
sb.append(i).append(",");
}
// .deleteCharAt(sb.length() - 1)
System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
}
}
Are you trying to find a sum of subset or a subarray?
If a subset, then a simple recursion could do the trick, e.g.:
public static boolean hasSum(int [] array, int sum)
{
return hasSum(array, 0, 0, sum);
}
private static boolean hasSum(int[] array, int index, int currentSum, int targetSum) {
if (currentSum == targetSum)
return true;
if (index == array.length)
return false;
return hasSum(array, index + 1, currentSum + array[index], targetSum) || // this recursion branch includes current element
hasSum(array, index + 1, currentSum, targetSum); // this doesn't
}
If you're trying to find a subarray, I'd use prefix sums, e.g.:
public static boolean hasSum(int [] array, int sum)
{
int[] prefixSums = new int[array.length];
for (int i = 0; i < prefixSums.length; i++) {
prefixSums[i] = (i == 0) ? array[i] : array[i] + prefixSums[i - 1];
}
for (int to = 0; to < prefixSums.length; to++) {
if (prefixSums[to] == sum)
return true; // interval [0 .. to]
for (int from = 0; from < to; from++) {
if (prefixSums[to] - prefixSums[from] == sum)
return true; // interval (from .. to]
}
}
return false;
}
BTW I think reading the input values from Scanner inside the static initializer is a bad idea, why don't you move them to main()?
I am trying to make radix sort function that calculates the number of digits of integer numbers using the radix sort as a base, and then sort the numbers from least significant to most significant.
I am using an array that holds random integers.
How can I make this method works well?
I am using this code:
public static void sort( int[] a, int radix)
{
int i, m = a[0], exp = 1, n = a.length;
int[] b = new int[10];
for (i = 1; i < n; i++)
if (a[i] > m)
m = a[i];
while (m / exp > 0)
{
int[] bucket = new int[10];
for (i = 0; i < n; i++)
bucket[(a[i] / exp) % 10]++;
for (i = 1; i < 10; i++)
bucket[i] += bucket[i - 1];
for (i = n - 1; i >= 0; i--)
b[--bucket[(a[i] / exp) % 10]] = a[i];
for (i = 0; i < n; i++)
a[i] = b[i];
exp *= 10;
}
}
Try
int[] b = new int[a.length];
or since n = a.length
int[] b = new int[n];
I am just pointing out the most obvious problems and leave the details to you.
Each bucket will have to hold a list of numbers so using just an int as a bucket is not going to work. Use something like this instead:
List<Integer>[] bucket = new List<Integer>[10];
The array used to collect the elements in the new order needs to be the same size as the original array. You just have made it 10 long.
Statement in last for loop
a[i] = b[i];
tells that size of b must be equal to or greater than a. Hence go for #rcgldr answer. Also the value of radix passed to your function is lying unused. You can also make your function a tad faster by swapping array pointers instead of copying the elements i.e. avoiding the last for loop.
int swap[] = a;
a = b;
b = swap;
then finally after all the loops are over, return the array a
return a;
Above is your program for sorting in ascending order. I am giving below the program to sort in descending order. The only change that was required was to start adding frequencies from the end of the base array( in this case Z ) to index zero.
public static int[] DSC(int A[], int radix, int base)
{
int length = A.length ;
int B[] = new int[length] ;
int div = 1 ;
int swap[] ;
int i ;
while(radix > 0)
{
int Z[] = new int[base] ;
i = 0 ;
while(i < length)
{
Z[( A[i] / div ) % base]++ ;
i++ ;
}
i = base ;
while(i > 1)
{
i--;
Z[i-1] += Z[i] ;
}
i = length ;
while(i > 0)
{
i-- ;
B[--Z[( A[i] / div ) % base]] = A[i];
}
swap = A;
A = B;
B = swap;
div *= base;
radix--;
}
return A;
}
For non-negative integers, using binary instead of decimal, might be more efficient & intuitive for machine.
Here is an implementation I wrote, with test case:
RadixSort.java
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* Radix sort.
*
* #author eric
* #date 3/12/20 12:05 PM
*/
public class RadixSort {
/**
* Sort given array, the array will be modified.
*
* #param data array of integer of non-negative integers,
* #throws IllegalArgumentException if input contain negative integer,
*/
public static void sort(int[] data) {
int numSys = 2;
int bits = validAndfindHighestBit(data); // find highest bit,
// create queues,
List<List<Integer>> queues = new ArrayList<>(numSys);
for (int i = 0; i < numSys; i++) queues.add(new LinkedList<>());
// sort bit by bit, low to high,
for (int i = 0; i < bits; i++) {
// re-init queues,
for (int j = 0; j < numSys; j++) queues.get(j).clear();
// array -> queues,
for (int x : data) {
int bit = (x >> i) & 1; // get the i-th bit,
queues.get(bit).add(x);
}
// queues -> array,
int t = 0;
for (List<Integer> queue : queues) {
for (int x : queue) data[t++] = x;
}
}
}
/**
* Valid input number, and find highest bit that has 1.
*
* #param data
* #return
* #throws IllegalArgumentException if input contain negative integer,
*/
private static int validAndfindHighestBit(int[] data) {
// find max number,
int max = 0;
for (int x : data) {
if (x < 0) throw new IllegalArgumentException("negative integers are not supported");
if (x > max) max = x;
}
System.out.printf("max number: %d, ", max);
// find highest bit,
int highestBit = 0;
while (max != 0) {
highestBit++;
max >>= 1;
}
System.out.printf("highest bit: %d\n", highestBit);
return highestBit;
}
}
RadixSortTest.java
(Test case via TestNG)
import org.testng.Assert;
import org.testng.annotations.Test;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import static org.testng.Assert.*;
/**
* RadixSort test.
*/
public class RadixSortTest {
#Test
public void testSort() {
int[] data;
// generated un-sorted random array,
do data = genRandomArr(); while (data.length > 1 && isSorted(data));
System.out.printf("input arr:\t%s\n", Arrays.toString(data));
if (data.length > 1) Assert.assertFalse(isSorted(data));
// sort
RadixSort.sort(data);
System.out.printf("output arr:\t%s\n", Arrays.toString(data));
Assert.assertTrue(isSorted(data));
}
// corner case,
#Test
public void testSort_corner() {
int[] dataEmpty = new int[0]; // empty array,
RadixSort.sort(dataEmpty);
Assert.assertTrue(isSorted(dataEmpty));
int[] dataSingle = new int[]{5}; // single element,
RadixSort.sort(dataSingle);
Assert.assertTrue(isSorted(dataSingle));
}
// invalid input,
#Test(expectedExceptions = IllegalArgumentException.class)
public void testSort_invalid() {
int[] dataSingle = new int[]{1, -1}; // negative number,
RadixSort.sort(dataSingle);
}
/**
* generate random array, of size 10, in range [0, 1024),
*
* #return
*/
public static int[] genRandomArr() {
return genRandomArr(10, 100);
}
/**
* generate random array,
*
* #param size array size, default to 10,
* #param bound upper bound, default to 100,
* #return
*/
public static int[] genRandomArr(int size, int bound) {
if (size <= 0) size = 10;
if (bound <= 0) bound = 100;
ThreadLocalRandom rd = ThreadLocalRandom.current();
int[] arr = new int[size];
for (int i = 0; i < arr.length; i++) arr[i] = rd.nextInt(bound);
return arr;
}
// check whether array is sorted,
private static boolean isSorted(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) return false;
}
return true;
}
}
I know how to create an array of 100 with integers from 1-100 which will be just:
int [] array = new int[100]; // Sorted Array of 100
for (int a = 0; a < array.length; a++) {
array[a] = a + 1;
}
But my question is how to create an array of 100 with some sorted integers from 1-1000, inclusive. Any help will be appreciated!
How about this?
int [] array = new int[100];
for (int a = 0; a < array.length; a++) {
array[a] = (a + 1) * 10;
}
Simple, if you have no other requirement.
Edit: To make it almost sorted (like every 10th unsorted element), there are many ways. One, using BevynQ's solution, can be:
Random r = new Random();
int [] array = new int[100];
for (int a = 0; a < array.length; a++) {
if ((a + 1) % 10 != 0) {
array[a] = (a + 1) * 10;
} else {
array[a] = r.nextInt(1000);
}
}
Here is a simple solution using random
Random r = new Random();
int [] array = new int[100];
int last = 0;
for (int a = 0; a < array.length; a++) {
last = last + r.nextInt(10) + 1;
array[a] = last;
}
You can even create an array with data elements of a particular sequence such as prime numbers, factors or some series like fibonacci series.
Example:
class Fibonacci {
public static void main(String args[]) {
int array[] = new int[100];
System.out.println("*****Fibonacci Series*****");
int f1, f2=0, f3=1;
for(int i=1;i<=100;i++) {
array[i] = f3;
f1 = f2;
f2 = f3;
f3 = f1 + f2;
}
}
}
You can even make it so how sorted it is can easily be changed by the user. This is a lot more code to write, but works in essence by swaping a certain number of spots in the array. That number can change by the user. I put 0 to 100 before swaping the numbers, but all that matters is it is a well orderd math pattern.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package partlysorted;
import java.util.Scanner;
/**
*
* #author Library computer
*/
public class PartlySorted {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
//scanner for user input
Scanner input = new Scanner(System.in);
//intro
System.out.println("Welcome to the partly sorted pogram");
System.out.println("This will make a partly sorted list of integers");
//the numbers
int[] nums = new int[100];
//how unsorted for it to be
int suffels = -1;
//when to show a typo message
boolean firstLoop = true;
while(suffels < 0 || suffels > 100)
{
if(firstLoop)
{
System.out.println("Please enter how sorted sorted you want (0 to 100, no decimals)");
}
else
{
System.out.println("Looks like you made a typo");
System.out.println("Please enter a integer from 0 to 100");
}
suffels = input.nextInt();
firstLoop = false;
}
//fill it sorted first
for(int i = 0; i < nums.length; i++)
{
nums[i] = i;
}
//suffle the array
for(int swaps = 0; swaps < suffels; swaps++)
{
int firstPlace = (int)(Math.random() * 100);
int secondPlace = (int)(Math.random() * 100);
//swap the places
int temp = nums[firstPlace];
nums[firstPlace] = nums[secondPlace];
nums[secondPlace] = temp;
}
//printing it out
for(int n: nums)
{
System.out.println(n);
}
}
}
I have written a method to evaluate a Pascal's triangle of n rows. However when I test the method I receive the error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
Here is the code:
public static int[] PascalTriangle(int n) {
int[] pt = new int[n + 1];
if (n == 0) {
pt[0] = 1;
return pt;
}
int[] ppt = PascalTriangle(n - 1);
pt[0] = pt[n] = 1;
for (int i = 0; i < ppt.length; i++) {
pt[i] = ppt[i - 1] + ppt[i];
}
return pt;
}
Please let me know if you have any ideas for how the code could be edited to fix the problem.
for(int i = 0; i < ppt.length; i++)
{
pt[i] = ppt[i-1] + ppt[i];
In your first iteration, i == 0 and so (i-1) == -1. This is the cause of the error.
You can special handle the boundaries to avoid this. Or as the others have suggested, start i at 1 instead of 0.
Here is some code a friend of mine came up with
import java.util.Scanner;
public class Pascal {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the number of rows to print: ");
int rows = scanner.nextInt();
System.out.println("Pascal Triangle:");
print(rows);
scanner.close();
}
public static void print(int n) {
for (int i = 0; i < n; i++) {
for (int k = 0; k < n - i; k++) {
System.out.print(" "); // print space for triangle like structure
}
for (int j = 0; j <= i; j++) {
System.out.print(pascal(i, j) + " ");
}
System.out.println();
}
}
public static int pascal(int i, int j) {
if (j == 0 || j == i) {
return 1;
} else {
return pascal(i - 1, j - 1) + pascal(i - 1, j);
}
}
}
In this code:
pt[0] = pt[n] = 1;
for(int i = 0; i < ppt.length; i++)
{
pt[i] = ppt[i-1] + ppt[i];
}
the problem is that when i is 0, you're trying to access ppt[i-1] which is ppt[-1]. The thing to notice is that when i is 0, you don't need to execute the statement that sets pt[i], because you already set pt[0] up before the loop! Try initializing i to 1 instead of 0.
Improvement in #Clemson code using Dynamic Programming :
class Solution {
int[][] dp ;
public List<List<Integer>> generate(int numRows) {
dp = new int[numRows][numRows];
List<List<Integer>> results = new ArrayList<>();
pascal(results, numRows);
return results;
}
private void pascal(List<List<Integer>> results, int numRows) {
for(int i = 0; i < numRows; i++) {
List<Integer> list = new ArrayList<>();
for(int j = 0; j <= i ; j++) {
list.add(dfs(i, j));
}
results.add(list);
}
}
private int dfs(int i, int j) {
if(j == 0 || i == j) return 1;
if(dp[i][j] != 0) return dp[i][j];
return dp[i][j] = dfs(i - 1, j - 1) + dfs(i - 1, j );
}
}
This isn't the solution to your code but it is solution to printing Pascals Triangle using only recursion which means no loops, using the combinations formula. All it needs is a main method or demo class to create an instance of the PascalsTriangle class. Hope this helps future Java students.
public class PascalsTriangle {
private StringBuilder str; // StringBuilder to display triangle
/**
* Starts the process of printing the Pascals Triangle
* #param rows Number of rows to print
*/
public PascalsTriangle(int rows) {
str = new StringBuilder();
printTriangle(rows, str);
}
/**
* Uses recursion to function as an "outer loop" and calls
* itself once for each row in triangle. Then displays the result
* #param row The number of the row to generate
* #param str StringBuilder to insert each row into
*/
public static void printTriangle(int row, StringBuilder str) {
// calls itself until row equals -1
if (row >= 0) {
// calls lower function to generate row and inserts the result into front of StringBuilder
str.insert(0, getRow(row, 0) + "\n");
// calls itself with a decremented row number
printTriangle(row - 1, str);
} else {
// when the base case is reached - display the result
JOptionPane.showMessageDialog(null, str);
System.exit(0);
}
}
/**
* Uses recursion to act as the "inner loop" and calculate each number in the given row
* #param rowNumber Number of the row being generated
* #param elementNumber Number of the element within the row (always starts with 0)
* #return String containing full row of numbers or empty string when base case is reached
*/
public static String getRow(int rowNumber, int elementNumber) {
// calls itself until elementNumber is greater than rowNumber
if (elementNumber <= rowNumber) {
// calculates element using combinations formula: n!/r!(n-r)!
int element = fact(rowNumber) / (fact(elementNumber) * (fact(rowNumber - elementNumber)));
// calls itself for each element in row and returns full String
return element + " " + getRow(rowNumber, elementNumber + 1);
} else return "";
}
/**
* Helper function that uses recursion to calculate factorial of given integer
* #param n Number to calculate factorial
* #return Factorial
*/
public static int fact(int n) {
if (n <= 0)
return 1;
else
return n * fact(n - 1);
}