I have a large string like "wall hall to wall hall fall be", and I want to print longest strings. Then i want to know how many times all longest strings Is repeated?
For exampele,longest strings are:
wall Is repeated 2
hall Is repeated 2
fall Is repeated 1
This is my code:
public void bigesttstring(String str){
String[] wordsArray=str.split(" ");
int n= str.trim().split("\\s+").length;
int maxsize=0;
String maxWord="";
for(int i=0;i<wordsArray.length;i++){
if(wordsArray[i].length()>maxsize){
maxWord=wordsArray[i];
maxsize=wordsArray[i].length();
}
}
System.out.println("Max sized word is "+maxWord+" with size "+maxsize);
}
But this code only prints "wall".
for count repeated String(i mean "maxWord"),this code write:
int count=0;
for(int i=0;i<wordsArray.length;i++){
if(maxWord.equals(wordsArray[i])){
count++;
}
}
and for display other longest strings i have this code:
int k=0;
for(int i=0;i<wordsArray.length;i++){
if(maxWord.equals(wordsArray[i])){
continue;
}
if(maxsize==wordsArray[i].length()){
k++;
}
}
String[] other=new String[k];
int o=0;
for(int i=0;i<wordsArray.length;i++){
if(maxWord.equals(wordsArray[i])){
continue;
}
if(maxsize==wordsArray[i].length()){
other[o]=wordsArray[i];
o++;
}
}
I allowed to use this functions:
char char At(int i);
int ComoareTo(String another string);
boolean endsWith(String suffix);
int indexof();
int indexof(String str);
String substring();
char[] toCharArray();
String lowercase();
And want another code like this for shortest strings.
You have written
if(wordsArray[i].length()>maxsize)
For wall, hall and fall, it is only true for first wall. That's why you are getting wall and size 4.
Here you are not considering that the longest string length may be same for different string. You will have to store the longest string in an array and if condition should be
if(wordsArray[i].length()>=maxsize)
you will consider = and > case seperately. Since in the case of > you will have to delete all the string in array.
You need to change it to equal because currently if the words is the same length as the current largest word it will ignore it. Also if you want it to have the biggest words. You need to store them in an array. I implemented it here.
package OtherPeoplesCode;
public class string {
public static void main(String[] args) {
bigeststring("wall hall to wall hall fall be");
}
public static void bigeststring(String str){
String[] wordsArray=str.split(" ");
String[] biggestWordsArray = new String[wordsArray.length];
int x = 0;
int n= str.trim().split("\\s+").length;
int maxsize=0;
String maxWord="";
for(int i=0;i<wordsArray.length;i++){
if(wordsArray[i].length()>maxsize){
maxWord=wordsArray[i];
maxsize=wordsArray[i].length();
for(int y = 0; y <= biggestWordsArray.length -1; y++){
biggestWordsArray[y] = "";
}
}
else if(maxsize==wordsArray[i].length()){
biggestWordsArray[x] = wordsArray[i];
x++;
}
}
if(biggestWordsArray[0].equals("")){
System.out.println("Max sized word is "+maxWord+" with size "+maxsize);
}
else if(!(biggestWordsArray[0].equals(""))){
System.out.println("TIE!");
for(int y = 0; y <= biggestWordsArray.length -1; y++){
if(!(biggestWordsArray[y].equals(""))){
System.out.print("Word #" + y + " is ");
System.out.println(biggestWordsArray[y]);
}
}
}
}
}
EDIT: This is the working code, sorry about the delay.
Using Map is possibly the most straight-forward and easy way to do. However if you said your teacher don't allow you to use that, may you tell us what is allowed? So that we don't end up wasting time suggesting different methods and end up none of them is acceptable because your teacher doesn't allow.
One most brute force way that I can suggest you to try is (lots of place for optimization, but I think you may want the easiest way):
loop through the list of words, and find out the length of the longest word and number of words with such length
Create a new array with "number of word" you found in 1. Loop through the original word list again, for each word with length == maxWordLength, put that in the new array IF it is not already existed in it (a simple check by a loop.
Now you have a list that contains all DISTINCT words that are "longest", with some possible null at the end. In order to display them in a format like "word : numOfOccurence", you can do something like
loop through result array until you hit null. For each word in the result array, have a loop in the original word list to count its occurence. Then you can print out the message as you want
in psuedo code:
String[] wordList = ....;
int maxLen = 0;
int maxLenOccurence = 0;
foreach word in wordList {
if word is longer then maxLen {
maxLen = word's length
maxLenOccurence = 1;
}
else if word's length is equals to maxLen {
maxLenOccurence ++
}
}
// 2,3
String[] maxLenWordList = new String[maxLenOccurence];
foreach word in wordList {
else if word's length is equals to maxLen {
for i = 0 to maxLenWordList length {
if (maxLenWordList[i] == word)
break
if (maxLenWordList[i] == null
maxLenWordList[i] = word
}
}
//4
foreach maxLenWord in maxLenWordList {
count = 0
foreach word in wordList {
if maxLenWord == word
count ++
}
display "Max sized word is "+ maxLenWord + " with size " + count
}
Another way doesn't involve other data structure is:
Have the word list
Sort the word list first by length then by the literal value
First element of the result list is the longest one, and string with same value become adjacent. You can do a loop print out all matching and its count (do some thinking by yourself here. Shouldn't be that hard)
Also you can use this;
String[] allLongestStrings(String[] inputArray) {
List<String> list = new ArrayList<String>();
int max = 0;
for (int i = 0; i < inputArray.length; i++) {
StringBuilder s = new StringBuilder(inputArray[i]);
int n = s.length();
if (n > max) {
max = n;
}
}
for (int i = 0; i < inputArray.length; i++) {
StringBuilder s = new StringBuilder(inputArray[i]);
int n = s.length();
if (n == max) {
list.add(s.toString());
}
}
return list.toArray(new String[list.size()]);
}
Related
This question already has answers here:
How to sort String array by length using Arrays.sort()
(10 answers)
Closed 10 months ago.
INPUT: this is my string
OUTPUT: is my this string
I have to arrange words in a sentence according to their length and if two words have the same length then print them alphabetically (the first priority is length).
My incorrect code:
import java.util.Scanner;
class accordingtolength
{
void main()
{
String result="";
Scanner sc=new Scanner(System.in);
System.out.println("Enter the String");
String str=sc.nextLine();
String arr[]=str.split(" ");
int l=arr.length;
for(int i=0;i<l-1;i++)
{
String temp=arr[i]+" ";
String temp1=arr[i+1]+" ";
int a=temp.length();
int b=temp1.length();
if(a==b)
{
int c=temp.compareTo(temp1);
if(c>0)
result=temp1.concat(temp);
else
result=temp.concat(temp1);
}
else if(a>b)
result=temp1.concat(temp);
else
result=temp.concat(temp1);
}
System.out.println(result);
}
}
I know my code is incorrect so there is no need to attach the output.
Please help.
Perhaps this is what you were looking for. Using minimal external classes, this simply sorts the array of words in ascending order based on their length first and then alphabetically if those lengths are equal It uses a variant of what is known as a selection sort. It is a basic sort and quite often used as an introduction to sorting. But it is not very efficient.
read in the string and split based on spaces (I modified your regex to allow 1 or more spaces).
then use nested loops to iterate thru the list, comparing lengths.
if the word indexed by the outer loop (i) is longer than the word indexed by the inner loop (j), swap the words.
else if equal length compare words to each other and sort alphabetically (the String class implements the Comparable interface).
when both loops are finished, the array will be sorted in
then you can just iterate over the result building a string of words separated by spaces.
public class AccordingToLength {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the String:");
String str = sc.nextLine();
String arr[] = str.split("\\s+");
for (int i = 0; i < arr.length-1; i++) {
int outer = arr[i].length();
for (int j = i + 1; j < arr.length; j++) {
int inner = arr[j].length();
if (outer > inner || outer == inner && arr[i].compareTo(arr[j]) > 0) {
String temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
outer = inner; // outer has new length (what was just swapped)
}
}
}
String result = "";
for (String word : arr) {
result += word + " ";
}
System.out.println(result);
}
}
for input = "if a day now any easy when new test is done do den deed none"; this prints
a do if is any day den new now deed done easy none test when
There are multiple ways to solve this problem. The two most convenient ways are.
If you are allowed to use streams and comparator, then you can achieve it in a single line.
Arrays.stream(arr)
.sorted(Comparator
.comparing(String::length)
.thenComparing(Function.identity()))
.forEach(System.out::println);
Using Arrays.sort() to sort the actual array elements.
Arrays.sort(arr, (o1, o2) -> {
if (o1.length() > o2.length()) {
return 1;
} else if (o2.length() > o1.length()) {
return -1;
} else {
return o1.compareTo(o2);
}
});
System.out.println(Arrays.toString(arr));
If you don't want to use java provided APIs and data structures, you can implement a different version of bubble sort.
boolean isSwapped;
for (int i = 0; i < arr.length - 1; i++) {
isSwapped = false;
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j].length() > arr[j + 1].length()
|| arr[j].length() == arr[j + 1].length() && arr[j].compareTo(arr[j + 1]) > 0) {
swap(arr, j, j + 1);
isSwapped = true;
}
}
if (!isSwapped)
break;
}
The problem is
how to get the maximum repeated String in an array using only operations on the arrays in java?
so i got into this question in a test and couldn't figure it out.
lets suppose we have an array of string.
str1[] = { "abbey", "bob", "caley", "caley", "zeeman", "abbey", "bob", "abbey" }
str2[] = { "abbey", "bob", "caley", "caley", "zeeman", "abbey", "bob", "abbey", "caley" }
in str1 abbey was maximum repeated, so abbey should be returned and
in str2 abbey and caley both have same number of repetitions and hence we take maximum alphabet as the winner and is returned(caley here).
c > a
so i tried till
import java.util.*;
public class test {
static String highestRepeated(String[] str) {
int n = str.length, num = 0;
String temp;
String str2[] = new String[n / 2];
for (int k = 0;k < n; k++) { // outer comparision
for (int l = k + 1; l < n; l++) { // inner comparision
if (str[k].equals(str[l])) {
// if matched, increase count
num++;
}
}
// I'm stuck here
}
return result;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("enter how many votes");
int n = sc.nextInt();
String[] str = new String[n];
for (int i = 0; i < n; i++) {
Str[i] = sc.nextLine();
}
String res = highestRepeated(str);
System.out.println(res + " is the winner");
}
}
so, how should i take the count of occurrence of each string with and attach it with the string itself.
All this, without using a map and any hashing but just by using arrays?
Here is a (unpolished) solution:
static String highestRepeated(String[] str) {
String[] sorted = Arrays.copyOf(str, str.length);
Arrays.sort(sorted, 0, sorted.length, Comparator.reverseOrder());
String currentString = sorted[0];
String bestString = sorted[0];
int maxCount = 1;
int currentCount = 1;
for (int i = 1 ; i < sorted.length ; i++) {
if (currentString.equals(sorted[i])) {
currentCount++;
} else {
if (maxCount < currentCount) {
maxCount = currentCount;
bestString = currentString;
}
currentString = sorted[i];
currentCount = 1;
}
}
if (currentCount > maxCount) {
return currentString;
}
return bestString;
}
Explanation:
Sort the array from highest to lowest lexicographically. That's what Arrays.sort(sorted, 0, sorted.length, Comparator.reverseOrder()); does. we sort in this order because you want the largest string if there are multiple strings with the same number of repeats.
Now we can just count the strings by looping through the array. We don't need a hash map or anything because we know that there will be no more of a string in the rest of the array when we encounter a different string.
currentString is the string that we are currently counting the number of repeats of, using currentCount. maxCount is the number of occurrence of the most repeated string - bestString - that we have currently counted.
The if statement is pretty self-explanatory: if it is the same string, count it, otherwise see if the previous string we counted (currentCount) appears more times than the current max.
At the end, I check if the last string being counted is more than max. If the last string in the array happens to be the most repeated one, bestString won't be assigned to it because bestString is only assigned when a different string is encountered.
Note that this algorithm does not handle edge cases like empty arrays or only one element arrays. I'm sure you will figure that out yourself.
another version
static String lastMostFrequent(String ... strs) {
if (strs.length == 0) return null;
Arrays.sort(strs);
String str = strs[0];
for (int longest=0, l=1, i=1; i<strs.length; i++) {
if (!strs[i-1].equals(strs[i])) { l=1; continue; }
if (++l < longest) continue;
longest = l;
str = strs[i];
}
return str;
}
change in
if (++l <= longest) continue;
for firstMostFrequent
you can't use == to check if two strings are the same.
try using this instead:
if (str[k].equals(str[l])) {
// if matched, increase count
num++;
}
Problem: Check if the numbers in the string are in increasing order.
Return:
True -> If numbers are in increasing order.
False -> If numbers are not in increasing order.
The String sequence are :
CASE 1 :1234 (Easy) 1 <2<3<4 TRUE
CASE 2 :9101112 (Medium) 9<10<11<12 TRUE
CASE 3 :9991000 (Hard) 999<1000 TRUE
CASE 4 :10203 (Easy) 1<02<03 FALSE
(numbers cannot have 0 separated).
*IMPORTANT : THERE IS NO SPACES IN STRING THAT HAVE NUMBERS"
My Sample Code:
// converting string into array of numbers
String[] str = s.split("");
int[] numbers = new int[str.length];
int i = 0;
for (String a : str) {
numbers[i] = Integer.parseInt(a.trim());
i++;
}
for(int j=0;j<str.length;j++)
System.out.print(numbers[j]+" ");
//to verify whether they differ by 1 or not
int flag=0;
for(int j=0;j<numbers.length-1;j++){
int result=Integer.parseInt(numbers[j]+""+numbers[j+1]) ;
if(numbers[j]>=0 && numbers[j]<=8 && numbers[j+1]==numbers[j]+1){
flag=1;
}
else if(numbers[j]==9){
int res=Integer.parseInt(numbers[j+1]+""+numbers[j+2]) ;
if(res==numbers[j]+1)
flag=1;
}
else if(result>9){
//do something
}
}
This is the code I wrote ,but I cant understand how to perform for anything except one-digit-numbers ( Example one-digit number is 1234 but two-digit numbers are 121314). Can anyone have a solution to this problem?. Please share with me in comments with a sample code.
I'm gonna describe the solution for you, but you have to write the code.
You know that the input string is a sequence of increasing numbers, but you don't know how many digits is in the first number.
This means that you start by assuming it's 1 digit. If that fails, you try 2 digits, then 3, and so forth, until you've tried half the entire input length. You stop at half, because anything longer than half cannot have next number following it.
That if your outer loop, trying with length of first number from 1 and up.
In the loop, you extract the first number using substring(begin, end), and parse that into a number using Integer.parseInt(s). That is the first number of the sequence.
You then start another (inner) loop, incrementing that number by one at a time, formatting the number to text using Integer.toString(i), and check if the next N characters of the input (extracted using substring(begin, end)) matches. If it doesn't match, you exit inner loop, to make outer loop try with next larger initial number.
If all increasing numbers match exactly to the length of the input string, you found a good sequence.
This is code for the pseudo-code suggested by Andreas .Thanks for the help.
for (int a0 = 0; a0 < q; a0++) {
String s = in.next();
boolean flag = true;
for (int i = 1; i < s.length() / 2; i++) {
int first = Integer.parseInt(s.substring(0, i));
int k=1;
for (int j = i; j < s.length(); j++) {
if (Integer.toString(first + (k++)).equals(s.substring(j, j + i)))
flag = true;
else{
flag=false;
break;
}
}
if (flag)
System.out.println("YES");
else
System.out.println("NO");
}
I would suggest the following solution. This code generates all substrings of the input sequence, orders them based on their start index, and then checks whether there exists a path that leads from the start index to the end index on which all numbers that appear are ordered. However, I've noticed a mistake (I guess ?) in your example: 10203 should also evaluate to true because 10<203.
import java.util.*;
import java.util.stream.Collectors;
public class PlayGround {
private static class Entry {
public Entry(int sidx, int eidx, int val) {
this.sidx = sidx;
this.eidx = eidx;
this.val = val;
}
public int sidx = 0;
public int eidx = 0;
public int val = 0;
#Override
public String toString(){
return String.valueOf(this.val);
}
}
public static void main(String[] args) {
assert(check("1234"));
assert(check("9101112"));
assert(check("9991000"));
assert(check("10203"));
}
private static boolean check(String seq) {
TreeMap<Integer,Set<Entry>> em = new TreeMap();
// compute all substrings of seq and put them into tree map
for(int i = 0; i < seq.length(); i++) {
for(int k = 1 ; k <= seq.length()-i; k++) {
String s = seq.substring(i,i+k);
if(s.startsWith("0")){
continue;
}
if(!em.containsKey(i))
em.put(i, new HashSet<>());
Entry e = new Entry(i, i+k, Integer.parseInt(s));
em.get(i).add(e);
}
}
if(em.size() <= 1)
return false;
Map.Entry<Integer,Set<Entry>> first = em.entrySet().iterator().next();
LinkedList<Entry> wlist = new LinkedList<>();
wlist.addAll(first.getValue().stream().filter(e -> e.eidx < seq
.length()).collect(Collectors.toSet()));
while(!wlist.isEmpty()) {
Entry e = wlist.pop();
if(e.eidx == seq.length()) {
return true;
}
int nidx = e.eidx + 1;
if(!em.containsKey(nidx))
continue;
wlist.addAll(em.get(nidx).stream().filter(n -> n.val > e.val).collect
(Collectors.toSet()));
}
return false;
}
}
Supposed the entered string is separated by spaces, then the code below as follows, because there is no way we can tell the difference if the number is entered as a whole number.
boolean increasing = true;
String string = "1 7 3 4"; // CHANGE NUMBERS
String strNumbers[] = string.split(" "); // separate by spaces.
for(int i = 0; i < strNumbers.length - 1; i++) {
// if current number is greater than the next number.
if(Integer.parseInt(strNumbers[i]) > Integer.parseInt(strNumbers[i + 1])) {
increasing = false;
break; // exit loop
}
}
if(increasing) System.out.println("TRUE");
else System.out.println("FALSE");
How can i get the # of times a single word is in a given sentence.. String.split cannot be used.. I don't really need the code. I just need an idea to get started..
package exam2;
import java.util.Arrays;
public class Problem2 {
/**
* #param args
*/
public static String input, word, a, b, c;
public static int index;
public static void Input() {
System.out.println("Enter Sentence: ");
input = IO.readString();
System.out.println("Enter Word: ");
word = IO.readString();
}
public static void Calc() {
Input();
index = input.indexOf(word);
int[] data = new int[input.length()];
data[0] = index;
while (index >= 0) {
System.out.println("Index : " + index);
for (int i = 1; i < data.length; i++) {
data[i] = index;
}
index = input.indexOf(word, index + word.length());
}
int count = 0;
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data.length; j++) {
if (data[i] == data[j]) {
a = input.substring(data[i], data[i] + word.length());
}
else if (data[i] != data[j]) {
b = input.substring(data[i], data[i] + word.length());
c = input.substring(data[j], data[j] + word.length());
}
}
}
if (a.equalsIgnoreCase(word)) {
count++;
}
System.out.println(count);
}
public static void main(String[] args) {
Calc();
}
}
using a while loop i finding the index of word given by the user in the sentence again given by the user.. I am storing those index in the array. for some reason that is not working.. so i found another way of implementing it. if the index of that word in the array is the equals each other then the word only exits once. I have got this to work.. but if the word exits more than once that is creating the problem..
Get the first letter of the word given by user.Next look at the sentence and find the letter.Then check the second letter of the word and compare it with the next letter in sentence . If its same again continue comparing .If not start again from next letter. Each time you get all the letters of the word and then a space you add 1 to a counter.Think that will work.
Take a look at String.indexOf(String, int). This finds the next position of the parameter String, starting at the parameter int.
Split can't be used? That seems rather odd. I'll bite though, and say simply that we don't have enough information to give a correct answer.
What is a word exactly?
How should symbols/letters be considered?
When is a sentence completed?
Should hyphened words be special?
Do we have 1 sentence and we are testing many words?
Do we have 1 word and many sentence?
What about substring matches (can vs canteen)?
Given what I can guess you should loop through the "sentence" tokenized the input by building "words" until you hit word boundary. Put the found words into a HashMap (keyed on the word) and increment the value for each word as you find it.
You need to call 'input.indexOf(word, fromIndex)' in a loop to find the string. Each time you call this function and it returns something other than -1 increment your count. When it returns -1 or you reach the end of the string stop. fromIndex will start at 0 and will need to be incremented each time you find a string by the length of the string.
The Problem is simple Find "ABC" in "ABCDSGDABCSAGAABCCCCAAABAABC" without using String.split("ABC")
Here is the solution I propose, I'm looking for any solutions that might be better than this one.
public static void main(String[] args) {
String haystack = "ABCDSGDABCSAGAABCCCCAAABAABC";
String needle = "ABC";
char [] needl = needle.toCharArray();
int needleLen = needle.length();
int found=0;
char hay[] = haystack.toCharArray();
int index =0;
int chMatched =0;
for (int i=0; i<hay.length; i++){
if (index >= needleLen || chMatched==0)
index=0;
System.out.print("\nchar-->"+hay[i] + ", with->"+needl[index]);
if(hay[i] == needl[index]){
chMatched++;
System.out.println(", matched");
}else {
chMatched=0;
index=0;
if(hay[i] == needl[index]){
chMatched++;
System.out.print("\nchar->"+hay[i] + ", with->"+needl[index]);
System.out.print(", matched");
}else
continue;
}
if(chMatched == needleLen){
found++;
System.out.println("found. Total ->"+found);
}
index++;
}
System.out.println("Result Found-->"+found);
}
It took me a while creating this one. Can someone suggest a better solution (if any)
P.S. Drop the sysouts if they look messy to you.
How about:
boolean found = haystack.indexOf("ABC") >= 0;
**Edit - The question asks for number of occurences, so here's a modified version of the above:
public static void main(String[] args)
{
String needle = "ABC";
String haystack = "ABCDSGDABCSAGAABCCCCAAABAABC";
int numberOfOccurences = 0;
int index = haystack.indexOf(needle);
while (index != -1)
{
numberOfOccurences++;
haystack = haystack.substring(index+needle.length());
index = haystack.indexOf(needle);
}
System.out.println("" + numberOfOccurences);
}
If you're looking for an algorithm, google for "Boyer-Moore". You can do this in sub-linear time.
edit to clarify and hopefully make all the purists happy: the time bound on Boyer-Moore is, formally speaking, linear. However the effective performance is often such that you do many fewer comparisons than you would with a simpler approach, and in particular you can often skip through the "haystack" string without having to check each character.
You say your challenge is to find ABC within a string. If all you need is to know if ABC exists within the string, a simple indexOf() test will suffice.
If you need to know the number of occurrences, as your posted code tries to find, a simple approach would be to use a regex:
public static int countOccurrences(string haystack, string regexToFind) {
Pattern p = Pattern.compile(regexToFind);
Matcher m = p.matcher(haystack); // get a matcher object
int count = 0;
while(m.find()) {
count++;
}
return count;
}
Have a look at http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm
public class NeedleCount
{
public static void main(String[] args)
{
String s="AVBVDABCHJHDFABCJKHKHF",ned="ABC";
int nedIndex=-1,count=0,totalNed=0;
for(int i=0;i<s.length();i++)
{
if(i>ned.length()-1)
nedIndex++;
else
nedIndex=i;
if(s.charAt(i)==ned.charAt(nedIndex))
count++;
else
{
nedIndex=0;
count=0;
if(s.charAt(i)==ned.charAt(nedIndex))
count++;
else
nedIndex=-1;
}
if(count==ned.length())
{
nedIndex=-1;
count=0;
totalNed++;
System.out.println(totalNed+" needle found at index="+(i-(ned.length()-1)));
}
}
System.out.print("Total Ned="+totalNed);
}
}
Asked by others, better in what sense? A regexp based solution will be the most concise and readable (:-) ). Boyer-Moore (http://en.wikipedia.org/wiki/Boyer–Moore_string_search_algorithm) will be the most efficient in terms of time (O(N)).
If you don't mind implementing a new datastructure as replacement for strings, have a look at Tries: http://c2.com/cgi/wiki?StringTrie or http://en.wikipedia.org/wiki/Trie
If you don't look for a regular expression but an exact match they should provide the fastest solution (proportional to length of search string).
public class FindNeedleInHaystack {
String hayStack="ASDVKDBGKBCDGFLBJADLBCNFVKVBCDXKBXCVJXBCVKFALDKBJAFFXBCD";
String needle="BCD";
boolean flag=false;
public void findNeedle() {
//Below for loop iterates the string by each character till reaches max length
for(int i=0;i<hayStack.length();i++) {
//When i=n (0,1,2... ) then we are at nth character of hayStack. Let's start comparing nth char of hayStach with first char of needle
if(hayStack.charAt(i)==needle.charAt(0)) {
//if condition return true, we reach forloop which iterates needle by lenghth.
//Now needle(BCD) first char is 'B' and nth char of hayStack is 'B'. Then let's compare remaining characters of needle with haystack using below loop.
for(int j=0;j<needle.length();j++) {
//for example at i=9 is 'B', i+j is i+0,i+1,i+2...
//if condition return true, loop continues or else it will break and goes to i+1
if(hayStack.charAt(i+j)==needle.charAt(j)) {
flag=true;
} else {
flag=false;
break;
}
}
if(flag) {
System.out.print(i+" ");
}
}
}
}
}
Below code will perform exactly O(n) complexity because we are looping n chars of haystack. If you want to capture start and end index's of needle uncomment below commented code. Solution is around playing with characters and no Java String functions (Pattern matching, IndexOf, substring etc.,) are used as they may bring extra space/time complexity
char[] needleArray = needle.toCharArray();
char[] hayStackArray = hayStack.toCharArray();
//java.util.LinkedList<Pair<Integer,Integer>> indexList = new LinkedList<>();
int head;
int tail = 0;
int needleCount = 0;
while(tail<hayStackArray.length){
head = tail;
boolean proceed = false;
for(int j=0;j<needleArray.length;j++){
if(head+j<hayStackArray.length && hayStackArray[head+j]==needleArray[j]){
tail = head+j;
proceed = true;
}else{
proceed = false;
break;
}
}
if(proceed){
// indexList.add(new Pair<>(head,tail));
needleCount++;
}
++tail;
}
System.out.println(needleCount);
//System.out.println(indexList);