Find the Longest Substring without Repeating Characters - Java - java

I was trying to solve a leetcode question but my solution is not returning the correct value for one of the test cases. I wanted to implement the two-pointer technique for this solution (if im using the technique wrong, advice is welcome on explaining the proper way to do it). The details are below:
Leetcode Question Title:
Longest Substring Without Repeating Characters.
Question:
Given a string, find the length of the longest substring without repeating characters. ( return int )
My Solution:
public int lengthOfLongestSubstring(String s) {
//place holder for me to create a "sub-string"
String sub = "";
//counter variable to count the characters in the substring
int count = 0;
int maxCount = 0;
//my attempt at a TWO POINTER TECHNIQUE
//pointers - to determine when the loop should break
int head = 0;
int tail = s.length();
//this variable was intended to be used with the "indexOf" method, as the "start from" index...
int index = 0;
while(head < tail){
//check if the next character in the string was already added to my substring.
int val = sub.indexOf(s.charAt(head), index);
//we proceed if it is -1 because this means the substring didnt previously contain that character
if(val == -1){
//added character to my substring
sub+= s.charAt(head);
count++;
head++;
} else {
//reset data to default conditions, while continuing at the "head index" and check the rest of the substring
count = 0;
sub = "";
}
//determine what the length of the longest substring.
maxCount = count > maxCount ? count : maxCount;
}
return maxCount;
}
I passed the test cases:
> "" = expect 0
> " " = expect 1
> "abcabcbb" = expect 3
> "bbbbb" = expect 1
> "pwwkew" = expect 3
> "aab" = expect 2
I failed test cases:
> "dvdgd" = expect 3, but got 2
> "dvjgdeds" = expect 5, but got 4
> "ddvbgdaeds" = expect 6, but got 4
Possible Issues:
I believe the issue occurred because it moves pass the index with "v", and then processes the substring "dg". So I attempted to change the solution, but fixing that issue caused all my other cases to return errors so I figured that attempt at a fix should be tossed out.
What I have also tried:
I also attempted to manipulate the "indexOf" method to change the start index, whenever the character was found in the string. This however generated an infinite loop.
I have been trying to solve this problem for a few hours and I am stomped. So any help would be appreciated greatly. And please be detailed with your explanation if you can, I am very new to DSA and programming, thank you greatly. If more information from me is needed, please let me know am I will try to answer.

Well, here you go:
public static int lengthOfLongestSubstring(String s) {
//place holder for me to create a "sub-string"
String sub = "";
//counter variable to count the characters in the substring
int count = 0;
int maxCount = 0;
//my attempt at a TWO POINTER TECHNIQUE
//pointers - to determine when the loop should break
int head = 0;
int tail = s.length();
//this variable shows where to start from
int index = 0;
while(head < tail){
//check if the next character in the string was already added to my substring.
int val = sub.indexOf(s.charAt(head)); //search whole substing
//we proceed if it is -1 because this means the substring didnt previously contain that character
if(val == -1){
//added character to my substring
sub+= s.charAt(head);
count++;
head++;
//determine what the length of the longest substring.
maxCount = count > maxCount ? count : maxCount;
System.out.println(sub); //let's see what we got so far
} else {
//reset data to default conditions, while continuing at the "head index" and check the rest of the substring
count = 0;
sub = "";
head=index+1; //begin from the next letter
index++; //move
}
}
return maxCount;
}

Related

alternative approach to count number of rotation required to find original string from rotated string

WE got 2 strings one correct and one its rotation? we have to tell that after how many steps of rotation of 2nd string we get the original (first)string(suppose only one side rotation is allowed)
but problem here is traditional method of rotating one charater of string at a time and then comparing rotated string with original is taking more time than allowed
which alternative approach can be used?
string1: david
string2: vidda
(processing part-rotation first: avidd, second: david, so answer is 2)
output: 2
String one = "david";
String two = "vidda";
one.concat(one).indexOf(two)
would work wouldn't it?
I don't know if my approach is fast enough... But it has a runtime of O(n) where n is the length of the strings.
This approach only works if it is given that it is solvable and if both strings have the same length:
public static void main(String[] args) {
String string1 = "david";
String string2 = "avidd";
char[] a = string1.toCharArray();
char[] b = string2.toCharArray();
int pointer = a.length-1;
int off = 0;
int current = 0;
for (int i = b.length-1; i >= 0; i--) {
if (b[i] == a[pointer]) { //found a match
current++; //our current match is one higher
pointer--; //pointer of string1 goes one back
} else if (current != 0) { //no match anymore and we have had a match
i ++; //we have to recalculate the actual position in the next step of the loop
off += current; //we have to rotate `current` times more
current = 0; //reset current match
pointer = a.length-1; //reset pointer
} else { //no match and we didn't have had a match the last time
off ++; //we have to rotate one more time
}
}
System.out.println("Rotate: " + off);
}
basically it starts at the end of both the strings and goes back to the beginning until it doesn't get any differences any more. If it does get a difference at any point it adds the current counter to off and recontinues at the end of string1.
My algorithm does not check if the strings are the same after having done off rotations.

How to define number sequence in string?

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.

Identifying set of integers in strings

I'm new to Java, trying to learn more.
How do I identify a contiguous set of integers in a string?
For example, if I have the string "123hh h3ll0 wor1d" the program should output 4 as the answer.
Here's what I've worked on, and as a result, my program outputs 6. I understand why but I don't know how to implement what I want the program to do.
public static void main (String[] args) throws java.lang.Exception
{
String string = "123hh h3ll0 w0rld";
int count = 0;
if (string.isEmpty())
count = 0;
for (int i = 0; i < string.length(); i++)
{
char c = string.charAt(i);
if (Character.isDigit(c))
count++;
}
System.out.println(count);
}
Your program is a good start, but it counts all digits. You need to avoid count++ when you are in a contiguous group of digits. You can do it by adding a boolean flag which you set to true when you see a digit, and then to false when you see a non-digit:
boolean inDigits = false;
for (int i = 0; i < string.length(); i++)
{
char c = string.charAt(i);
if (Character.isDigit(c)) {
if (!inDigits) count++;
inDigits = true;
} else {
inDigits = false;
}
}
Demo 1
A simpler way to find the number of groups is to split on \\d+ (a sequence of one or more digits), count the number of groups you get, and subtract one:
System.out.println(string.split("\\d+").length-1);
Demo 2
Your program counts each occurrence of a digit within the input string; and as there 6 digits; 6 is your result. So no surprises there. You have to understand: if you are interested in sequences of digits, then just checking each character "are you a digit" isn't enough!
If you are interested in the length of the longest sequence, then your "counting" must be enhanced:
While being within a sequence, you keep increasing the "currentSequenceLength" counter
When hitting a non-digit, you stop counting; and you compare the length of the last sequence with the "maximum" that you also have to remember.
That should be enough to get you going; as for sure; the idea is not that we do the homework/learning part for you.
Based on what you stated about contiguous, you want to reset the count every time you are not on a digit and store the maximum count achieved during this process.
Add int currentMaximum = 0 and when a non-digit is read in, check to see if count is greater than currentMaximum and set currentMaximum to count and then set count = 0. This will cause the count to reset at each non-digit and only count up when digits are contiguous.
So your code snippet is simply counting every digit in the string, which you said you knew. So you have to see which situation does it occur that you actually want to count. For contiguous digits, the situation you're looking for is when the current character is a digit, and the next is not. That is when the chain of contiguous digits is broken. I have edited your for loop to use this technique to find the number of contiguous digit sets:
public static void main (String[] args) throws java.lang.Exception {
String string = "123hh h3ll0 w0rld";
int count = 0;
if (string.isEmpty()) {
count = 0;
} else {
for (int i = 0; i < string.length() - 1; i++){
char current = string.charAt(i);
char next = string.charAt(i+1);
if (Character.isDigit(current) && !Character.isDigit(next)){
count++;
}
}
System.out.println(count);
}
}
I would target the numbers in the string via pre-processing OR real time, your problem statement doesn't define a requirement for either, and then refer to the related problem: here and additionally here (which provides a c++ and java sample too).
There's not too much to elaborate on because you haven't set up the problem space to define other factors (more in-depth problem statement by OP would help answers reflect more accurate responses). Try to specify such things as:
does/should it reset when encountering non-digits?
can you use objects like sets?
are you reading in simple test strings or large data amounts?
etc.
Without more info, I think there will be a varying response of answers here.
Cheers
This code will generate count = 6 and group = 4.
enter public static void main (String[] args) throws java.lang.Exception
{
String string = "123hh h3ll0 w0rld";
boolean isGroup = false;
int count = 0;
int group = 0;
if (string.isEmpty()) {
count = 0;
} else {
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (Character.isDigit(c)) {
count++;
if (!isGroup) {
group++;
isGroup = true;
}
} else {
isGroup = false;
}
}
}
System.out.println(count);
System.out.println(group);
}

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);

Why am I getting java.lang.StringIndexOutOfBoundsException?

I want to write a program that prints words incrementally until a complete sentence appears. For example : I need to write (input), and output:
I
I need
I need to
I need to write.
Here is my code:
public static void main(String[] args) {
String sentence = "I need to write.";
int len = sentence.length();
int numSpace=0;
System.out.println(sentence);
System.out.println(len);
for(int k=0; k<len; k++){
if(sentence.charAt(k)!='\t')
continue;
numSpace++;
}
System.out.println("Found "+numSpace +"\t in the string.");
int n=1;
for (int m = 1; m <=3; m++) {
n=sentence.indexOf('\t',n-1);
System.out.println("ligne"+m+sentence.substring(0, n));
}
}
and this is what I get:
I need to write.
16
Found 0 in the string.
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: -1 at
java.lang.String.substring(String.java:1937) at
split1.Split1.main(Split1.java:36) Java Result: 1 BUILD SUCCESSFUL
(total time: 0 seconds)
I don't understand why numSpace doesn't count the occurrences of spaces, nor why I don't get the correct output (even if I replace numSpace by 3 for example).
You don't have a \t character, so indexOf(..) returns -1
You try a substring from 0 to -1 - fails
The solution is to check:
if (n > -1) {
System.out.prinltn(...);
}
Your loop looking for numSpace is incorrect. You are looking for a \t which is a tab character, of which there are none in the string.
Further, when you loop in the bottom, you get an exception because you are trying to parse by that same\t, which will again return no results. The value of n in n=sentence.indexOf('\t',n-1); is going to return -1 which means "there is not last index of what you are looking for". Then you try to get an actual substring with the value of -1 which is an invalid substring, so you get an exception.
You are mistaken by the concept of \t which is an escape sequence for a horizontal tab and not for a whitespace character (space). Searching for ' ' would do the trick and find the whitespaces in your sentence.
This looks like homework, so my answer is a hint.
Hint: read the javadoc for String.indexOf paying attention to what it says about the value returned when the string / character is not found.
(In fact - even if this is not formal homework, you are clearly a Java beginner. And beginners need to learn that the javadocs are the first place to look when using an unfamiliar method.)
The easiest way to solve this I guess would be to split the String first by using the function String.split. Something like this:
static void sentence(String snt) {
String[] split = snt.split(" ");
for (int i = 0; i < split.length; i++) {
for (int j = 0; j <= i; j++) {
if (i == 1 && j == 0) System.out.print(split[j]);
else System.out.printf(" %s", split[j]);
}
}
}
As other people pointed out. You are counting every characters except tabs(\t) as a space. You need to check for spaces by
if (sentence.charAt(k) == ' ')
\t represents a tab. To look for a space, just use ' '.
.indexOf() returns -1 if it can't find a character in the string. So we keep looping until .indexOf() returns -1.
Use of continue wasn't really needed here. We increment numSpaces when we encounter a space.
System.out.format is useful when we want to mix literal strings and variables. No ugly +s needed.
String sentence = "I need to write.";
int len = sentence.length();
int numSpace = 0;
for (int k = 0; k < len; k++) {
if (sentence.charAt(k) == ' ') {
numSpace++;
}
}
System.out.format("Found %s in the string.\n", numSpace);
int index = sentence.indexOf(' ');
while(index > -1) {
System.out.println(sentence.substring(0, index));
index = sentence.indexOf(' ', index + 1);
}
System.out.println(sentence);
}
Try this, it should pretty much do what you want. I figure you have already finished this so I just made the code real fast. Read the comments for the reasons behind the code.
public static void main(String[] args) {
String sentence = "I need to write.";
int len = sentence.length();
String[] broken = sentence.split(" "); //Doing this instead of the counting of characters is just easier...
/*
* The split method makes it where it populates the array based on either side of a " "
* (blank space) so at the array index of 0 would be 'I' at 1 would be "need", etc.
*/
boolean done = false;
int n = 0;
while (!done) { // While done is false do the below
for (int i = 0; i <= n; i++) { //This prints out the below however many times the count of 'n' is.
/*
* The reason behind this is so that it will print just 'I' the first time when
* 'n' is 0 (because it only prints once starting at 0, which is 'I') but when 'n' is
* 1 it goes through twice making it print 2 times ('I' then 'need") and so on and so
* forth.
*/
System.out.print(broken[i] + " ");
}
System.out.println(); // Since the above method is a print this puts an '\n' (enter) moving the next prints on the next line
n++; //Makes 'n' go up so that it is larger for the next go around
if (n == broken.length) { //the '.length' portion says how many indexes there are in the array broken
/* If you don't have this then the 'while' will go on forever. basically when 'n' hits
* the same number as the amount of words in the array it stops printing.
*/
done = true;
}
}
}

Categories

Resources