How to define number sequence in string? - java

I have a task to create a string with a non-defined length (input digits from the keyboard until the user presses "Enter"), then I have to define how many of digits are in sequence. Unfortunately I can't handle this. I think I'm almost there but I'm not. I've created the string which I hoped to copy character by character to an array and then compare each digit with the next one, but I have trouble with copying characters into an array.
Here's my code:
int sum = 0;
String someSymbols = sc.nextLine();
int array [] = new int[someSymbols.length()];
for(int i=0; i<someSymbols.length(); i++){
for (int j=0; j<=array.length; j++){
array[j] = someSymbols.charAt(i);
}
sum++;
}

Not sure of what you want to achieve but here are 2 examples for inspiration:
Taking digits until reaching a different digit. Ignoring non digits
String s = "22u223r5";
String digitsOnly = s.replaceAll("[^\\d.]", "");
int firstDifferentDigit = -1;
for(int i = 1; i < digitsOnly.length(); i++) {
if(digitsOnly.charAt(i) != digitsOnly.charAt(i-1)) {
firstDifferentDigit = i;
break;
}
}
System.out.println("firstDifferentDigit:"+firstDifferentDigit);
System.out.println(digitsOnly.substring(0,firstDifferentDigit));
Outputs
firstDifferentDigit:4
2222
Taking digits until first non digit
String s = "124g35h6j3lk4kj56";
int firstNonDigitCharacter = -1;
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) < '0' || s.charAt(i) > '9') {
firstNonDigitCharacter = i;
break;
}
}
System.out.println("firstNonDigitCharacter:"+firstNonDigitCharacter);
System.out.println(s.substring(0,firstNonDigitCharacter));
Outputs
firstNonDigitCharacter:3
124
EDIT
This works for how you described the exercise:
String someSymbols = "72745123";
List<String> sequences = new ArrayList<>();
boolean inSequence = false; // will flag if we are currently within a sequence
StringBuilder currentSequence = new StringBuilder(); // this will store the numbers of the sequence
for(int i = 0; i < someSymbols.length(); i++) {
char currentChar = someSymbols.charAt(i);
char nextChar = 0;
if(i < someSymbols.length()-1)
nextChar = someSymbols.charAt(i+1);
// if next number is 1 more than the current one, we are in a sequence
if(currentChar == nextChar-1) {
inSequence = true;
currentSequence.append(String.valueOf(currentChar));
// if next number is NOT 1 more than the current one and we are in a sequence, it is the last of the sequence
} else if(inSequence) {
currentSequence.append(String.valueOf(currentChar));
sequences.add(currentSequence.toString());
currentSequence = new StringBuilder();
inSequence = false;
}
}
System.out.println(sequences);
Outputs
[45, 123]

Thanks a lot! I made it with your help! It turns out that the task was to count how many numbers occur in the string of any symbols. As simple as that. My bad! But I'm grateful to be part of this forum :)
Here's the code:
String f = sc.nextLine();
int count = 0;
for(int i=0; i<f.length(); i++){
if((f.charAt(i)>='0') && (f.charAt(i)<='9')){
count++;
}
}
System.out.println("The numbers in the row are : " + count);

I deleted my first answer, because I got the question wrong, thought it's about a character sequence, of which some happen to be digits.
Trying to wrap my head around the new functional style in Java8, but conversion is complicated and full of pitfalls. Surely, this isn't canonical. I guess a collector could be appropriate here, but I broke out and made half of the work in an recursive method.
import java.util.*;
import java.util.stream.*;
String s = "123534567321468"
List<Integer> li = IntStream.range (0, s.length()-2).filter (i -> (s.charAt(i+1) != s.charAt(i)+1)).collect (ArrayList::new, List::add, List::addAll);
li.add (s.length()-1);
int maxDiff (int last, List<Integer> li , int maxdiff) {
if (li.isEmpty ())
return maxdiff;
return maxDiff (li.get(0), li.subList (1, li.size () - 1), Math.max (li.get(0) - last, maxdiff));
}
int result = maxDiff (0, li, 0);
It starts elegantly.
IntStream.range (0, s.length()-2).filter (i -> (s.charAt(i+1) != s.charAt(i)+1))
| Expression value is: java.util.stream.IntPipeline$9#5ce81285
| assigned to temporary variable $20 of type IntStream
-> $20.forEach (i -> System.out.println (i));
2
3
8
9
10
11
12
That's the List of indexes, where chains of numbers are broken.
String s = "123534567321468"
123 is from 0 to 2, 5 is just 3, 34567, the later winner from 4 to 8, ...
Note that we needn't transform the String into Numbers, since the characters are chained in ASCII or UTF-X one by one, like numbers.
To convert it into a List, the complicated collect method is used, because Array of primitive int doesn't work well with List .
For the last interval, li.add (s.length()-1) has to be added - adding elements wouldn't work with array.
maxDiff protocolls the max so far, the last element and repeatedly takes the head from the list, to compare it with the last element to build the current difference.
The Code was testet in the jshell of Java9, which is an amazing tool and needs no embedding class, nor 'main' for snippets. :)
Just for comparison, this is my solution in scala:
val s = "123534567321468"
val cuts = (0 to s.length-2).filter (i => {s.charAt(i+1) != s.charAt(i)+1}).toList ::: s.length-1 :: Nil
(0 :: cuts).sliding (2, 1).map {p => p(1) - p(0)}.max
Sliding(a,b) defines a window of width a=2 which moves forward by b=1.

Related

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.

Maximum repeating sequence instead of longest repeating sequence

I am trying to get the most repeated sequence of characters in a string.
For example :
Input:
s = "abccbaabccba"
Output:
2
I have used dynamic programming to figure out the repeating sequence, but this returns the longest repeating character sequence. For example:
Input:
s = "abcabcabcabc"
Output:
2
2(abcabc,abcabc) instead of 4(abc,abc,abc,abc)
Here is the part of the code where I'm filling the DP table and extracting repeating sequence. Can anyone suggest how I can get the most repeating sequence?
//Run through the string and fill the DP table.
char[] chars = s.toCharArray();
for(int i = 1; i <= length; i++){
for(int j = 1; j <= length; j++){
if( chars[i-1] == chars[j-1] && Math.abs(i-j) > table[i-1][j-1]){
table[i][j] = table[i-1][j-1] + 1;
if(table[i][j] > max_length_sub){
max_length_sub = table[i][j];
array_index = Math.min(i, j);
}
}else{
table[i][j] = 0;
}
}
}
//Check if there was a repeating sequence and return the number of times it occurred.
if( max_length_sub > 0 ){
String temp = s;
String subSeq = "";
for(int i = (array_index - max_length_sub); i< max_length_sub; i++){
subSeq = subSeq + s.charAt(i);
}
System.out.println( subSeq );
Pattern pattern = Pattern.compile(subSeq);
Matcher matcher = pattern.matcher(s);
int count = 0;
while (matcher.find())
count++;
// To find left overs - doesn't seem to matter
String[] splits = temp.split(subSeq);
if (splits.length == 0){
return count;
}else{
return 0;
}
}
Simple and dump, the the smallest sequence to be considered is a pair of characters (*):
loop over the whole String an get every consecutive pair of characters, like using a for and substring to get the characters;
count the occurrence of that pair in the String, create a method countOccurrences() using indexof(String, int) or regular expressions; and
store the greatest count, use one variable maxCount outside the loop and an if to check if the actual count is greater (or Math.max())
(*) if "abc" occurs 5 times, than "ab" (and "bc") will occur at least 5 times too - so it is enough to search just for "ab" and "bc", not need to check "abc"
Edit without leftovers, see comments, summary:
check if the first character is repeated over the whole string, if not
check if the 2 initial characters are repeated all over, if not
check if the 3 ...
at least 2 counters/loops needed: one for the number of characters to test, second for the position being tested. Some arithmetic could be used to improve performance: the length of the string must be divisible by the number of repeated characters without remainder.

Algorithm for combinatorics (6 choose 2)

Following this question, I want to now code "6 choose 2" times "4 choose 2." By that I mean, lets say I have 6 characters "A B C D E F." The first time I choose any two characters to delete. The 2nd time I want to choose 2 different letters to delete and then I append the results of these two trials. Hence, I will receive 90("6 choose 2" times "4 choose 2") eight character strings. The characters in the pattern are from the same pattern {1,2,3,4,5, 6}. All the characters are unique and no repetition.
Here is what I have so far.
public String[] genDelPatterns(String design){
char[] data = design.toCharArray();
String[] deletionPatterns = new String[15];
int x = 0;
StringBuilder sb = new StringBuilder("");
int index = 0;
for(int i = 0; i < (6-1); i++){
for(int j = i+1; j < 6; j++){
for(int k= 0; k < 6; k++){
if((k != j) && (k != i))
sb.append(String.valueOf(data[k]));
}
deletionPatterns[x++] = sb.toString();
sb = new StringBuilder("");
}
}
return deletionPatterns;
}
public String[] gen8String(String[] pattern1, String[] pattern2){
String[] combinedPatterns = new String[225];
int k = 0;
for(int i = 0; i < 15; i++)
{
for(int j = 0; j < 15; j++)
combinedPatterns[k++] = pattern1[i] + pattern2[j];
}
return combinedPatterns;
}
I will be calling the methods like this:
gen8String(genDelPatterns("143256"), genDelPatterns("254316"));
Currently, I am generating all the possible 8 letter strings. But I want to only generate the 8 character strings according to the aforementioned specifications. I am really stuck on how I can elegantly do this multiplication. The only way I can think of is to make another method that does "4 choose 2" and then combine the 2 string arrays. But this seems very roundabout.
EDIT: An example of an 8 character string would be something like "14322516", given the inputs I have already entered when calling gen8String, (143256,254316). Note that the first 4 characters are derived from 143256 with the 5 and 6 deleted. But since I deleted 5 and 6 in the first trail, I am no longer allowed to delete the same things in the 2nd pattern. Hence, I deleted the 3 and 4 from the 2nd pattern.
you have a chain of methods , each one called a variation itself.
For so, my advice is to use a recursive method!
to achieve your goal you have to have a little experience with this solution.
A simple example of a method that exploits the recursion:
public static long factorial(int n) {
if (n == 1) return 1;
return n * factorial(n-1);
}
I can also suggest you to pass objects (constructed to perfection) for the method parameter, if is too complex to pass simple variables
This is the heart of this solution in my opinion.
While what you tried to do is definitely working, it seems you are looking for other way to implement it. Here is the skeleton of what I would do given the small constrains.
// Very pseudo code
// FOR(x,y,z) := for(int x=y; x<z;x++)
string removeCharacter(string s, int banA, int banB){
string ret = "";
FOR(i,1,7){
if(i != banA && i != banB){
ret += s[i];
}
}
return ret;
}
List<string> Generate(s1,s2){
List<string> ret = new List<string>();
FOR(i,1,7) FOR(j,i+1,7) FOR(m,1,7) FOR(n,m+1,7){
if(m != i && m != j && n != i && n != j){
string firstHalf = removeCharacter(s1,i,j);
string secondHalf = removeCharacter(s2,m,n);
ret.Add(firstHalf + secondHalf);
}
}
return ret;
}
This should generate all possible 8-characters string.
Here is the solution I came up with. Doesn't really take "mathematical" approach, I guess. But it does the job.
//generating a subset of 90 eight character strings (unique deletion patterns)
public static String[] gen8String(String[] pattern1, String[] pattern2){
String[] combinedSubset = new String[90]; //emty array for the subset of 90 strings
String combinedString = ""; //string holder for each combined string
int index = 0; //used for combinedSubset array
int present = 0; //used to check if all 6 characters are present
for(int i = 0; i < 15; i++){
for(int j = 0; j < 15; j++){
combinedString = pattern1[i] + pattern2[j]; //combine both 4 letter strings into 8 char length string
char[] parsedString = combinedString.toCharArray(); //parse into array
//check if all 6 characters are present
for(int k = 1; k <= 6; k++)
{
if(new String(parsedString).contains(k+"")) {
present++;
}
else
break;
//if all 6 are present, then add it to combined subset
if(present == 6)
combinedSubset[index++] = combinedString;
}
present = 0;
}
}
return combinedSubset;
}

Matching subsequence of length 2 (at same index) in two strings

Given 2 strings, a and b, return the number of the positions where they contain the same length 2 substring. For instance a and b is respectively "xxcaazz" and "xxbaaz" yields 3, since the "xx", "aa", and "az" substrings appear in the same place in both strings.
What is wrong with my solution?
int count=0;
for(int i=0;i<a.length();i++)
{
for(int u=i; u<b.length(); u++)
{
String aSub=a.substring(i,i+1);
String bSub=b.substring(u,u+1);
if(aSub.equals(bSub))
count++;
}
}
return count;
}
In order to fix your solution, you really don't need the inner loop. Since the index should be same for the substrings in both string, only one loop is needed.
Also, you should iterate till 2nd last character of the smaller string, to avoid IndexOutOfBounds. And for substring, give i+2 as second argument instead.
Overall, you would have to change your code to something like this:
int count=0;
for(int i=0; i < small(a, b).length()-1; i++)
{
String aSub=a.substring(i,i+2);
String bSub=b.substring(i,i+2);
if(aSub.equals(bSub))
count++;
}
}
return count;
Why I asked about the length of string is, it might become expensive to create substrings of length 2 in loop. For length n of smaller string, you would be creating 2 * n substrings.
I would rather not create substring, and just match character by character, while keeping track of whether previous character matched or not. This will work perfectly fine in your case, as length of substring to match is 2. Code would be like:
String a = "iaxxai";
String b = "aaxxaaxx";
boolean lastCharacterMatch = false;
int count = 0;
for (int i = 0; i < Math.min(a.length(), b.length()); i++) {
if (a.charAt(i) == b.charAt(i)) {
if (lastCharacterMatch) {
count++;
} else {
lastCharacterMatch = true;
}
} else {
lastCharacterMatch = false;
}
}
System.out.println(count);
The heart of the problem lies with your usage of the substring method. The important thing to note is that the beginning index is inclusive, and the end index is exclusive.
As an example, dissecting your usage, String aSub=a.substring(i,i+1); in the first iteration of the loop i = 0 so this line is then String aSub=a.substring(0,1); From the javadocs, and my explanation above, this would result in a substring from the first character to the first character or String aSub="x"; Changing this to i+2 and u+2 will get you the desired behavior but beware of index out of bounds errors with the way your loops are currently written.
String a = "xxcaazz";
String b = "xxbaaz";
int count = 0;
for (int i = 0; i < (a.length() > b.length() ? b : a).length() - 1; i++) {
String aSub = a.substring(i, i + 2);
String bSub = b.substring(i, i + 2);
if (aSub.equals(bSub)) {
count++;
}
}
System.out.println(count);

Java reading in a string and converting numbers in strings into Integers types

I am trying to take numbers from a users string (if it has numbers) and convert those numbers to their numerical value. I have the following code which takes in user input.
Ex: java Convert "55s" will just output the number 55, which i will store for later usage
{
char Element = 0;
double Sum = 0;
boolean Check = false;
for(String s: args) // taking in user input for command line
{
for (int i = 0; i<s.length(); i++)
{
Check = true;
Element = s.charAt(i); // converting the string into chars
Sum = convert_to_numb (Element, Check);
Check = false;
}
}
The input is a string in which i separate into chars and send it to my conversion functions. The idea i have follows
public static double convert_to_numb (char elem, boolean check) //trying to convert chars to numbers
{
char iter = elem;
double number = 0;
int count = 0;
while (check == true)
{
number = number + (iter - 48) * Math.pow(10,count);
System.out.println(iter);
count ++;
}
return number;
}
Here I am feeding in the chars to see if they're numbers and convert the actual numbers into their integer value. To try to clarify i would like to perform the following task given an example input of "55" covert it to 5*10^1 + 5*10^0 = 55. I would appreciate any help. Thanks.
Alright, I think I might know what you're trying to accomplish, though as others have mentioned it is a little unclear.
To address the code you just posted, I don't think it'll behave the way you expect. For starters, the Boolean variable 'Check' accomplishes nothing at the moment. convert_to_numb is only called while Check is true, so it's redundant.
Additionally, the sum isn't being stored anywhere as you loop through the string. Every time you obtain a sum, it overwrites the previous one.
Your convert_to_numb method is even more troubling; it contains an infinite loop. Since Check is always set to 'true', you essentially have a while(true) loop that will never end.
I'm going to assume that your objective here is to parse whichever Strings are input into the program looking for groups of consecutive digits. Then you want to store these groups of digits as integers, perhaps in an array if you find multiple.
Something like this might do the trick.
{
ArrayList<Integer> discovered = new ArrayList<Integer>();
for (String s : args) {
// contains previous consecutive digits (if any)
ArrayList<Integer> digits = new ArrayList<Integer>();
for (int i = 0; i < s.length(); i++) {
Character c = s.charAt(i);
// add digit to digit array
if (c.isDigit()) {
digits.add(c.getNumericValue())
}
// not a digit, so we clear the digit array
else {
// combine the array to form an integer
if (! digits.isEmpty()) {
int sum = 0;
int counter = 0;
for (Integer i : digits) {
sum += i * Math.pow(10, counter);
counter++;
}
discovered.add(sum);
digits.clear();
}
}
}
}
}
Note the use of ArrayLists and the Integer and Character wrapper classes. These all provide functionality that helps deal with edge-cases. For example, I'm not sure that (iter - 48) part would have worked in all cases.
Something like this:
public static void main(String[] args) {
String string = "55s";
String[] piece = string.split("[\\D]+");
for (int j = 0; j < piece.length; j++) {
if(piece[j].trim().length() > 0) {
System.out.println(piece[j]);
}
}
}
It will split your initial string, the rest you should do yourself.

Categories

Resources