Java: Longest Ascending substring - java

I am trying to create a Java program that reads a numerical string typed from the keyboard,
and gives out the longest ascending substring.
The following is my code:
import java.util.Scanner;
public class Ascending{
public static void main(String args[]){
Scanner in = new Scanner(System.in);
System.out.print("Enter a number = ");
String n = in.nextLine();
int length = n.length();
for(int i = 0; i < length; i++) {
char first = n.charAt(i);
char next = n.charAt(i+1);
char last = n.charAt(length-1);
int f = (int)(first - 48);
int nx = (int)(next - 48);
int l = (int)(last - 48);
if (f<nx) {
String asc = n.substring(i, i++);
i++;
System.out.println("output = " + asc);
}
else {
String asc = n.substring(i, i++);
System.out.println("output = " + asc);
break;}
}
}
}
When I compile the above, I get
<Enter a number = 12 output = >
without any results.
I am assuming something went wrong inside the for-loop but I am unable to figure out where exactly I went wrong.
I'm afraid I might have defined too many unnecessary variables?

You are using the post-increment operator, but I don't think you have experimented to see how it works. Try this:
int i = 0;
System.out.println(i);
System.out.println(i++);
System.out.println(i);
You'll get
0
0
1
That's because post-increment (++) says "increment this value, then return what the value was before you incremented it".
So when you ask for
n.substring(i, i++);
You are explicitly asking for a 0-length string (because i == i++).
You could use the pre-increment operator, ++i, but it's rarely used outside of code-golf so you'll just end up confusing people. Best practice IMO is to just use ++ on its own line and avoid looking at the return value.
Really, what you want here is
n.substring(i, i+1);

Related

Finding the nth term in a sequence

I have a sequence, and I am trying to make a program to find the nth term of the sequence.
The sequence is as follows:
1, 11, 21, 1211, 111221, 312211...
In this sequence, each term describes the previous term. For example, "1211" means that the previous term; the previous term is "21" where there is one occurrence of a 2 and then one occurrence of a 1 (=1211). To get the third term, "21," you look at the second term: 11. There are two occurrences of a 1 which gives us "21."
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
System.out.println( Main.num(n-1, "1"));
}
public static String num(int times, String x){
if(times == 0){
return x;
}else{
//System.out.println("meow");
String y = "" + x.charAt(0);
int counter = 0;
for(int i = 1; i < x.length(); i++){
if(x.charAt(i) == x.charAt(i-1)){
counter++;
}else{
y += "" + counter + x.charAt(i-1);
counter = 0;
}
}
return num(times--, y);
}
//return "";
}
}
My code uses recursion to find the nth term. But, it gives us errors :(
First, I start of the method "num" by passing it the number of terms-1 (since the first term is already given) and the first term (1).
In the method num, we start off by using a conditional to establish the base case (when you are done finding the nth term).
If the base case is false, then you find the next term in the sequence.
This is a very cool sequence! I like that it is English based and not mathematical, haha. (Though now I wonder ... is there a formula we could make for the nth term? I'm pretty sure it's impossible or uses some crazy-level math, but just something to think about ...)
In your solution, the recursive logic of your code is correct: after you find each term, you repeat the method with your knew number and find the next term using that element, and end when you have determined the first n elements. Your base case is also correct.
However, the algorithm you developed for determining the terms in the sequence is the issue.
To determine the next element in the sequence, we want to:
Logical Error:
Create a empty variable, y, for your next element. The variable, counter, should not start at 0, however. This is because every element will ALWAYS have an occurrence of at least 1, so we should initialize int counter = 1;
Iterate through the characters in x. (You did this step correctly) We begin at i = 1, because we compare each character to the previous one.
If the current character is equal to the previous character, we increment counter by 1.
Otherwise, we concatenate counter and the character being repeated, to y. Remember, to reinitialize counter to 1, not 0.
Technical Errors:
Once we reach the end of iterating x, we need to concatenate our final counter and character to y, since the else statement for the final characters will never run in our for loop.
This is done with the following code: y += "" + counter + x.charAt(x.length() - 1);
Finally, when you are doing your recursive call, you should do --times instead of times--. The difference between these two parameters is that with your original code, you are post-decrementing. This means the value of times is decreasing after the method call, when we want the decreased value to be sent into the method. To solve this, we need to pre-decrement, by doing --times.
import java.util.*;
class CoolSequence {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
System.out.println(num(n, "1"));
}
public static String num(int times, String x){
if(times == 0){
return x;
}
else{
String y = "";
int counter = 1;
for(int i = 1; i < x.length(); i++){
if(x.charAt(i) == x.charAt(i - 1)){
counter++;
}
else{
y += "" + counter + x.charAt(i - 1);
counter = 1;
}
}
y += "" + counter + x.charAt(x.length() - 1);
return num(--times, y);
}
}
}
Testing:
6
13112221
An alternative approach would be using an iterative method:
import java.util.*;
class CoolSequence2 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
ArrayList<String> nums = new ArrayList<String>();
int n = scan.nextInt();
String val = "1";
for(int i = 0; i < n; i++){
String copy = val;
val = "";
while(!copy.equals("")){
char curr = copy.charAt(0);
int ind = 0;
int cons = 0;
while(ind < copy.length() && curr == copy.charAt(ind)){
cons += 1;
ind += 1;
}
val += String.valueOf(cons) + copy.charAt(cons - 1);
copy = copy.substring(cons);
}
nums.add(val);
}
System.out.println(nums.get(nums.size() - 1));
}
}
6
13112221
In this method, we use a for loop to iterate through n terms. To determine each element, we do a similar method to your logic:
We create an empty string, val, to hold the new element, and store our current element in copy. We also initialize a cons, similar to your counter.
While copy is not empty, we iterate through copy and increment cons until there is an element that is not equal to the next element.
When this occurs, we concatenate cons and the repeated element to val, like in your code. Then, we cut out the repeated elements from copy and continue the process.
We add the new value of val to nums, and keep iterating through the n elements.
I hope these two methods of approaching your problem helped! Please let me know if you have any further questions or clarifications :)
You can use Pattern with backreference.
The regular expression "(.)\\1*" matches any single character ("(.)") and zero or more sequences of the same character ("\\1*"). "\\1" is called a backreference, it refers to the string enclosed in parentheses 1st.
For example, it matches 111, 22 and 1 for 111221.
replaceAll() calls the lambda expression specified by the argument each time it matches. The lambda expression receives a MatchResult and returns a string. The matched string is replaced with the result.
The lambda expression in this case concatenates the length of the matched string (match.group().length()) and the first character (match.group(1)).
static final Pattern SEQUENCE_OF_SAME_CHARACTER = Pattern.compile("(.)\\1*");
static String num(int times, String x) {
for (int i = 0; i < times; ++i)
x = SEQUENCE_OF_SAME_CHARACTER.matcher(x).replaceAll(
match -> match.group().length() + match.group(1));
return x;
}
public static void main(String[] args) {
for (int i = 1; i <= 8; ++i)
System.out.print(num(i - 1, "1") + " ");
}
output:
1 11 21 1211 111221 312211 13112221 1113213211

How to increment conditionally?

so im a complete beginner and I was wondering if it was possible to increment a counter conditionally. I am trying to count the letter “I” in a sentence and everytime i pass an “I”, i want counter to increment by 1 but if there is more than 1 of these together “III” it still only increments by 1 until there a character after it like “IIIaI” which would count as 2 instances.
Is this possible?
Sorry guys, here is my code:
public static int countTheIs(string sentence){
int iCounter = 0;
String iCount = "iI"; //both cases included
for (int j = 0; j < sentence.length(); j++){
char ch =sentence.charAt(j);
if (iCount.indexOf(ch) != -1){
iCounter++;
}
}
}
You are actually quite far already, all you need to do is to check the previous character. This can be done the following way:
String sentence = "Test i two II three iIi";
int iCounter = 0;
String iCount = "iI";
for (int j = 0; j < sentence.length(); j++){
char current = sentence.charAt(j);
char previous; //1
if (j==0) {
previous = 'Z'; //2
} else {
previous = sentence.charAt(j-1); //3
}
if (iCount.indexOf(current) != -1 && iCount.indexOf(previous) == -1 ){ //4
iCounter++;
}
}
Let me explain to you what I have done, according to my // tags
//1 We make a new char variable holding the previous character.
//2 Because the first index of the String has no previous characters, we will set it to a random, non-matching character to prevent errors at the start. I picked Z in this example.
//3 If there is a previous character, we get this by subtracting 1 from j
//4 We check in the if statement if the currenct character is in iCount, and the previous character is not in iCount. If this is the case, the counter will increase.
When the above code is ran, the result will output 3.
OK, I'm going to assume that you have a string input, you are counting by using a loop and then using charAt(x)(x is the number you use to increment the loop) and then comparing.
Simply check if charAt(x-1) is also I. If it is, then don't increment i. Also, you want to make sure x>0 otherwise it will throw an error.
Please run the below code:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CountI {
public static void main(String[] args) {
String input = "IIiaIii";
String regex = "([A-Za-z])\\1+";
Pattern pattern = Pattern.compile(regex , Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(input);
String output = matcher.replaceAll("$1");
int result = 0;
for(int i = 0; i < output.length(); i++){
if(output.charAt(i) == 73 || output.charAt(i) == 105){
result++;
}
}
System.out.println(result);
}
}
Output:
2
Process finished with exit code 0
You want Regular Expressions and the Java Pattern class (https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html).
In my sample below I used "w" instead of "l" because it's easier to distinguish. Using regular expressions, define a pattern that will capture one or more consecutive occurrences of the letter: w+, then use a matcher, count the number of times it matches.
String input = "wwowwee w w w";
Pattern p = Pattern.compile("w+");
Matcher matcher = p.matcher(input);
int count = 0;
while(matcher.find()) {
count++;
}
System.out.println("Count: " + count);
Or, simply split the string and count the number of splits:
String input = "wwowwee w w w";
Pattern p = Pattern.compile("w+");
String[] tokens = p.split(input);
System.out.println("token count: " + tokens.length);
Both give the correct results.
Edit: This doesn't answer the question about incrementing a counter conditionally, but it solves the problem that question was posed to address.

The loop runs twice in a single run

This problem is from https://www.hackerrank.com/ and link to it is https://www.hackerrank.com/challenges/java-list/problem .
In the below code while loop is running twice as according to question we need to enter Q, Q times an operation to perform in the Array Declared. For this, i am running twice the loop so that I can get the desired result.
import java.util.*;
public class javaList {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int i, x;
ArrayList L = new ArrayList(N);
for (i = 0; i < N; i++) {
L.add(sc.nextInt());
}
int Q = sc.nextInt();
i = 0;
// for normal running i have multiplied Q by 2 so that i can get the results
while (i < Q * 2) {
System.out.println("Loop: " + i);
String s = sc.nextLine();
int sz = L.size();
// code for checking insert
if (s.equals("Insert")) {
x = sc.nextInt();
int y = sc.nextInt();
//if the position i am looking exists then just replace
// i need to insert at index x of array L but array.size() gives one more than the last index
if ((sz - 1) >= x) {
L.add(x, y);
}
//if the position i am looking does not exist then create
else {
for (int j = sz; j <= x; j++) {
//add number to desired place
if (j == x)
L.add(y);
//in between the two endings of array and insertion adding default value 0
else
L.add(0);
}
}
//checking code for Delete
} else if (s.equals("Delete")) {
x = sc.nextInt();
//if the desired location exists then only replace
if ((sz - 1) >= x) {
L.remove(x);
}
}
i++;
}
for (i = 0; i < L.size(); i++) {
System.out.print(L.get(i) + " ");
}
}
}
I want to Know why the loop is running twice in a single run.
So, from discussion in the comments, you've stated that your question is:
if Q = 2 then it should ask operations Insert or Delete 4 times as of my code. But it asks only 2 times. Simply that is my problem
First, you may not fully understand your own program flow. Before the while loop, you need to enter three sets of values, a value for N, values for L, and a value for Q.
Once you enter your while loop, you will be prompted for a value for s (which it seems you intend to be either "Insert" or "Delete"). However, the first time around, it will get an empty string and s will be "\n". Why? Because for N, L, and Q, the user will enter values as follows:
[value] [ENTER]
The return key is itself a value. So, in the input buffer (assuming Q = 2), is "2\n". When your code runs to get s String s = sc.nextLine(); it will see the next line symbol and skip prompting user for input.
Because s is not "Insert" or "Delete", it will skip those the first time around. You will then be prompted to enter a value for "s" after the start next loop.
To help you realize what's going on, I suggest adding statements everywhere you ask users to enter a value, like System.out.println("Enter a value for Q:");
This will help you keep track of program flow.
Your code is waaay to complicated. Try this:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
List<Integer> list = new ArrayList<>();
for (int i = 0, n = scanner.nextInt(); i < n; i++) {
list.add(scanner.nextInt());
}
for (int i = 0, n = scanner.nextInt(); i < n; i++) {
if (scanner.next().equals("Insert")) {
list.add(scanner.nextInt(), scanner.nextInt());
} else {
list.remove(scanner.nextInt());
}
}
String result = list.stream()
.map(String::valueOf)
.collect(Collectors.joining(" "));
System.out.println(result);
}

Questions about array

Here is my code and it works perfectly fine.
import java.util.Random;
class apples
{
public static void main(String args[])
{
Random rand = new Random();
int frequency[] = new int[7];
for(int roll = 1;roll < 1000;roll++){
++frequency[1+rand.nextInt(6)];
}
System.out.println("Face\tFrequency");
for(int face = 1;face < frequency.length;face++){
System.out.println(face + "\t" + frequency[face]);
}
}
}
I do not understand this line of code
++frequency[1+rand.nextInt(6)];
When I removed the "++" operator, it couldn't be compiled. I know that it will add 1 to the randon numbers generated from 0 to 5 but why there is a "++" in front of frequency ? Why is it neccessary to put the "++" operator there ?
The ++ operator is incrementing the frequency at the specified index. In this case, it's the same as saying:
for(int roll = 1;roll < 1000;roll++){
int index = 1+rand.nextInt(6);
frequency[index] = frequency[index] + 1;
}
Removing the ++ operator, you're left with:
for(int roll = 1;roll < 1000;roll++){
frequency[1+rand.nextInt(6)];
}
The line frequency[1+rand.nextInt(6)] makes no sense; it is not an operation, it does not do anything.
EDIT:
Perhaps a better illustration: let x be the value looked up in the frequency array. Then the original is equivalent to:
for(int roll = 1;roll < 1000;roll++){
int x = frequency[1+rand.nextInt(6)];
++x; // Equivalent to "x = x + 1"
}
Whereas if you remove the increment operator, your resulting loop would be:
for(int roll = 1;roll < 1000;roll++){
int x = frequency[1+rand.nextInt(6)];
x; // ...what?
}
The statement without the ++ looks at the contents of the array, but does not do anything with the value. Adding the ++ operator tells it to increment the value found there.
You probably are thinking that frequency[1+rand.nextInt(6)] is adding a value to the array. It is not. It is looking up a location in memory from a random location.
++ is a shorthand for
int i = 1+rand.nextInt(6);
frequency[i] = frequency[i] + 1;
Removing it causes no increment expression is executed.
that line is equivalent to this line of code
int index = 1+rand.nextInt(6);
frequency[index] = frequency[index]+1 ;
so if you removed '++' you make the statement incomplete like the following:
int x= 5;
x;
so it gives you error

not a statement error, illegal start of type

import java.util.*;
public class ulang {
public static void main(final String[] args) {
int a;
int b;
int sum;
Scanner scan = new Scanner(System.in);
System.out.println("Enter num 1: ");
a = in.nextLine();
System.out.println("Enter num 2: ");
b = in.nextLine();
{
sum = a + b;
}
for (i = 0; i < 5; i++) {
(sum >= 10)
System.out.println("Congratulations");
else
System.out.println("Sum of the number is Less than 10");
}
}
}
I'm weak on looping especially in Java. So I need some corrections on my coding, but I have no idea how to fix it.
The coding should run like this: User need to insert 2 numbers and the program will calculate the sum of both number. After that, the program will determine if the total of sum is >=10 or <10. If the sum >=10, "Congratulations" will appear but if it is <10, then "The sum of number less than 10" will appear. How to fix it?
This is the immediate problem:
(sum>=10)
I believe you meant that to be an if statement:
if (sum>=10)
Additionally:
You're trying to use an in variable, but the Scanner variable is called scan
Scanner.nextLine() returns a String - I suspect you wanted Scanner.nextInt()
Your for loop uses a variable that hasn't been declared. You probably meant:
for (int i = 0; i < 5; i++)
A few other suggestions though:
The sum isn't going to change between the loop iterations... why are you looping at all?
You've got a new block in which you're calculating the sum, but for no obvious reason. Why?
It's generally a good idea to declare variables at the point of initialization, e.g.
Scanner scan = new Scanner(System.in);
System.out.println("Enter num 1: ");
int a = scan.nextInt();
System.out.println("Enter num 2: ");
int b = scan.nextInt();
int sum = a + b;
Given that you want to take the same basic action (writing a message to the screen) whether or not the user was successful, you might consider using the conditional operator like this:
String message = sum >= 10 ? "Congratulations"
: "Sum of the number is Less than 10";
System.out.println(message);
That would then allow you to refactor the loop to only evaluate the condition once:
String message = sum >= 10 ? "Congratulations"
: "Sum of the number is Less than 10";
for (int i = 0; i < 5; i++)
{
System.out.println(message);
}
(sum>=10)
This line needs an if at the beginning, or it won't be read as a branch.
if (sum >= 10)
You also should name your main-class Ulang, because java class identifiers should start with an upper case letter, for readability.
The loop should look like the following:
for (int i = 0; i < 5; i++) {
The first part defines the counter and assigns zero to it. The second is your condition and the last counts for you.
for (int i = 0; i < 5; i++) {
if (sum >= 10)
System.out.println("Congratulations");
else
System.out.println("Sum of the number is Less than 10");
}

Categories

Resources