Recursively finding indices of a string - java

I'm trying to write a code that returns an Array whose elements are the indices of the word(occurences) that I'm looking for in a string :
ex)
d
Input:
String sent = "Hi is Hi is Hi is";
String find = "Hi";
ArrayList<Integer> index = indexFinder(sent,find);
For(int i=0;i<index.size(),i++)
System.out.println(index.get(i));
Output:
0
6
12
It would be very nice if Java had a string slicing function like python.. but since it does not.. I tried to use substring() method.
import java.util.ArrayList;
public class recursionEx {
ArrayList<Integer> index = new ArrayList<Integer>();
ArrayList<Integer> indexFinder(String sent, String find){
int pos =0;
int subPos =0;
if(sent.contains(find)==false){
return index;
}
else if(sent.contains(find)){
pos = sent.indexOf(find);
index.add(pos);
subPos = pos+find.length();
return indexFinder(sent.substring(subPos),find);
}
return index;
}
public static void main(String[] args) {
String sent = "Hi is Hi is Hi is";
String find = "Hi";
recursionEx r = new recursionEx();
ArrayList<Integer> g = r.indexFinder(sent, find);
for(int i=0;i<g.size();i++){
System.out.println(g.get(i));
}
}
}
the output was
0
4
4
In hindsight, I'm gettng the substring of the original String sent every iteration, thus elements in index Array are the indices of the String find in substring of String sent which are 0,4,4.
How can I fix this to get the desired output?
Any help is appreciated!

You should not use the substring as parameter, but only the start of the search in the string. Here is a way that works, it is not perfect, try to make it better :
import java.util.ArrayList;
public class recursionEx {
ArrayList<Integer> index = new ArrayList<Integer>();
String string;
recursionEx(String string){this.string = string;}
ArrayList<Integer> indexFinder(int position, String find){
int pos =0;
int subPos =0;
if(string.substring(position).contains(find)==false){
return index;
}
else if(string.substring(position).contains(find)){
pos = string.substring(position).indexOf(find) + position;
index.add(pos);
subPos = pos+find.length();
return indexFinder(subPos,find);
}
return index;
}
public static void main(String[] args) {
String sent = "Hi is Hi is Hi is";
String find = "Hi";
recursionEx r = new recursionEx(sent);
ArrayList<Integer> g = r.indexFinder(0, find);
for (Integer pos : g)
System.out.println(pos);
}
}

Add the length of the former substring to each following output, then you get the correct numbers. You can calculate these lengths by the older indices.

You don't have to use recursion to find the indices of substrings but rather use indexOf(searchstring, offset) until you don't find the search string anymore.
Alternatively use regex, i.e. Pattern and Matcher and collect the group(0) indices.
Edit:
Since you want to use recursion you could change the loop into recursive calls. In that case you could just pass the offset to the recursive call as well and keep using indexOff(find, offset).
If you want to do it using substring() you'd also have to keep track of the substring's position in the original string and add that to the results of indexOf(find), otherwise you get the indices relative to the substring only.

Related

NumberFormatException when trying to use parseInt()and trim() does not fix it

Hi I am trying to solve a Kata(coding practice exercise) in CodeWars which is called "Your order, please" (there is a BIG chance that my code won't solve it but I am really just trying to get rid of the error..and there's a link to the exercise at the end in case you want to check it out)
Either way what the Kata basically says is that you will be given a String such as
"4of Fo1r pe6ople g3ood th5e the2"
and you have to order the words by getting the int and returning in the correct order so
"Fo1r the2 g3ood 4of th5e pe6ople"
Now what I coded is supposed to go through each element and get the number to then order it, so I tried to use parseInt and it did not work. I read on another article that trim() would get rid of...
java.lang.NumberFormatException: For input string: "4of" //trim did not fix it
I am not sure whether I did not implement trim() correctly or parseInt() or what is wrong, any help would be very much appreciated and thank you for taking your time to read this. Without further ado here's the code.
public class Kata {
public static String order(String words) {
String[] unordered = words.split(" ");
String[] order = new String[unordered.length];
System.out.println(unordered.length);
for(int i = 0; i < unordered.length; i++){
int correctIndex = (Integer.parseInt(unordered[i].trim())) -1;
order[correctIndex] = unordered[i];
System.out.println(unordered[i]);
}
return "I will return order concatenated";
}
public static void main(String[] args) {
System.out.println(order("4of Fo1r pe6ople g3ood th5e the2"));
}
}
And the error... (6 is the output before it)
6
Exception in thread "main" java.lang.NumberFormatException: For input string: "4of"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at Kata.order(Kata.java:8)
at Kata.main(Kata.java:17)
https://www.codewars.com/kata/55c45be3b2079eccff00010f/train/java
(the link to the Kata)
4of is not an integer string and therefore, you can not parse it into an int. You can replace its non-digit characters (\D) with "" and then you can parse it to an int. Learn more about regex patterns from the documentation of java.util.regex.Pattern.
The problem can be solved in the following simple steps:
Split the sentence on space (which you have already done).
Create an int[] original and populate it with embedded numeric values from the resulting, String[] unordered.
Create a clone of original[] and sort the same. Let's say this clone is int[] order.
Populate a String[] ordered based on order[].
Join the elements of ordered[] on space.
Demo:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String words = "4of Fo1r pe6ople g3ood th5e the2";
String[] unordered = words.split(" ");
String[] ordered = new String[unordered.length];
int[] original = new int[unordered.length];
// Populate order with embedded numeric values
for (int i = 0; i < unordered.length; i++) {
original[i] = Integer.parseInt(unordered[i].replaceAll("\\D", ""));
}
// Create a clone of original[] and sort it
int[] order = original.clone();
Arrays.sort(order);
// Populate ordered[] based on order[]
for (int i = 0; i < order.length; i++) {
for (int j = 0; j < original.length; j++) {
if (order[i] == original[j]) {
ordered[i] = unordered[j];
break;
}
}
}
// Join the elements of ordered[] on space
String result = String.join(" ", ordered);
System.out.println(result);
}
}
Output:
Fo1r the2 g3ood 4of th5e pe6ople
Just remove all non-numeric characters (by using regex replacement) and then parse the resulting value to an integer.
for (int i = 0; i < unordered.length; i++){
String wordNum = unordered[i].trim().replaceAll("\\D+", "");
int correctIndex = (Integer.parseInt(wordNum)) - 1;
order[correctIndex] = unordered[i];
}
NumberFormatException is thrown when
The input string provided might be null. Example-
Integer.parseInt(null);
The input string might be empty. Example-
Integer.parseInt("");
The input string might be having trailing space. Example-
Integer.parseInt("123 ");
The input string might be having a leading space. Example-
Integer.parseInt(" 123");
The input string may be alphanumeric.Example-
Long.parseLong("b2");
There are other reasons also. You are trying to pass unordered[i] in parseInt.
int correctIndex = (Integer.parseInt(unordered[i].trim())) -1;
It is an alphanumeric String. So the compiler gives NumberFormatException.
Try using this function to calculate the index instead.
//Method to find the correctIndex
static int findIndex(String s)
{
char ch;
//Access all the characters of the String and the find the digit
for (int i = 0;i < s.length();i++)
{
ch = s.charAt(i);
if (Character.isDigit(ch))
{
return ch-49; //Convert the character to index
}
}
return -1;
}

location and repetition of characters within a string

Hi biologist here with a little bit of coding background. my goal is to be able to input a string of characters and the code to be able to tell me how many times they occur and at what location in the string.
so ill be entering a string and i want the location and abundance of sq and tq within the string. with the location being the first character e.g njnsqjjfl sq would be located at postition 4.
This is what ive come up with so far (probably very wrong)
string S = "...";
int counter =0;
for(int i=0; i<s.length; i++){
if(s.charAt (i) == 'sq')}
counter++;})
string S = "...";
int counter =0;
for(int i=0; i<s.length; i++){
if(s.charAt (i) == 'tq')}
counter++;})
any input will help, thankyou
So , you can have multiple occurrences of "sq" and "tq" in your code, so you can have 2 arraylists to save these two separately(or one to save them together).
ArrayList<Integer>sqLocation = new ArrayList<>();
ArrayList<Integer>tqLocation = new ArrayList<>();
for(int i =0;i<s.length()-1;i++){
if(s.charAt(i)=='s' && s.charAt(i+1)=='q'){
sqLocation.add(i);
}
else if(s.charAt(i)=='t' && s.charAt(i+1)=='q'){
tqLocation.add(i);
}
}
System.out.println("No. of times sq occurs = "+sqLocation.size());
System.out.println("Locations ="+sqLocation);
System.out.println("No. of times tq occurs = "+tqLocation.size());
System.out.println("Locations ="+tqLocation);
This can be achieved using regex. Your use case is to count occurrences and position of those occurrences. The method match returns an integer list which is position and count is size of list
Exmaple code
public class RegexTest {
public static List<Integer> match(String text, String regex) {
List<Integer> matchedPos = new ArrayList<>();
Matcher m = Pattern.compile("(?=(" + regex + "))").matcher(text);
while(m.find()) {
matchedPos.add(m.start());
}
return matchedPos;
}
public static void main(String[] args) {
System.out.println(match("sadfsagsqltrtwrttqsqsqsqsqsqs", "sq"));
System.out.println(match("sadfsagsqltrtwrttqksdfngjfngjntqtqtqtqtqtq", "tq"));
}
}
what you want is a HashMap <String, List <Integer>>
this will hold, the String that you are looking for e.g. sq or tq, and a List of the positions that they are at.
You want to loop around using String.indexOf see https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#indexOf(java.lang.String,%20int)
psuedocode being
String contents = "sadfsagsqltrtwrttqksdfngjfngjntqtqtqtqtqtq";
map.add (lookFor, new ArrayList ());
int index = 0;
while ((index = contents.indexOf (lookFor, index)) != -1) {
list = map.get (lookFor);
list.add (index);
}
You should use not charAt but substring to get a part of String.
int count(String s, String target) {
int counter = 0;
int tlen = target.length();
for (int i = tlen; i < s.length(); i++) {
if (s.substring(i - tlen, i).equals(target)) {
counter++;
}
}
return counter;
}
// in some method
count("...", "sq");
count("...", "tq");

Obtain lexicographically smallest & largest substring. My algorithm failed most of the test cases but I can't understand why. Help me figure it out

I had to do a test today for an interview and the problem was obtaining the lexicographically smallest and largest substring (in other words, sort by name).
Link - Complete the function SmallestAndLargestSubstring, which takes a string S consisting of lowercase English letters (a-z) as its argument and returns lexicographically smallest and largest substrings which start with a vowel and end with a consonant.
My algorithm passed the basic test cases but failed most of the others. It's not the most efficient code, but it was the fastest to write.
static String[] SmallestAndLargestSubstring(String s) {
ArrayList<Character> vowelList = new ArrayList<Character>();
vowelList.add('a');
vowelList.add('e');
vowelList.add('i');
vowelList.add('o');
vowelList.add('u');
ArrayList<Character> consonantList = new ArrayList<Character>();
for (char c='a'; c<='z'; c++) {
if (!vowelList.contains(c))
consonantList.add(c);
}
ArrayList<String> substringList = new ArrayList<String>();
for (int i=0; i<s.length(); i++) {
char c = s.charAt(i);
if (vowelList.contains(c)) {
String substring = "";
substring+=c;
for (int j=i+1; j<s.length(); j++) {
char c2 = s.charAt(j);
substring+=c2;
if (consonantList.contains(c2)) {
substringList.add(substring);
}
}
}
}
Collections.sort(substringList);
String[] outputAdapter = new String[2];
outputAdapter[0]=substringList.get(0);
outputAdapter[1]=substringList.get(substringList.size()-1);
return outputAdapter;
}
Anyway, I wanted to figure out where I went wrong, so I reversed engineered the test cases to figure out what was the input being passed in, and hopefully I would be able to figure out what was wrong with my algorithm.
Here's what I uncovered, and these are my answers (which are wrong according to the test cases).
Input
String s = "azizezozuzawwwwwwwwwuzzzzzzzzabbbbbbbaaaabbbboiz"
My answer
smallest = "aaaab";
largest = "uzzzzzzzzabbbbbbbaaaabbbboiz";
But for the life of me, I can't figure out where my mistake is. Here's my full list of substrings, sorted from the smallest to the largest. Link to sorted results
Been racking my brains for the last 3 hours. I'd be grateful if anyone can figure out where my mistake was.
Edit: Here are 3 more test cases. My answers match these test case answers.
string = "aba"; smallest = "ab"; largest = "ab";
string = "aab"; smallest = "aab"; largest = "ab";
string = "abababababbaaaaaaaaaaaaaaz"; smallest = "aaaaaaaaaaaaaaz"; largest = "az";
/*
It is the Basic code to Obtain Substring which start with Vowel and End up with Consonant. It is going to print on the Basis of Name Comparable, The first and the Last Substring in the List.Similarly we can achieve on the basis of length, the firt and last Substring using different comparator function.
*/
public class StringSubsequencesStartVowelEndConsonant {
static List<String> subsequence = new LinkedList<>();
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.println("Enter the String:\n");
String string = in.next();
findSubstring(string);
}
private static void findSubstring(String string) {
for(int i=0;i<string.length();i++){
if(isVowel(string.charAt(i))){
for(int j=string.length()-1;j>=i;j--){
if(isConsonant(string.charAt(j))){
String subString = string.substring(i,j+1);
subsequence.add(subString);
}
}
}
}
Collections.sort(subsequence);
for(String str : subsequence){
System.out.print(str+" ");
}
System.out.println();
System.out.println(subsequence.get(0));
System.out.println(subsequence.get(subsequence.size()-1));
}
private static boolean isConsonant(char chars) {
return !(chars=='a'|| chars=='e'||chars=='i'||chars=='o'||chars=='u');
}
private static boolean isVowel(char chars) {
return (chars=='a'|| chars=='e'||chars=='i'||chars=='o'||chars=='u');
}
}

Repetition of a word in String with out using collections

Can any one suggest me to write a logic for this without using collections.
I have a string s="This is the place called island and it is a nice place ";
Input String to find repetition word is: "is";
output should be : 4
You can follow the below logic to do it.
Split the String on whitespace.
Initialize an integer counter to 0.
Traverse through each of the elements of the resultant array and for each String element of the array, do the following:
a) If stringElement.contains("is"), increment the counter created in step 2.
b) If !stringElement.contains("is"), do nothing and move on to the next element.
Do this till you exhaust all the elements of the array.
Print the counter value.
Try to write the code for this on your own and get back here if you're stuck up anywhere.
As simple as
int count = 0;
for (int startIndex = 0; startIndex >= 0; startIndex = str.indexOf("is", startIndex)) {
count++;
}
Use the following method, it should work:
public static int countSubStrings(String subString, String mainString){
return (mainString.length() - mainString.replace(subString, "").length()) / subString.length();
}
string s="This is the place called island and it is a nice place ";
s = s+" ";
System.out.println(s.split("is").length-1);
you can use this. Hope you are using Java.
public static void main(String[] args) {
String str = "This is the place called island and it is a nice place";
Pattern pattern = Pattern.compile("is");
Matcher matcher = pattern.matcher(str);
int count = 0;
while (matcher.find())
count++;
System.out.println(count); // prints 4
}
this method will count how many time s2 appears in s1
public static int CountStr(String s1,String s2){
int cnt=0,temp=0;
if(s1.indexOf(s2)>0){
temp=s1.indexOf(s2);
cnt++;
}
while(s1.indexOf(s2,temp+1)>0){
cnt++;
temp=s1.indexOf(s2,temp+1);
}
return cnt;
}

Removing duplicates from a string

I am trying to remove duplicates from a String in Java. Here i what I have tried
public void unique(String s)
{
// put your code here
char[]newArray = s.toCharArray();
Set<Character> uniquUsers = new HashSet<Character>();
for (int i = 0; i < newArray.length; i++) {
if (!uniquUsers.add(newArray[i]))
newArray[i] =' ';
}
System.out.println(new String(newArray));
}
Problem with this is when I try to remove the duplicate I replace it with a space. I tried replacing the duplicate with '' but it cannot be done or I cant set the duplicate place to null. What is the best way to do this?
If you use regex, you only need one line!
public void unique(String s) {
System.out.println(s.replaceAll("(.)(?=.*\\1)", ""));
}
This removes (by replacing with blank) all characters that found again later in the input (by using a look ahead with a back reference to the captured character).
If I understand your question correctly, perhaps you could try something like:
public static String unique(final String string){
final StringBuilder builder = new StringBuilder();
for(final char c : string.toCharArray())
if(builder.indexOf(Character.toString(c)) == -1)
builder.append(c);
return builder.toString();
}
You can use BitSet
public String removeDuplicateChar(String str){
if(str==null || str.equals(""))throw new NullPointerException();
BitSet b = new BitSet(256);
for(int i=0;i<str.length();i++){
b.set(str.charAt(i));
}
StringBuilder s = new StringBuilder();
for(int i=0;i<256;i++){
if(b.isSet(i)){
s.append((char)i);
}
}
return s.toString();
}
You can roll down your own BitSet like below:
class BitSet {
int[] numbers;
BitSet(int k){
numbers = new int[(k >> 5) + 1];
}
boolean isSet(int k){
int remender = k & 0x1F;
int devide = k >> 5;
return ((numbers[devide] & (1 << remender)) == 1);
}
void set(int k){
int remender = k & 0x1F;
int devide = k >> 5;
numbers[devide] = numbers[devide] | (1 << remender);
}
}
This will work for what you are attempting.
public static void unique(String s) {
// r code here
char[] newArray = s.toCharArray();
Set<Character> uniqueUsers = new HashSet<>();
for (int i = 0; i < newArray.length; i++) {
uniqueUsers.add(newArray[i]);
}
newArray = new char[uniqueUsers.size()];
Iterator iterator = uniqueUsers.iterator();
int i = 0;
while (iterator.hasNext()) {
newArray[i] = (char)iterator.next();
i++;
}
System.out.println(new String(newArray));
}
without changing almost anything in your code, change the line
System.out.println(new String(newArray));
for
System.out.println( new String(newArray).replaceAll(" ", ""));
the addition of replaceAll will remove blanks
import java.util.*;
class StrDup{
public static void main(String[] args){
String s = "abcdabacdabbbabbbaaaaaaaaaaaaaaaaaaabbbbbbbbbbdddddddddcccccc";
String dup = removeDupl(s);
}
public static String removeDupl(String s){
StringBuilder sb = new StringBuilder(s);
String ch = "";
for(int i = 0; i < sb.length(); i++){
ch = sb.substring(i,i+1);
int j = i+1;
int k = 0;
while(sb.indexOf(ch,j)!=-1){
k = sb.indexOf(ch,j);
sb.deleleCharAt(k);
j = k;
}
}
return sb.toString();
}
}
In the code above, I'm doing the following tasks.
I'm first converting the string to a StringBuilder. Strings in Java are immutable, which means they are like CDs. You can't do anything with them once they are created. The only thing they are vulnerable to is their departure, i.e. the end of their life cycle by the garbage collector, but that's a whole different thing. Foe example:
String s = "Tanish";
s + "is a good boy";
This will do nothing. String s is still Tanish. To make the second line of code happen, you will have to assign the operation to some variable, like this:
s = s + "is a good boy";
And, make no mistake! I said strings are immutable, and here I am reassigning s with some new string. But, it's a NEW string. The original string Tanish is still there, somewhere in the pool of strings. Think of it like this: the string that you are creating is immutable. Tanish is immutable, but s is a reference variable. It can refer to anything in the course of its life. So, Tanish and Tanish is a good boy are 2 separate strings, but s now refers to the latter, instead of the former.
StringBuilder is another way of creating strings in Java, and they are mutable. You can change them. So, if Tanish is a StringBuilder, it is vulnerable to every kind of operation (append, insert, delete, etc.).
Now we have the StringBuilder sb, which is same as the String s.
I've used a StringBuilder built-in method, i.e. indexOf(). This methods finds the index of the character I'm looking for. Once I have the index, I delete the character at that index.
Remember, StringBuilder is mutable. And that's the reason I can delete the characters.
indexOf is overloaded to accept 2 arguments (sb.indexOf(substr ,index)). This returns you the position of the first occurrence of string within the sb, starting from index.
In the example string, sb.indexOf(a,1) will give me 4. All I'm trying to say to Java is, "Return me the index of 'a', but start looking for 'a' from index 1'. So, this way I've the very first a at 0, which I don't want to get rid of.
Now all I'm doing inside the for loop is extracting the character at ith position. j represents the position from where to start looking for the extracted character. This is important, so that we don't loose the one character we need. K represents the result of indexOf('a',j), i.e. the first occurrence of a, after index j.
That's pretty much it. Now, as long as we have a character ch lying in the string (indexOf(....) returns -1, if it can't find the specified character (...or the string as i specified before) as a duplicate, we will obtain it's position (k), delete it using deleteCharAt(k) and update j to k. i.e., the next duplicate a (if it exists) will appear after k, where it was last found.
DEMONSTRATION:
In the example I took, let's say we want to get rid of duplicate cs.
So, we will start looking for the first c after the very first c, i.e. index 3.
sb.indexOf("c",3) will give us 7, where a c is lying. so, k = 7. delete it, and then set j to k. Now, j = 7. Basically after deleting the character, the succeeding string shifts to left by 1. So, now at 7th pos we have d, which was at 8 before. Now, k = indexOf("c",7) and repeat the entire cycle. Also, remember that indexOf("c",j) will start looking right from j. which means if c, is found at j, it will return j. That's why when we extracted the first character, we started looking from position 1 after the character's position.
public class Duplicates {
public static void main(String[] args) {
String str="aabbccddeeff";
String[] str1 = str.split("");
ArrayList<String> List = new ArrayList<String>
Arrays.asList(str1);
List<String> newStr = List.stream().distinct().collect(Collectors.toList());
System.out.print(newStr);
}
}

Categories