Project Euler #18: Maximum Path Sum I - java

So basically I interpreted this problem as follows:
3
7 4
2 4 6
8 5 9 3
The two number below the starting should be compared and the larger should be picked as the new number. So in this case, it would be 3, then 7, then 4, then 9. Sum them up, get the answer of 23. I wrote a program to achieve this:
public class ProblemEighteen {
private static int pos = 1;
public static void main(String[] args) {
try {
Scanner in = new Scanner(new File("Problem18Text"));
int sum = 0;
while (in.hasNextLine()) {
final String line = in.nextLine();
int big = getBiggestNum(line);
sum += big;
System.out.println(big);
}
System.out.println(sum);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private static int getBiggestNum(String line) {
final String[] numbers = line.split(" ");
if (numbers.length == 1) {
pos = 1;
return Integer.parseInt(numbers[0]);
} else {
int i = 1;
int numOne = -1;
int numTwo = -1;
for (final String num : numbers) {
if (pos == i) {
numOne = Integer.parseInt(num);
} else if (pos + 1 == i) {
numTwo = Integer.parseInt(num);
}
i++;
if (numOne != -1 && numTwo != -1)
break;
}
if (numOne > numTwo) {
return numOne;
} else {
pos += 1;
return numTwo;
}
}
}
It works fine for the example I gave above, but when I put in the actual problem to solve, it said I got it wrong (I got 1064). I added a print statement to see what numbers it was selecting and it got them all right (based on how I understood what I was trying to find) but I still got it wrong... Anyone know why?

It's been a while since I've solved this problem, but you'll find that it's best that you start at the bottom of the triangle and work your way up. Especially, when you get to problem 67.
If you read your data into an array as baum suggested, you'd have data that looks like this:
3 0 0 0
7 4 0 0
2 4 6 0
8 5 9 3
So start at the bottom taking two numbers at a time and comparing a sum to their adjacent number in the next above row.
8 + 2 = 10 or 5 + 2 = 7. 10 is greater so replace the 2 with the 10.
5 + 4 = 9 or 9 + 4 = 13. 13 is greater so replace the 4 with the 13.
9 + 6 = 15 or 3 + 6 = 9. 15 is greater so replace the 6 with 15.
Now move up one row and perform the same checks until you get to the very top and the very top should contain the correct answer.

Related

Issue with getting this java program to display the proper whitespace in the answer

So my problem is, my output seems to be correct except it is giving me 0/10 for credit because of the whitespace after the output counts down to one in each situation. It is saying I need a newline after the one but I have tried several things and it's the same output every time.
2.31 LAB: Hailstone sequence
Given a positive integer n, the following rules will always create a sequence that ends with 1, called the hailstone sequence:
If n is even, divide it by 2
If n is odd, multiply it by 3 and add 1 (i.e. 3n +1)
Continue until n is 1
Write a program that reads an integer as input and prints the hailstone sequence starting with the integer entered. Format the output so that ten integers, each separated by a tab character (\t), are printed per line.
The output format can be achieved as follows:
System.out.print(n + "\t");
Ex: If the input is:
25
the output is:
25 76 38 19 58 29 88 44 22 11
34 17 52 26 13 40 20 10 5 16
8 4 2 1
import java.util.Scanner;
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
int n;
n = scnr.nextInt();
System.out.print(n + "\t");
int count = 1;
while (n > 1) {
if (n % 2 == 0) {
n = n * 1 / 2;
} else {
n = 3 * n + 1;
}
System.out.print(n + "\t");
count++;
if (count % 10 == 0) {
System.out.print("\n");
}
}
}
This is what I came up with and I am new to java so it is probably something I am overthinking, any thoughts would be appreciated.
"enter image description here" is not an image description
If nothing works, I guess you can trick it by just skipping the tab on the 10'th print. So instead of your normal System.out.print(n + "\t"); print try:
if ((count + 1) % 10 == 0) {
System.out.print(n);
} else {
System.out.print(n + "\t");
}
instead of your normal print.
I figured it out, I just needed to change the order of the code a little and make (n != 1) and System.out.print(n) at the very end. Thanks for the help.
try this, changed the print condition to exclude the tab for end value and when n is 1.
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
int n;
n = scnr.nextInt();
System.out.print(n + "\t");
int count = 1;
while (n > 1) {
if (n % 2 == 0) {
n = n * 1 / 2;
} else {
n = 3 * n + 1;
}
count++;
if (count % 10 == 0) {
System.out.println(n);
}else{
if(n==1) {
System.out.print(n);
}else{
System.out.print(n + "\t");
}
}
}
}

Run-length encoding in java [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
How to print out the number of a specific digit along with the digit itself in form "nxw." n is the frequency of the number, w is the number itself.
So, for example, if the user's input was 1 1 1. The output would be 3x1.
If the user's input was 1 1 1 at the first line and 7 7 1 1 0 at the second line. The output would be 3x1.2x7.2x1.1x0. with no spaces.
Note:
loop ends with a dot.
numbers don't have to be in a specific order
user can input as many digits as they want.
So for example, Input can be 1 1 1 at the first line 7 7 1 1 0 at the second ... etc.
This is my code so far. But I know that it's not true.
import java.util.*;
public class LaufLaengenKodierung {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int freq = 0;
int oldNum = 0;
int num = 0;
boolean first = true;
while(sc.hasNextInt()) {
int i = sc.nextInt();
if(i == oldNum) {
freq++;
num = i;
} else if(i != oldNum) {
freq = 1;
oldNum = i;
num = i;
if(first) {
first = false;
num = i;
freq = 1;
}
}
}
System.out.print(freq + "x" + num + ".");
sc.close();
}
}
Existing code needs to be slightly refactored to print the frequency and integer value as soon as a sub-sequence of the same values ends.
static void printRLE(String input) {
Scanner sc = new Scanner(input);
int freq = 0;
int oldNum = 0;
boolean first = true;
while(sc.hasNextInt()) {
int i = sc.nextInt();
if (i != oldNum || first) {
if (first)
first = false;
else // integer value changed
System.out.printf("%dx%d.", freq, oldNum);
oldNum = i;
freq = 1;
} else {
freq++;
}
}
if (!first)
System.out.printf("%dx%d.%n", freq, oldNum);
else
System.out.println("No integer found"); // or print 0x0 if it's correct
sc.close();
}
Tests:
String[] tests = {
"",
"abc.",
"11 11 11",
"1 1 1\n7 7 1 1 0",
"0 0 0",
};
for (String test: tests) {
System.out.println("test=[" + test + "]");
printRLE(test);
System.out.println("--------");
}
Output:
test=[]
No integer found
--------
test=[abc.]
No integer found
--------
test=[11 11 11]
3x11.
--------
test=[1 1 1
7 7 1 1 0]
3x1.2x7.2x1.1x0.
--------
test=[0 0 0]
3x0.
--------
Update
If separate digits need to be counted only (not the integer numbers), e.g. input 11 11 11 should be converted to 6x1. instead of 3x11. as shown above, the method should be refactored to process the digits inside numbers:
static void printRLEDigits(String input) {
Scanner sc = new Scanner(input);
int freq = 0;
int oldNum = 0;
boolean first = true;
out: while(sc.hasNext()) {
String s = sc.next(); // getting "number" delimited with whitespaces
for (char c: s.toCharArray()) {
if (!Character.isDigit(c)) {
break out;
}
int i = c - '0';
if (i != oldNum || first) {
if (first)
first = false;
else // digit changed
System.out.printf("%dx%d.", freq, oldNum);
oldNum = i;
freq = 1;
} else {
freq++;
}
}
}
if (!first)
System.out.printf("%dx%d.%n", freq, oldNum);
else
System.out.println("No integer found");
sc.close();
}
Output for tests: "11 11 11", "112 223", "1 1 1\n7 7 1 1 0", "0 0 0":
test=[11 11 11]
6x1.
--------
test=[112 223]
2x1.3x2.1x3.
--------
test=[1 1 1
7 7 1 1 0]
3x1.2x7.2x1.1x0.
--------
test=[0 0 0]
3x0.
--------
Online demo of both methods printRLE and printRLEDigits
You have to save the count of each individual digit. You can do this by creating an int array of size 10, for the digits 0 to 9. Then it's a simple loop like
while(sc.hasNextInt()) {
int i = sc.nextInt();
countArray[i]++;
}
After that you check each element in the array and output the count of the digit, when it is bigger than 0. It can look like this:
for (int i=0; i<countArray.length; i++) {
if (countArray[i] > 0) {
System.out.printf("%dx%d.", countArray[i], i);
}
}
Keep in mind that you have to check if the number entered by the user is in the limit of 0 to 9, otherwise you run into ArrayIndexOutOfBoundsExceptions.

Java Hailstone Sequence

I have to do a Hailstone Sequence code in Java for example it should go like this:
10 5 16 8 4 2 1 4 2 1
Mine goes like this:
10 5 16 8 4 2 1
How to fix this?
This is my code:
static int counter;
static int HailstoneNumbers(int Number)
{
System.out.print(Number+ " ");
if (Number == 1 && counter == 0) {
return counter;
}
else if (Number == 1 && counter != 0) {
counter++;
return counter;
}
else if (Number % 2 == 0) {
counter++;
HailstoneNumbers(Number / 2);
}
else if (Number % 2 != 0) {
counter++;
HailstoneNumbers(3 * Number + 1);
}
return counter;
}
public static void main(String[] args)
{
int Number;
KeyboardReader reader = new KeyboardReader();
System.out.println("What is your intial value? ");
Number = reader.readInt();
int x;
x = HailstoneNumbers(Number);
System.out.println();
System.out.println("Number of Steps: " +x);
}
}
Your code explicitly says to stop the sequence when it reaches the number 1. Maybe you meant the behavior to be different depending on the value of counter, but it isn't clear why it should not stop at the first 1 but should stop at the second (as counter will not be 0 for either).

Terminated due to timeout error [duplicate]

I am working on a program that takes an integer and finds the number of combinations of consecutive sums that the integer has:
The number 13 can be expressed as a sum of consecutive positive
integers 6 + 7. Fourteen can be expressed as 2 + 3 + 4 + 5, also a sum
of consecutive positive integers. Some numbers can be expressed as a
sum of consecutive positive integers in more than one way. For
example, 25 is 12 + 13 and is also 3 + 4 + 5 + 6 + 7.
I researched and read that it's the number of odd factors minus one. So I wrote a program that finds the number of odd factors and my answer is still wrong in certain cases. Any insight?
Code seems to work fine but there is a crash due to Timeout which is probably due to optimization error.
The constraints for possible input size is
1 to 10^(12)
The code below is copied from alfasin's answer below:
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
static long consecutive(long num) {
while (num % 2 == 0) num /= 2;
return consecutiveHelper(num);
}
public static long consecutiveHelper(long num) {
return LongStream.rangeClosed(3, (num / 2)).parallel().filter(x -> x % 2 != 0).map(fn -> (num % fn == 0) ? 1 : 0).sum();
}
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
final String fileName = System.getenv("OUTPUT_PATH");
BufferedWriter bw = null;
if (fileName != null) {
bw = new BufferedWriter(new FileWriter(fileName));
}
else {
bw = new BufferedWriter(new OutputStreamWriter(System.out));
}
int res;
long num;
num = Long.parseLong(in.nextLine().trim());
res = consecutive(num);
bw.write(String.valueOf(res));
bw.newLine();
bw.close();
}
}
This is what i currently have
As the post i answered to was duplicate, I copied my answer here as well.Let's try to find a pseudo-optimized method to resolve your problem :
What you need to do is to decompose your number in prime factors.
For example, if you take 1200 :
1200 = 2*2*2*2*3*5*5 = 1 * 2^4 * 3^1 * 5^2
You can then analyze how you could get odd factors with those prime factors. A quick analyze will tell you that :
odd * odd = odd
odd * even = even
even * even = even
With that in mind, let's find all the factors we get with odd * odd :
1 * 1 = 1
3 * 1 = 3
5 * 1 = 5
5 * 3 = 15
5 * 5 = 25
5 * 5 * 3 = 75
A quick way to find these combinations without writing them all is the "plus 1 method" : add 1 to the number of occurences of each prime odd factor, and multiply them together :
We found that 1200 = 1 * 2^4 * 3^1 * 5^2, so we can do :
("number of 3" + 1) ("number of 5" + 1) = (1 + 1) ( 2 + 1) = 6
There are 6 odd factors for the number 1200, and as you stated, remove 1 from that number to get the number of combinations of consecutive sums that 1200 has :
6 - 1 = 5 <-- woohoo ! finally got the result !
Now, let's look at the code. What we want to have is a Map, the keys being the prime factors and the values being the number of their occurences :
/*
If number is odd,
find the number in the keys and add 1 to its value.
If the number is not in the keys, add it with value = 1.
*/
public static void addValue(Map<Integer, Integer> factors, int i) {
if(i % 2 != 0) {
int count = factors.containsKey(i) ? factors.get(i) : 0;
factors.put(i, ++count);
}
}
/*
Classic algorithm to find prime numbers
*/
public static Map<Integer, Integer> oddPrimeFactors(int number) {
int n = number;
Map<Integer, Integer> factors = new HashMap<>();
for (int i = 2; i <= n / i; i++) {
while (n % i == 0) {
addValue(factors, i);
n /= i;
}
}
if(n > 1) addValue(factors, n);
return factors;
}
With that, let's try to print what the map contains for number 1200 :
public static void main(String[] args) {
int n = 1200;
System.out.println(oddPrimeFactors(n));
}
$n : {3=1, 5=2}
Good ! Now let's finish the program with the method we developed before :
public static int combinations = 1;
public static void main(String[] args) {
int n = 1200;
oddPrimeFactors(n).forEach((key, value) -> combinations *= (value + 1));
combinations--;
System.out.println(combinations);
}
$combinations = 5
Finished ! feel free to ask if you did not understand something !
Note : I tried my program with the max value Integer can handle and it took less than one second for my program to proceed, which seems pretty fast to me. It could probably be faster though, it's up to you to find the most optimized version of this code !
Here are the optimizations that we discussed in the comments section, see comments as markers:
static int consecutive(long num) {
while (num % 2 == 0) num /= 2; // 1st opt.
return consecutiveHelper(num)-1;
}
public static int consecutiveHelper(long num) {
long factorNumber = 1;
int count = 0;
while(factorNumber <= num / 2) { // 2nd opt.
if(num % factorNumber == 0) {
count++;
}
factorNumber += 2; // 3rd opt.
}
if (num % 2 != 0) {
count++;
}
return count;
}
UPDATE
I managed to reduce ~50% runtime for big-numbers (10^12) by using Java 8 Stream interface and running in parallel:
static long consecutive(long num) {
while (num % 2 == 0) num /= 2;
return consecutiveHelper(num);
}
public static long consecutiveHelper(long num) {
return LongStream
.rangeClosed(3, (num / 2))
.parallel()
.filter(x -> x % 2 != 0)
.map(fn -> (num % fn == 0) ? 1 : 0)
.sum();
}
That said, parallel will be more expensive when you're dealing with smaller numbers. If you want your answer to be optimal you should use both methods: for smaller numbers use the first and for large numbers use the latter.

Longest Snake Sequence

Question : A set of numbers separated by space is passed as input. The program must print the largest snake sequence present in the numbers. A snake sequence is made up of adjacent numbers such that for each number, the number on the right or left is +1 or -1 of it's value. If multiple snake sequences of maximum length is possible print the snake sequence appearing in the natural input order.
Example Input/Output 1:
Input:
5 6 7 9 8 8
Output:
5 6 7 8 9 8
8 9 8 7 6 5
Example Input/Output 2:
Input:
9 8 7 5 3 0 1 -2 -3 1 2
Output:
3 2 1 0 1
void doPermute(int[] in, StringBuffer out, boolean[] used, int length, int level, StringBuffer max) {
if (level == length) {
int count = 0;
for (int i = 1; i < out.length(); i++) {
if (Math.abs(Character.getNumericValue(out.charAt(i)) - Character.getNumericValue(out.charAt(i - 1))) != 1) {
//System.out.println(Character.getNumericValue(i) - Character.getNumericValue(i - 1) + " " + i + " yes");
count++;
break;
}
}
if (count == 0) {
max.append(out + " ");
}
return;
}
for (int i = 0; i < length; ++i) {
if (used[i]) {
continue;
}
out.append(in[i]);
used[i] = true;
doPermute(in, out, used, length, level + 1, max);
used[i] = false;
out.setLength(out.length() - 1);
}
}
As i am using StringBuffer my code passed the test cases that contains positive value (first test case) but failed in test cases containing negative values(second test case).
Update:-
I replaced stringbuffer with Integer[] and made few changes.it works fine for smaller inputs of length 8 or 9. How to make it fast for larger inputs of length 13 to 15?
Have you tried doing the process using an array of integers?
Scanner sc = new Scanner(System.in);
String s = sc.nextLine(); //The numbers entered in string format separated by spaces
String ss = s.split(" "); //Numbers separated by space will be put as individual numbers in a String array but each number is still in string format
int l = ss.length, i = 0;
int[] n = new int[l]; //The integer array which will store the values
for(i = 0; i < l; i++)
{
n[i] = Integer.parseInt(ss[i]); //Has integers now instead of string numbers
}
There might be creation of a few extra arrays but then calling the Character.getNumericValue() function repeatedly can also reduce efficiency. Also might solve your StringBuffer problem.
But SkillRack is very annoying anyway.
Your comparison isn't finding adjacent numbers for negative values.
For example: Abs(-2) - (-3) = 5 but -2 and -3 should be adjacent.
Ok. I see you're parsing - and digit separately.
Given the requirement of what a snake sequence is, the longest snake sequence for "5 6 7 9 8 8" is "5 6 7". The output listed above does not correspond to the definition: " adjacent numbers such that for each number, the number on the right or left is +1 or -1 of it's value". How does "5 6 7 8 9 8" meet the definition of snake sequence for "5 6 7 9 8 8"? Sorry I couldn't help.
You might want to parse the code into Integers, store the longest sequences in a map).
#Test
public void testSnake(){
String t2 = "9 8 7 5 3 0 1 -2 -3 1 2";
List<String> numsStr = Arrays.asList(t2.split(" "));
List<Integer> nums = new ArrayList();
HashMap<Integer,List<Integer> > numMap = new HashMap();
numsStr.forEach((s) -> {
Integer val = Integer.decode(s);
nums.add(val);
});
nums.forEach((num) -> {
System.out.println("num: " + num);
// track longest sequence, store in numMap
});
// Print numMap
}

Categories