How does if condition finds unique letter in the string? - java

I am newbie here!!
I am unable to understand how "s.indexOf(s.charAt(i), s.indexOf(s.charAt(i)) + 1) == -1 "
checking for unique letter in the string. Below is the code,
String s = "leetcode";
for (int i = 0; i < s.length(); i++) {
if (s.indexOf(s.charAt(i), s.indexOf(s.charAt(i)) + 1) == -1) {
return i;
}
}
return -1;
Thank you for your help!
I am trying to find the unique character in the given string. I came across this code. I am trying to understand how it work!

For a rather verbose function like this, the best thing to do is break it down to the smallest possible computation (effectively).
Please refer to the following code snippet:
public class App {
private static int unique(String s) {
/** The String (non-primitive) is an array of chars (primitive).
* So, it'll be iterated with a loop. S.length () is the length of the char array.
*/
for (int i = 0; i < s.length(); i++) {
/** This will return the char element of the index i -> public char charAt(int index) */
char chatAtI = s.charAt(i);
/** Follow the println logs to see what's happening, or use a debugger on an IDE. */
System.out.println("chatAtI -> " + chatAtI);
/** Returns the index within this string of the first occurrence of the specified character
* or -1 if the character does not occur.
*/
int charIndex = s.indexOf(chatAtI) + 1;
System.out.println("charIndex -> " + charIndex);
/** The indexOf() method returns the position of the first occurrence of a specified character(s) in a string.
* It's an overloaded method.
* In the if condition, you're also using the variant which [1] returns the index of the first char occurrence
* and [2] start the search at the specified index or -1 if the character does not exist.
* The moment a unique occurrence is found, it'll return the index;
* meaning - "if the current char doesn't repeat in the char array, return its index and exit the method."
* Keep in mind the +1 above is what does the trick, as if that character doesn't repeat indexOf() returns -1.
*/
if (s.indexOf(chatAtI, charIndex) == -1) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
/** l is the first unique occurrence. Therefore, its index, 0, is returned. */
System.out.println(unique("leetcode"));
}
}
Articles for further reading:
https://www.digitalocean.com/community/tutorials/java-char-to-string-to-char-array
https://www.freecodecamp.org/news/charat-in-java-how-to-use-the-java-charat-method-2/
https://www.geeksforgeeks.org/java-string-indexof/
I hope this made sense. If not, let me know, as I can edit the answer and give more context.

Related

First Unique Character In a String-Leetcode

I have tried out 387.First Unique Character In A string
Given a string s, find the first non-repeating character in it and
return its index. If it does not exist, return -1.
EXAMPLE : 1
Input: s = "leetcode"
Output: 0
EXAMPLE :2
Input: s = "loveleetcode"
Output: 2
I have been trying this problem. I thought we will pick one by one all the characters and check if a repeating character exists break from the loop. And if not then return that index.I have thought over a solution which I believe is not the most efficient way but I want to know the how can I solve this problem with the approach given below:
public int firstUniqChar(String s) {
for(int i=0;i<s.length();i++){
for(int j=i+1;j<s.length();j++){
if(s.charAt(i)==s.charAt(j)){
break;
}
}
}
return -1;
}
I'm confused how to return the index.I'm unable to find the logic after:
for(int j=i+1;j<s.length();j++){
if(s.charAt(i)==s.charAt(j)){
break;
}
}
If anyone can help me find out the logic here.
Try this.
public static int firstUniqChar(String s) {
L: for (int i = 0, length = s.length(); i < length; i++) {
for (int j = 0; j < length; j++)
if (i != j && s.charAt(i) == s.charAt(j))
continue L;
return i;
}
return -1;
}
public static void main(String[] args) {
System.out.println(firstUniqChar("leetcode"));
System.out.println(firstUniqChar("loveleetcode"));
System.out.println(firstUniqChar("aabb"));
}
output:
0
2
-1
you can use a flag variable.
public int firstUniqChar(String s) {
int flag=0;
for(int i=0;i<s.length();i++){
flag=0;
for(int j=0;j<s.length();j++){
if(s.charAt(i)==s.charAt(j) && i!=j){
flag=1;
break;
}
}
if(flag==0){
return i;
}
}
return -1;
}
There are 26 possible lowercase English letters, so you could use two 26 element arrays.
One array, letterCount, keeps counts of each letter. Start at 0 and add 1 every time the corresponding letter appears in the text string. The second array, position, holds the position of the first occurrence of that letter, or -1 if the letter never appears. You will need to initialise that array to -1 for all elements.
Process the string in order, recording initial positions, once only for each letter, and incrementing the count for each letter in the string.
After the string has been processed, look through the letterCount array. If there are no letters with a 1 count then return -1. If exactly one letter has a 1 count, then return the position of that letter from the position array. If more than one letter has a 1 count, then pick the one with the lowest value for its position.
Using two loops is a highly inefficient way of solving this problem. The string can be up to 100,000 characters long and you are processing it multiple times. Far better to process it only once, keeping track of what you have found so far.
Fix you code
You need to add a variable that tells you if you have breaked the loop or not
static int firstUniqChar(String s) {
boolean duplicate;
for (int i = 0; i < s.length(); i++) {
duplicate = false;
for (int j = i + 1; j < s.length(); j++) {
if (s.charAt(i) == s.charAt(j)) {
duplicate = true;
break;
}
}
if (!duplicate) {
return i;
}
}
return -1;
}
Improve
There is a smarter way, that is finding the last index occurence of the current char, if it's equal to the current index : that char is unique and you return its index
static int firstUniqChar(String s) {
for (int i = 0; i < s.length(); i++) {
if (s.lastIndexOf(s.charAt(i)) == i) {
return i;
}
}
return -1;
}
If you do not bother about time complexity using IdenxOF operations, then one can try this solution.
indexOf() – also runs in linear time. It iterates through the internal array and checking each element one by one. So the time
complexity for this operation always requires O(n) time.
int firstUniqCharOneLoop(String str) {
for (int i = 0; i < str.length(); i++) {
if (str.indexOf(str.charAt(i))== str.lastIndexOf(str.charAt(i)) ) {
return i;
}
}
return -1;
}
The lowest complexity I managed to achieve:
public class UniqueSymbolFinder {
static int findFirstUniqueChar(String s) {
Set<Character> set = new HashSet<>(s.length());
List<CharWithIndex> candidates = new LinkedList<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
CharWithIndex charWithIndex = new CharWithIndex(ch, i);
if (set.add(ch)) {
candidates.add(charWithIndex);
} else {
candidates.remove(charWithIndex);
}
}
return candidates.size() == 0 ? -1 : candidates.get(0).index;
}
/**
* Class for storing the index.
* Used to avoid of using an indexOf or other iterations.
*/
private static class CharWithIndex {
int index;
char ch;
private CharWithIndex(char ch, int index) {
this.ch = ch;
this.index = index;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CharWithIndex that = (CharWithIndex) o;
return ch == that.ch;
}
#Override
public int hashCode() {
return Objects.hash(ch);
}
}
}
I believe the memory usage can still be optimized.
100% Correct JAVA Solution
Since the question is about returning the index of the first non-repeating character in a string, we need some data structure to save the index of each character in the string for us.
I choose here the HashMap of Java. Basically, what you can do with it, you can save a pair of values (or pair of other data structures).
So, in my solution, I am saving a Character Integer pair. The first is considered as a key (here it is each character in the string), and the second is its index value.
The problem here is that we only want to keep the minimum index of non-repeating characters and that's why if you take a look below, you will find the maxIndexForRepeatedValues is set to be 10 power 5 as the input constraint says 1 <= s.length <= 10 power 5.
However, I am using that value to neglect repeated characters that would be found in the HashMap and at the end, we retrieve the minimum index which is the index of course for the first character from the map, or if there were only repeated characters, we return -1.
To make the code shorter, I used ternary-operator but you can write it with if-else if you want!
class Solution {
public int firstUniqChar(String s) {
int maxIndexForRepeatedValues = 100000;
Map<Character, Integer> map = new HashMap<>();
for (int i = 0 ; i < s.length() ; i++) {
char key = s.charAt(i);
int resIndex = map.containsKey(key) ? maxIndexForRepeatedValues : i;
map.put(key, resIndex);
}
int minIndex = Collections.min(map.values());
return minIndex == maxIndexForRepeatedValues ? -1 : minIndex;
}
}

Implement String.length method by hand

I have to implement the .length method from String class "by hand" and I have no idea and hope you can help somehow.
No other methods or functions are allowed, than:
String.charAt()
String.substring()
String.isEmpty()
Bit-operations &,|, &&,||, <<, >>,>>>, !=, ==
Arithmetic operations
for and while Loop
recursion
if else statement
self created methods (int,String,char,boolean etc.)
self-created Arrays. (no Methods of them)
static void manual_length2(String length) {
//example String length = "Hello" = 5 letters.
int counter = 0;
int i = 0;
char g = ' ';
while(i <= 4 ) { /*4 is the number i already know */
g = length.charAt(i);
counter += 1;
length.substring(1);
++i;
}
System.out.println(counter);
Console: 5
This was my approach, but I'm stuck in the while statement's condition to terminate.
With the example "Hello" i already know that this word has 5 letters, but it needs to fit for all inputs. So i don't know how to express to border-value of the while statement.
Another approach is by recursion, but also, i ask myself how can i express the limit of the recursion.
How can i express:
.... lengthMethod1(String length, int ???) {
if(n == 0) {
return length.charAt(0);
}
else {
return ???? lengthMethod1(length, n - 1);
}
You can loop until the String is empty while removing the first character on each iteration.
static int manual_length(String str) {
int len = 0;
while(!str.isEmpty()){
++len;
str = str.substring(1);
}
return len;
}
This can be converted to a tail-recursive method as well.
static int manual_length(String str) {
return str.isEmpty() ? 0 : 1 + manual_length(str.substring(1));
}
Another approach is by recursion, but also, i ask myself how can i
express the limit of the recursion. How can i express:
Yes, you can do recursively like this:
static int manual_length(String str, int len) {
return str.isEmpty() ? len : manual_length(str.substring(1), len + 1);
}
You use an accumulator variable (i.e., len), that you increment, while removing a char from the string (i.e., str.substring(1)). When you reach the end (i.e., str.isEmpty()) you return the accumulator.

Wrong output in some tests

I have troubles in one method. In input we have string, for example (a+-b*i)some sign(c+-d*i). Program must calculate this and output result. I need to take index of sign in the first bracket and index in the second bracket. And than my program will be working. But, when in input (a-b*i)-(c-d*i) or (a-b*i)*(c-d*i) only, method returning wrong result -1.
My methods for two brackets.
public int getSign1(String str)
{
int sign1;
if(str.indexOf("+") < str.indexOf(")"))
sign1 = str.indexOf("+");
else if(str.indexOf("-", 2) < str.indexOf(")"))
sign1 = str.indexOf("-", 2);
else sign1 = -1;
return sign1;
}
public int getSign2(String str)
{
int sign2;
if(str.lastIndexOf("+") > str.lastIndexOf("("))
sign2 = str.lastIndexOf("+");
else if(str.lastIndexOf("-") > str.lastIndexOf("("))
sign2 = str.lastIndexOf("-");
else sign2 = -1;
return sign2;
}
The second method always working, but not the first (Please help me to find error).
Example: (1-2i)*(3-4i)
The first method is returning -1, but not 2. Why?
This happens because in the expression:
(1-2i)*(3-4i) you don't have any + char, and after seeing String#lastIndexOf:
the index of the last occurrence of the character in the character
sequence represented by this object, or -1 if the character does not
occur.
Then you know why str.lastIndexOf("+") will be -1. And it's of course < str.indexOf(")").
So sign1 will be -1.
You can fix it by:
if(str.indexOf("+")!= -1 && str.indexOf("+") < str.indexOf(")"))
For input (a-b*i)-(c-d*i) , here there is no '+' in this string.
public int getSign1(String str){
if(str.indexOf("+") < str.indexOf(")"))
sign1 = str.indexOf("+");
..
}
In this method first if you are checking '+' , hence it is not there its index is -1 which is less than str.indexOf(")") index so its returing -1.

java indexof(String str) method complexity [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the cost / complexity of a String.indexof() function call
What is the complexity of java indexof(String str) method. I mean there are String matching algorithms like KMP which runs in linear time. I am implementing a system that needs to search for large substring in a really large string,so can I use java indexof(String str) method or I should to implement KMP.
The complexity of Java's implementation of indexOf is O(m*n) where n and m are the length of the search string and pattern respectively.
What you can do to improve complexity is to use e.g., the Boyer-More algorithm to intelligently skip comparing logical parts of the string which cannot match the pattern.
java indexOf function complexity is O(n*m) where n is length of the text and m is a length of pattern
here is indexOf original code
/**
* Returns the index within this string of the first occurrence of the
* specified substring. The integer returned is the smallest value
* <i>k</i> such that:
* <blockquote><pre>
* this.startsWith(str, <i>k</i>)
* </pre></blockquote>
* is <code>true</code>.
*
* #param str any string.
* #return if the string argument occurs as a substring within this
* object, then the index of the first character of the first
* such substring is returned; if it does not occur as a
* substring, <code>-1</code> is returned.
*/
public int indexOf(String str) {
return indexOf(str, 0);
}
/**
* Returns the index within this string of the first occurrence of the
* specified substring, starting at the specified index. The integer
* returned is the smallest value <tt>k</tt> for which:
* <blockquote><pre>
* k >= Math.min(fromIndex, this.length()) && this.startsWith(str, k)
* </pre></blockquote>
* If no such value of <i>k</i> exists, then -1 is returned.
*
* #param str the substring for which to search.
* #param fromIndex the index from which to start the search.
* #return the index within this string of the first occurrence of the
* specified substring, starting at the specified index.
*/
public int indexOf(String str, int fromIndex) {
return indexOf(value, offset, count,
str.value, str.offset, str.count, fromIndex);
}
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* #param source the characters being searched.
* #param sourceOffset offset of the source string.
* #param sourceCount count of the source string.
* #param target the characters being searched for.
* #param targetOffset offset of the target string.
* #param targetCount count of the target string.
* #param fromIndex the index to begin searching from.
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first);
}
/* Found first character, now look at the rest of v2 */
if (i <= max) {
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j] ==
target[k]; j++, k++);
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
you can simply implements the KMP algorithm without using of indexOf Like this
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Scanner;
public class Main{
int failure[];
int i,j;
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
PrintWriter out=new PrintWriter(System.out);
String pat="",str="";
public Main(){
try{
int patLength=Integer.parseInt(in.readLine());
pat=in.readLine();
str=in.readLine();
fillFailure(pat,patLength);
match(str,pat,str.length(),patLength);
out.println();
failure=null;}catch(Exception e){}
out.flush();
}
public void fillFailure(String pat,int patLen){
failure=new int[patLen];
failure[0]=-1;
for(i=1;i<patLen;i++){
j=failure[i-1];
while(j>=0&&pat.charAt(j+1)!=pat.charAt(i))
j=failure[j];
if(pat.charAt(j+1)==pat.charAt(i))
failure[i]=j+1;
else
failure[i]=-1;
}
}
public void match(String str,String pat,int strLen,int patLen){
i=0;
j=0;
while(i<strLen){
if(str.charAt(i)==pat.charAt(j)){
i++;
j++;
if(j==patLen){
out.println(i-j);
j=failure[j-1]+1;
}
} else if (j==0){
i++;
}else{
j=failure[j-1]+1;
}
}
}
public static void main(String[] args) {
new Main();
}
}

.subString method not working correctly, Java

I am creating a simple program to convert binary numbers to hex, without the use of the methods provided by Java to do so. I have most of my code already, I'm just having trouble with my "split string" method.
Basically all I am trying to do in this method is
1) Take in a string (binary number)
2) Create an array of strings to hold the "groupings" of numbers
3) Split the binary number into groups of 4 digits (e.g. 10011101 = 1001, 1101)
4) Return the array of groupings
However, when using my method, it always only takes 3 for the first element in my "groupings" array. (e.g. should be "1001", but only putting "100"). What am I doing wrong here?
public String[] splitIntoFours (String toSplit) {
int stringPart = 4;
int arraySize = toSplit.length() / 4;
String[] groupings = new String[arraySize];
for (int iterator = 0; (iterator * stringPart) < toSplit.length(); iterator++){
//If statement to deal with the inital case of the iterator being 0,
//where this algorithm only takes the first 3 numbers instead of a
//sequence of 4 numbers.
int start = iterator * stringPart;
int end = start + stringPart;
if (end > toSplit.length()) {
end = toSplit.length();
}
groupings[iterator] = toSplit.substring(start, end);
}
return groupings;
}
Remember that substring will not return the character at the index denoted by end. It returns end-1.
The Javadoc and extract
public String substring(int beginIndex,
int endIndex)
Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.
Examples:
"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile"
The second parameter (endIndex) in String.substring is exclusive, look closely at the examples in the doc.
Copying this code and running it, it works correctly. So there is no problem. The output, using a String.length dividable through 4, is correct.
Your method works fine, although it throws an error when the size of the number that has to be split is not an multiple of four. This method is a bit more generic:
public static String[] split(String str, int sizeOfGroups) {
int arraySize = str.length() / sizeOfGroups;
String[] groupings = new String[arraySize+1];
int num1, num2;
for (int i = 0; i * sizeOfGroups < str.length(); i++) {
num1 = i * sizeOfGroups + sizeOfGroups;
num2 = i * sizeOfGroups;
if ((num1 >= str.length())) {
groupings[i] = str.substring(num2, str.length());
} else {
groupings[i] = str.substring(num2, num1);
}
}
return groupings;
}

Categories

Resources