Identifying and collecting consecutive ranges from an array [duplicate] - java

This question already has answers here:
How do I convert from int to String?
(20 answers)
Closed 1 year ago.
Task
Given int[] arrays such as I have to identify consecutive ranges and build a corresponding String
Another example would be
Notes
I can assume that the array is already ordered and there are no overlaps in the ranges.
Also, the array might be empty.
Ideas
I know how to build a string that just lists all numbers, like 4, 5, 6, 8, 14, 15, 16 but I have no idea how to identify the ranges and especially how to add a ~ between them.
I thought maybe regex might be usefull here, but I am unsure.

Explanation
You can simply iterate from left to right and maintain ranges while doing so.
For that, just remember the start of a range and the last value in each iteration. Then you can easily figure out if a range just stopped or is continuing. If it stopped, conclude the range and start the next.
For the special case of an empty array, just add a simple if to the start of the method, to handle it separately.
Build ranges
public static String buildRanges(int[] values) {
if (values.length == 0) {
return "";
}
StringJoiner result = new StringJoiner(", ");
int rangeStart = values[0];
int lastValue = values[0];
// Skip first value to simplify 'lastValue' logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (value != lastValue + 1) {
// Range ended, wrap it up
int rangeEnd = lastValue;
result.add(rangeStart == rangeEnd
? Integer.toString(rangeStart)
: rangeStart + "~" + rangeEnd);
rangeStart = value;
}
lastValue = value;
}
// Conclude last range
int rangeEnd = lastValue;
result.add(rangeStart == rangeEnd
? Integer.toString(rangeStart)
: rangeStart + "~" + rangeEnd);
return result.toString();
}
Simplify
To tackle the code duplication and to improve readability, I would suggest to also introduce a helper method rangeToString:
public static String rangeToString(int rangeStart, int rangeEnd) {
return rangeStart == rangeEnd
? Integer.toString(rangeStart)
: rangeStart + "~" + rangeEnd);
}
The code then simplifies to:
public static String buildRanges(int[] values) {
if (values.length == 0) {
return "";
}
StringJoiner result = new StringJoiner(", ");
int rangeStart = values[0];
int lastValue = values[0];
// Skip first value to simplify 'lastValue' logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (value != lastValue + 1) {
// Range ended, wrap it up
result.add(rangeToString(rangeStart, lastValue);
rangeStart = value;
}
lastValue = value;
}
// Conclude last range
result.add(rangeToString(rangeStart, lastValue);
return result.toString();
}
OOP solution
If you feel like, you can also introduce dedicated Range classes to solve this. Might be a bit overkill in this particular situation but still.
Let us first create a Range class that knows its start and end. Furthermore, it can convert itself to a String properly and you can attempt to increase the range.
public final class Range {
private final int start;
private int end;
public Range(int value) {
start = value;
end = value;
}
public boolean add(int value) {
if (value != end + 1) {
return false;
}
end = value;
return true;
}
#Override
public String toString() {
return start == end
? Integer.toString(start)
: start + "~" + end;
}
}
And now you can easily use that in a simple loop:
public static String buildRanges(int[] values) {
if (values.length == 0) {
return "";
}
StringJoiner result = new StringJoiner(", ");
Range range = new Range(values[0]);
// Skip first value to simplify logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (!range.add(value)) {
// Range ended, wrap it up
result.add(range.toString());
range = new Range(value);
}
}
// Conclude last range
result.add(range.toString());
return result.toString();
}
Collecting to List<Range>
This approach has the advantage that you can also collect to something like a List<Range> ranges and then continue working with the data, instead of only going to a String. Example:
public static List<Range> buildRanges(int[] values) {
if (values.length == 0) {
return List.of();
}
List<Range> ranges = new ArrayList<>();
Range range = new Range(values[0]);
// Skip first value to simplify logic
for (int i = 1; i < values.length; i++) {
int value = values[i];
if (!range.add(value)) {
// Range ended, wrap it up
ranges.add(range);
range = new Range(value);
}
}
// Conclude last range
ranges.add(range);
return ranges;
}
In particular useful if you also add some getStart() and getEnd() method to the Range class.
Notes
Note that the method will likely behave funky if the array contains duplicates. You did not specify what to do in that case, so I simply assumed duplicates will not exist for your use case.

Say you have the following Interval class:
public class Interval {
public final int min;
public final int max;
public Interval(int min, int max) {
this.min = min;
this.max = max;
}
public Interval(int minmax) {
this(minmax, minmax);
}
public static List<Interval> toIntervals(int... values) {
List<Interval> list = new ArrayList<>();
for (int val: values) {
addInterval(list, val, val);
}
return list;
}
private static void addInterval(List<Interval> list, int min, int max) {
int i = 0;
while (i < list.size()) {
Interval cur = list.get(i);
if (max < cur.min-1) {
break;
} else if (cur.max >= min-1) {
min = Math.min(min, cur.min);
max = Math.max(max, cur.max);
list.remove(i);
} else {
++i;
}
}
list.add(i, new Interval(min, max));
}
#Override
public String toString() {
if (min == max) {
return Integer.toString(min);
}
return min + "~" + max;
}
}
You can convert the list of numbers in your examples to lists of intervals:
List<Interval> list = Interval.toIntervals(4, 5, 6, 8, 14, 15, 16);
Or:
List<Interval> list = Interval.toIntervals(13, 14, 15, 16, 21, 23, 24, 25, 100);
And print lists like that:
System.out.println(list.stream()
.map(Interval::toString)
.collect(Collectors.joining(", ")));

Try this.
static String summary(int[] input) {
int length = input.length;
if (length == 0) return "";
StringBuilder sb = new StringBuilder();
new Object() {
int start = input[0];
int end = input[0];
String separator = "";
void append() {
sb.append(separator).append(start);
if (start != end)
sb.append("~").append(end);
separator = ", ";
}
void make() {
for (int i = 1; i < length; ++i) {
int current = input[i];
if (current != end + 1) {
append();
start = current;
}
end = current;
}
append();
}
}.make();
return sb.toString();
}
public static void main(String[] args) {
System.out.println(summary(new int[] {4, 5, 6, 8, 14, 15, 16}));
System.out.println(summary(new int[] {13, 14, 15, 16, 21, 23, 24, 25, 100}));
}
output:
4~6, 8, 14~16
13~16, 21, 23~25, 100

It is a int-to-string conversion, not a cast in java sence which means (TYPE2)OBJECTOFTYPE1 for instance int-to-double (widening) or Object-to-String.
The ranges one has to do oneself.
int[] a = {13, 14, 15, 16, 21, 23, 24, 25, 100};
StringBuilder sb = new StringBuilder();
if (a.length > 0) {
for (int i = 0; i < a.length; ++i) {
if (sb.length() != 0) {
sb.append(", ");
}
sb.append(Integer.toString(a[i]));
int rangeI = i;
while (a[i] != Integer.MAX_VALUE && a[i] + 1 == a[i + 1]) {
++i;
}
if (i != rangeI) {
sb.append('~').append(Integer.toString(a[i]));
}
}
}
return sb.toString();
You can do append(a[i]) as there is an overloaded method that does internally a conversion. For clearity not done.
The separation by comma is quite standard.
And for every element check its range of increasing followers.
As java ignores integer overflow, the check on MAX_VALUE.

Convert the integers to strings and append them using the StringBuilder class of Java: https://www.geeksforgeeks.org/stringbuilder-class-in-java-with-examples/
StringBuilder str = new StringBuilder();
and append the numbers and '~' (tilda) sign by using:
str.append(start_number);
str.append('~');
str.append(end_number);

Related

Empty integer array in java

Write a function that takes an array as input and returns an array of 2 numbers. The returned array contains the sum of even numbers and sum of odd numbers from the input.
If any of the input is null it should be treated as an empty array
Example:
Input:
[30, 18, 2, 83, 20, 71]
Output:
[70, 154]
Input:
[14, 11, 10, 67, 41]
Output:
[24, 119]
Input:
[36, 24, -82, 29, 44, -3, -100, -5, 49]
Output:
[-78, 70]
The function that I have written is
public int[] getSumOfEvensAndOdds(int[] input) {
int x[] = input;
int even = 0, odd = 0;
for (int i = 0; i < x.length; i++) {
if (x[i] % 2 == 0)
even += x[i];
else
odd += x[i];
}
int[] ans={even, odd};
return ans;
}
But how should I incorporate the part of the empty array?
Check if input is null first. If it is, work on an empty array instead:
int x[] = input == null ? new int[0] : input;
if any of the input is null it should be treated as an empty array
Why not just check for null value?
public int[] getSumOfEvensAndOdds(int[] input) {
int even = 0, odd = 0;
if(null != input){
for (int i: input) {
if (0 == i % 2){
even += i;
} else{
odd += i;
}
}
}
return new int[]{even, odd};
}
You need something like this:
public class Test {
public static int[] getSumOfEvensAndOdds(int[] input) {
int[] def = {0,0};
if (input != null && input.length!=0) {
int x[] = input;
int even = 0, odd = 0;
for (int i = 0; i < x.length; i++) {
if (x[i] % 2 == 0)
even += x[i];
else
odd += x[i];
}
int[] ans = {even, odd};
return ans;
}
return def;
}
public static void main(String [ ] args){
int[] ar = {10,20,30,40,50,60,71,80,90,91};
int[] res;
res = getSumOfEvensAndOdds(ar);
System.out.println("Result: " + res[0] + " " + res[1]);
int[] ar2 = {};
res = getSumOfEvensAndOdds(ar2);
System.out.println("Result: " + res[0] + " " + res[1]);
int[] ar3 = null;
res = getSumOfEvensAndOdds(ar3);
System.out.println("Result: " + res[0] + " " + res[1]);
}
}
I use input!=null to check whether the array is null and input.length!=0 to check if its size is 0. Also, in the main method I give three examples.
public int[] getSumOfEvensAndOdds(int[] input) {
int x[] = input;
int even = 0, odd = 0;
for (int i = 0; i < x.length; i++) {
if(x[i] != null) //in case array contains elements which aren't null
{
if (x[i] % 2 == 0)
even += x[i];
else
odd += x[i];
}
else //in case the array has null array elements
{
even = 0;
odd = 0;
}
int[] ans={even, odd};
return ans;
}
Empty array may be return like this return new int[]{}
Your question is just about arrays being empty. A quick search got me this: How can I check whether an array is null / empty?

java.lang.StringIndexOutOfBoundsException for the soln

This program is throwing java.lang.StringIndexOutOfBoundsException.
Prime numbers in a single long string: "2357111317192329..."
Test cases
Inputs:
(int) n = 0
Output:
(string) "23571"
Inputs:
(int) n = 3
Output:
(string) "71113"
public class Answer {
public static String answer(int n) {
int i = 0;
int num = 0;
String primeNumbers = "";
char[] ar = new char[5];
for (i = 1; i <= 10000; i++) {
int counter = 0;
for (num = i; num >= 1; num--) {
if (i % num == 0) {
counter = counter + 1;
}
}
if (counter == 2) {
primeNumbers = primeNumbers + i;
}
}
ar[0] = primeNumbers.charAt(n);
ar[1] = primeNumbers.charAt(n + 1);
ar[2] = primeNumbers.charAt(n + 2);
ar[3] = primeNumbers.charAt(n + 3);
ar[4] = primeNumbers.charAt(n + 4);
return String.valueOf(ar);
}
}
try this solution:
public class Answer {
public static String answer(int n) {
StringBuilder primeNumberString = new StringBuilder(0);
int currentPrimeNumber = 2;
while (primeNumberString.length() < n+5) {
primeNumberString.append(currentPrimeNumber);
currentPrimeNumber++;
for (int index = 2; index < currentPrimeNumber; index++) {
if (currentPrimeNumber % index == 0) {
currentPrimeNumber++;
index = 2;
} else {
continue;
}
}
}
return primeNumberString.toString().substring(n, n+5)
}
}
=======================================================
EDIT
The problem statement suggests that the required output from the method you have written should be a string of length 5 and it should be from 'n' to 'n+4'.
Our goal should be to come up with a solution that gives us the string from n to n+4 using as less resources as possible and as fast as possible.
In the approach you have taken, you are adding in your string, all the prime numbers between 0 and 10000. Which comes up to about 1,229 prime numbers. The flaw in this approach is that if the input is something like 0. You are still building a string of 1,229 prime numbers which is totally unnecessary. If the input is something like 100000 then the error you are facing occurs, since you don't have a big enough string.
The best approach here is to build a string up to the required length which is n+5. Then cut the substring out of it. It's simple and efficient.
Probably you don't generate enough length of the string and given value out of your length of string.
I would recommend you to check your program on max value of given N. Also I would recommend you to not use String (read about creating a new object each time when you concatenate String) and simplify the second loop.
public static String answer(int n) {
StringBuilder sb = new StringBuilder("");
char[] ar = new char[5];
for (int i = 2; i <= 10000; i++) {
boolean flag = true;
for (int j = 2; j*j <= i; j++) {
if(i%j==0) {
flag = false;
break;
}
}
if(flag) {
sb.append(i);
}
}
ar[0] = sb.charAt(n);
ar[1] = sb.charAt(n + 1);
ar[2] = sb.charAt(n + 2);
ar[3] = sb.charAt(n + 3);
ar[4] = sb.charAt(n + 4);
return String.valueOf(ar);
}

Java. How to generate all integers with certain number of 1's and 0's in it? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
What is the most efficient way to solve this problem using Java ?
For example: generate all numbers containing three 1's & two 0's
Solution:
11100
11010
10110
01110
11001
10101
01101
10011
01011
00111
You can use recursion:
public static void generateBits(String s, int ones, int zeros)
{
if(ones > 0)
generateBits(s + "1", ones - 1, zeros);
if(zeros > 0)
generateBits(s + "0", ones, zeros - 1);
if(ones == 0 && zeros == 0)
System.out.println(s);
}
The function accepts a partially completed string and a count of how many ones and zeros are left to add, then recurses for the case of adding a one and adding a zero (if any are remaining). When there are no more left to add it prints the string. This will generate each number once with no duplicates. You can parse the string into a number if you need to instead of printing it out. Call like this:
generateBits("", 3, 2);
I used the String type to allow leading zeros, while keeping it simple, however as pointed out in a comment by #Aivean, string concantenation can be expensive. Here's an alternative, more efficient solution that uses longs, and converts to a binary string representation with leading zeros when printing out the values:
public static void generateBits(long val, int ones, int zeros, int len)
{
if(ones > 0)
generateBits((val << 1) + 1L, ones - 1, zeros, len + 1);
if(zeros > 0)
generateBits(val << 1, ones, zeros - 1, len + 1);
if(ones == 0 && zeros == 0)
System.out.println(String.format("%"+len+"s", Long.toBinaryString(val)).replace(' ', '0'));
}
You need to pass in 0 for the length when calling it at the top level. You would call it like this:
generateBits(0L, 3, 2, 0);
Here's non-recursive BitSet-based solution:
static void genCombinations(int n, int k) {
BitSet bs = new BitSet(n);
bs.set(0, k);
while(true) {
// output
for(int i=0; i<n; i++)
System.out.print(bs.get(i) ? "1" : "0");
System.out.println();
int b = bs.previousClearBit(n-1); // the last zero
int b1 = bs.previousSetBit(b); // the last one before that zero
if(b1 == -1)
return;
bs.clear(b1);
bs.set(b1+1, b1+(n-b)+1);
bs.clear(b1+(n-b)+1, n);
}
}
public static void main(String[] args) {
genCombinations(5, 3);
}
Such iterative approach sometimes more convenient as you can create an Iterable class like this:
public static class Combinations implements Iterable<String> {
private int n;
private int k;
public Combinations(int n, int k) {
this.n = n;
this.k = k;
}
#Override
public Iterator<String> iterator() {
return new Iterator<String>() {
BitSet bs = new BitSet(n);
{
bs.set(0, k);
}
#Override
public boolean hasNext() {
return bs != null;
}
#Override
public String next() {
char[] res = new char[n];
for (int i = 0; i < n; i++)
res[i] = bs.get(i) ? '1' : '0';
int b = bs.previousClearBit(n - 1);
int b1 = bs.previousSetBit(b);
if (b1 == -1)
bs = null;
else {
bs.clear(b1);
bs.set(b1 + 1, b1 + (n - b) + 1);
bs.clear(b1 + (n - b) + 1, n);
}
return new String(res);
}
};
}
}
And use it in the for loop:
for(String comb : new Combinations(5, 3)) {
System.out.println(comb);
}
To get an int with leading zero's, you will have to generate it as a String. This is the fastest way without duplicates:
public final class Permutator {
public static void main(String[] args) {
new Permutator(3, 5);
}
public Permutator(int numberOfOnes, int length) {
StringBuilder start = new StringBuilder();
for (int x = 0; x < length; x++)
start.append('0');
permutate(numberOfOnes, 0, 0, length, start);
System.exit(0);
}
public void permutate(int numberOfOnes, int first, int depth, int length, StringBuilder base) {
for (int x = first; x < length; x++) {
StringBuilder onesAndZeros = new StringBuilder(base.toString());
onesAndZeros.setCharAt(x, '1');
if (numberOfOnes == depth + 1)
System.out.println(onesAndZeros.toString());
else
permutate(numberOfOnes, x + 1, depth + 1, length, onesAndZeros);
}
}
}
Nice puzzle, not utmost optimized, but my attempt: 0/1 for bit in int, recursion on ones only (and bit count). The number of results is (ones + zeros over ones).
int ones = 3;
int zeroes = 2;
allIntsWithOnesAndZeroes(ones, zeroes);
public static void allIntsWithOnesAndZeroes(int ones, int zeroes) {
int bitCount = ones + zeroes;
int bits = 0;
SortedSet<Integer> results = new TreeSet<>();
all(results, bits, 0, bitCount, ones);
System.out.printf("(%d over %d) = %d, #%d: %s%n",
bitCount, ones, over(bitCount, ones), results.size(), results);
long a = 0;
for (int n : results) {
System.out.println("- " + Integer.toBinaryString(n));
a |= 1L << n;
}
System.out.printf("all: %s%n", Long.toBinaryString(a));
}
private static void all(Set<Integer> results, int bits, int i, int bitCount, int ones) {
if (ones == 0) {
results.add(bits); // Assumes ones > 0.
}
if (i >= bitCount) {
return;
}
all(results, bits, i + 1, bitCount, ones);
int bits2 = bits | (1 << i);
all(results, bits2, i + 1, bitCount, ones - 1);
}
Some math:
public static long fac(long x) {
long n = 1;
while (x > 1) {
n *= x;
--x;
}
return n;
}
public static long over(long x, long y) {
return fac(x) / fac(y) / fac(x - y);
}

Find the longest sequence of same characters in a string

This code supposed to output the longest run on which a character in a string has a consecutive runs of itself. Though the problem is that it outputs: 8 (which should be 5 instead). I just would like to ask what seems to be the problem regarding this code.
public class Sample {
public static void main(String[] args) {
String setofletters = "aaakkcccccczz"; /* 15 */
int output = runLongestIndex(setofletters);
System.out.println("Longest run that first appeared in index:" + output);
}
public static int runLongestIndex(String setofletters) {
int ctr = 0;
int ctrstor = 0;
int ii = 0;
int output = 0;
// loops until the last character in the string
for (int i = 0; i < setofletters.length() - 1; i++) {
// checks if the letter is the same to the next
if (setofletters.charAt(i) == setofletters.charAt(i++)) {
ctr++;
ii = i++;
// loops until the letter in the index is no longer equal
while (setofletters.charAt(i) == setofletters.charAt(ii)) {
ii++;
ctr++;
}
if (ctr > ctrstor) {
output = i;
}
// storing purposes
ctrstor = ctr;
}
// resets the counter
ctr = 0;
}
return output;
}
}
UPDATE Sorry, I misunderstood your question a bit, you need to make the following changes in your code to make it work.(lines with comments)
public static int runLongestIndex(String setofletters){
int ctr = 1; // every character is repeated at least once, so you should initialize it to 1, not 0
int ctrstor = 0;
int ii = 0;
int output = 0;
for (int i = 0; i < setofletters.length() - 1; i++) {
if (i < setofletters.length() - 1 && setofletters.charAt(i) == setofletters.charAt(i+1)) { // i++ is not same as i+1
ctr++;
ii = i+1; // i++ is not same as i+1
while (setofletters.charAt(i) == setofletters.charAt(ii)) {
ii++;
ctr++;
}
if (ctr > ctrstor) {
output = i;
}
ctrstor = ctr;
}
ctr = 1; // for the same reason I mentioned above
}
return output;
}
EDIT : the easiest way to write your code is :
public static int runLongestIndex(String setofletters){
int ctr = 1;
int output = 0;
int j=0;
for(int i=0; i<setofletters.length()-1;i++){
j=i;
while(i <setofletters.length()-1 && setofletters.charAt(i)==setofletters.charAt(i+1)){
i++;
ctr++;
}
if(ctr>output){
output=j;
}
ctr = 1;
}
return output;
}
Why are you assigning i to output? You should assign ctr to output.
change
if(ctr>ctrstor){
output=i;
}
to
if(ctr>ctrstor){
output=ctr;
}
and also I think you should change
if(setofletters.charAt(i)==setofletters.charAt(i++))
to
if(i<setofletters.length()-1 && setofletters.charAt(i)==setofletters.charAt(i+1)){
and you should intialize ctr to 1 but not 0 because every character is repeated at least once.
I'll give you a Scala implementation for that problem.
Here it is the automatic test (in BDD style with ScalaTest)
import org.scalatest._
class RichStringSpec extends FlatSpec with MustMatchers {
"A rich string" should "find the longest run of consecutive characters" in {
import Example._
"abceedd".longestRun mustBe Set("ee", "dd")
"aeebceeedd".longestRun mustBe Set("eee")
"aaaaaaa".longestRun mustBe Set("aaaaaaa")
"abcdefgh".longestRun mustBe empty
}
}
Following is the imperative style implementation, with nested loops and mutable variables as you would normally choose to do in Java or C++:
object Example {
implicit class RichString(string: String) {
def longestRun: Set[String] = {
val chunks = mutable.Set.empty[String]
val ilen = string.length
var gmax = 0
for ((ch, curr) <- string.zipWithIndex) {
val chunk = mutable.ListBuffer(ch)
var next = curr + 1
while (next < ilen && string(next) == ch) {
chunk += string(next)
next = next + 1
}
gmax = chunk.length max gmax
if (gmax > 1) chunks += chunk.mkString
}
chunks.toSet.filter( _.length == gmax )
}
}
}
Following is a functional-style implementation, hence no variables, no loops but tail recursion with result accumulators and pattern matching to compare each character with the next one (Crazy! Isn't it?):
object Example {
implicit class RichString(string: String) {
def longestRun: Set[String] = {
def recurse(chars: String, chunk: mutable.ListBuffer[Char], chunks: mutable.Set[String]): Set[String] = {
chars.toList match {
case List(x, y, _*) if (x == y) =>
recurse(
chars.tail,
if (chunk.isEmpty) chunk ++= List(x, y) else chunk += y,
chunks
)
case Nil =>
// terminate recursion
chunks.toSet
case _ => // x != y
recurse(
chars.tail,
chunk = mutable.ListBuffer(),
chunks += chunk.mkString
)
}
}
val chunks = recurse(string, mutable.ListBuffer(), mutable.Set.empty[String])
val max = chunks.map(_.length).max
if (max > 0) chunks.filter( _.length == max ) else Set()
}
}
}
For example, for the given "aeebceeedd" string, both implementations above will build the following set of chunks (repeating characters)
Set("ee", "eee", "dd")
and they will filter those chunks having the maximum length (resulting "eee").
This code should work for any length of string sequence.
public class LongestStringSequqnce {
static String myString = "aaaabbbbcccchhhhiiiiibbbbbbbbbccccccc";
static int largestSequence = 0;
static char longestChar = '\0';
public static void main(String args[]) {
int currentSequence = 1;
char current = '\0';
char next = '\0';
for (int i = 0; i < myString.length() - 1; i++) {
current = myString.charAt(i);
next = myString.charAt(i + 1);
// If character's are in sequence , increase the counter
if (current == next) {
currentSequence += 1;
} else {
if (currentSequence > largestSequence) { // When sequence is
// completed, check if
// it is longest
largestSequence = currentSequence;
longestChar = current;
}
currentSequence = 1; // re-initialize counter
}
}
if (currentSequence > largestSequence) { // Check if last string
// sequence is longest
largestSequence = currentSequence;
longestChar = current;
}
System.out.println("Longest character sequence is of character "
+ longestChar + " and is " + largestSequence + " long");
}
}
Source : http://www.5balloons.info/program-java-code-to-find-longest-character-sequence-in-a-random-string/
if(ctr>ctrstor){
output=i;
}
//storing purposes
ctrstor=ctr;
This looks like the problem. So if you find 8 consecutive characters, it will set output to 8, and proceed. The next time thru, it finds 3 consecutive characters, so doesn't set output, but sets ctrstor. Next time thru it finds 4 consecutive characters, and this will set output to 4
There are few traps in the code that your logic felt in:
Code incorrectly assumes that there is always next character to compare current one.
This fails for string like "a" or the last character in any string.
Code does not store the max count of characters but only the max index (i).
MaxCount is needed to compare the next chars sequence size.
Loop for and loop while repeat the same subset of characters.
Also variable name style makes it harder to understand the code.
After correcting above
public static int runLongestIndex(String setofletters) {
int maxCount = 0;
int maxIndex = 0;
// loops each character in the string
for (int i = 0; i < setofletters.length() - 1; ) {
// new char sequence starts here
char currChar = setofletters.charAt(i);
int count = 1;
int index = i;
while ( (index < setofletters.length() - 1) &&
(currChar == setofletters.charAt(++index)) ) {
count++;
}
if (count > maxCount) {
maxIndex = i;
maxCount = count;
}
i = index;
}
return maxIndex;
}
See Java DEMO
I think you don't need an internal loop:
public static int runLongestIndex(String setofletters) {
if (setofletters == null || setofletters.isEmpty()) {
return -1;
}
int cnt = 1;
char prevC = setofletters.charAt(0);
int maxCnt = 1;
//char maxC = prevC;
int maxRunIdx = 0;
int curRunIdx = 0;
for (int i = 1; i < setofletters.length(); i++){
final char c = setofletters.charAt(i);
if (prevC == c) {
cnt++;
} else {
if (cnt > maxCnt) {
maxCnt = cnt;
//maxC = prevC;
maxRunIdx = curRunIdx;
}
cnt = 1;
curRunIdx = i;
}
prevC = c;
}
if (setofletters.charAt(setofletters.length() - 1) == prevC) {
if (cnt > maxCnt) {
//maxC = prevC;
maxCnt = cnt;
maxRunIdx = curRunIdx;
}
}
return maxRunIdx;
}
and this code:
System.out.println(runLongestIndex("aaakkcccccczz"));
gives you
5
This is how a "colleague" of mine is understanding to write readable code in order to solve this problem, even if this is working :)
public static int count (String str) {
int i = 0;
while(i < str.length()-1 && str.charAt(i)==str.charAt(i+1))
i ++;
return ++i;
}
public static int getLongestIndex(String str){
int output = 0;
for(int i=0, cnt = 1, counter = 0 ; i<str.length() - 1;i += cnt, cnt = count(str.substring(i)), output = (counter = (cnt > counter ? cnt : counter)) == cnt ? i : output);
return output;
}
int indexOfLongestRun(String str) {
char[] ar = str.toCharArray();
int longestRun = 0;
int lastLongestRun = 0;
int index = 0;
for(int i = ar.length-1; i>0; i--){
if(ar[i] == ar[i-1]){
longestRun++;
}else{
if(longestRun > lastLongestRun){
lastLongestRun = longestRun;
longestRun = 0;
index = i;
}
}
}
return index;
Well, the solution a bit depends on the additional requirements. Here is the code which returns the FIRST longest sequence of a repeated character int the given string, meaning if you have a second sequence with the same length you never get it out :(. But still, this is a simple and clear solution here, so good news - it works! :)
string = 'abbbccddddddddeehhhfffzzzzzzzzdddvyy'
longest_sequence = ''
for i in range(len(string)):
is_sequence = True
ch_sequence = ''
while is_sequence:
ch_sequence += string[i]
if i+1 < len(string) and string[i]==string[i+1]:
i += 1
else:
is_sequence = False
if len(ch_sequence) > len(longest_sequence):
longest_sequence = ch_sequence
print (longest_sequence)
#Paolo Angioletti already provided an answer using Scala, but it's more complicated than it needs to be. The idea is not very different from Run-length encoding. Time complexity O(n).
def longestConsecutive(s: String): (Char, Int) = {
Iterator.iterate(('\u0000', 0, 0)) { case (ch, longestRun, i) =>
val run = (i until s.length)
.takeWhile(s(_) == s(i))
.size
if (run > longestRun) (s(i), run, i + run)
else (ch, longestRun, i + run)
}
.dropWhile(i => s.isDefinedAt(i._3))
.take(1)
.map(x => (x._1, x._2))
.next()
}
Tested with:
("s", "ch", "n")
----------------
("", '\u0000', 0),
("a", 'a', 1),
("aabcddbbbea", 'b', 3),
("abcddbbb", 'b', 3),
("cbccca", 'c', 3)
#include <iostream>
#include<algorithm>
using namespace std;
int main() {
string s="abbcccccbbffffffffff";
//cin>>s;
int count=1;
int maxcount=1;
int start=0;
int ps=0;
for (int i=0;i<s.size()-1;i++)
{
if(s.at(i)==s.at(i+1))
{
count +=1;
maxcount=max(maxcount,count);
}
else
{
ps=max(ps,start+count);
count =1;
start=i;
}
}
for(int i=1;i<=maxcount;i++)
{
cout<<s.at(i+ps);
}
// your code goes here
return 0;
}
This is the simplest I can think of and it will print the number of the longest sequenced identical characters in a one line string.
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
scanner.close();
int count = 0;
int curCount = 1;
for (int i = 0; i < s.length() -1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {
curCount++;
if (curCount > count) {
count = curCount;
}
}else {
if (curCount > count) {
count = curCount;
}
curCount = 1;
}
}
System.out.println(count);
}

Checking if numbers of an integer are increasing (java)

What I am trying to do should be pretty easy, but as I'm new to java, I'm struggling with what might be basic programming.
The main issue is how to check if the (x+1) number of an integer is greater than the x number, which I am trying to do as follow :
for( int x=0; x < Integer.toString(numblist).length();x++) {
if (numblist[x] < numblist[x+1]) {
compliance= "OK";
} else{
compliance="NOK";
}
But it returns an error "array required but integer found".
It seems to be a basic type mistake, which might come from the previous step (keeping only the numbers included in a string):
for (int p = 0; p < listWithoutDuplicates.size(); p++) {
Integer numblist = Integer.parseInt(listWithoutDuplicates.get(p).getVariantString().replaceAll("[\\D]", ""));
I can't find the answer online, and the fact that it shouldn't be complicated drives me crazy, I would be grateful if someone could help me!
Do the reverse. If they are increasing starting from the first digit, it means that they are decreasing from the last to the first. And it is much easier to program this way:
public boolean increasingDigits(int input)
{
// Deal with negative inputs...
if (input < 0)
input = -input;
int lastSeen = 10; // always greater than any digit
int current;
while (input > 0) {
current = input % 10;
if (lastSeen < current)
return false;
lastSeen = current;
input /= 10;
}
return true;
}
You can't index an integer (i.e. numblist) using the [] syntax -- that only works for arrays, hence your error. I think you're making this more complicated than it has to be; why not just start from the back of the integer and check if the digits are decreasing, which would avoid all this business with strings:
int n = numblist;
boolean increasing = true;
while (n > 0) {
int d1 = n % 10;
n /= 10;
int d2 = n % 10;
if (d2 > d1) {
increasing = false;
break;
}
}
One way I could think of was this:
boolean checkNumber(int n) {
String check = String.valueOf(n); // Converts n to string.
int length = check.length(); // Gets length of string.
for (int i = 0; i < length-1; i++) {
if(check.charAt(i) <= check.charAt(i+1)) { // Uses the charAt method for comparison.
continue; // if index i <= index i+1, forces the next iteration of the loop.
}
else return false; // if the index i > index i+1, it's not an increasing number. Hence, will return false.
}
return true; // If all digits are in an increasing fashion, it'll return true.
}
I'm assuming that you're checking the individual digits within the integer. If so, it would be best to convert the Integer to a string and then loop though the characters in the string.
public class Test {
public static void main(String[] args) {
Integer num = 234; // New Integer
String string = num.toString(); // Converts the Integer to a string
// Loops through the characters in the string
for(int x = 0; x < string.length() - 1; x++){
// Makes sure that both string.charAt(x) and string.charAt(x+1) are integers
if(string.charAt(x) <= '9' && string.charAt(x) >= '0' && string.charAt(x+1) <= '9' && string.charAt(x+1) >= '0'){
if(Integer.valueOf(string.charAt(x)) < Integer.valueOf(string.charAt(x+1))){
System.out.println("OK");
}else{
System.out.println("NOK");
}
}
}
}
}
I think a simple way could be this
package javacore;
import java.util.Scanner;
// checkNumber
public class Main_exercise4 {
public static void main (String[] args) {
// Local Declarations
int number;
boolean increasingNumber=false;
Scanner input = new Scanner(System.in);
number = input.nextInt();
increasingNumber = checkNumber(number);
System.out.println(increasingNumber);
}
public static boolean checkNumber(int number) {
boolean increasing = false;
while(number>0) {
int lastDigit = number % 10;
number /= 10;
int nextLastDigit = number % 10;
if(nextLastDigit<=lastDigit) {
increasing=true;
}
else {
increasing=false;
break;
}
}
return increasing;
}
}
private boolean isIncreasingOrder(int num) {
String value = Integer.toString(num);
return IntStream.range(0, value.length() - 1).noneMatch(i -> Integer.parseInt(value.substring(i, i + 1)) > Integer.parseInt(value.substring(i + 1, i + 2)));
}

Categories