Replace a given string at given index with list of words.
The problem statement goes below, can someone give me some intuition or idea how to proceed on this?
//A replacement class similar to Linked List
class Replacement {
int start;
String before;
String after;
//Method to replace the words
public static String replaceRanges(String text, List<Replacement> replacements) {
//TODO your code here
return null;
}
}
/* below is the example of the problem
Example #1:
Input:
text = "num foo"
replacements = [
{start: 0, before: "num", after: "String"},
{start: 4, before: "foo", after: "bar"}
]
Output:
replaceRanges(text, replacements) returns:
"String bar"
Example #2: Input: text = "num_fooBar", Output: "String_barBar"
*/
If you have your replacements sorted from smallest index to highest, you can iterate the list from last to first and search for substrings in input string and replace them if they match
public static String replaceRanges(String text, List<Replacement> replacements) {
StringBuilder s = new StringBuilder(text);
for (int i = replacements.size() - 1; i>=0; i--) {
Replacement r = replacements.get(i);
int begin = r.start;
int end = r.start + r.before.length();
if (begin >= 0 && begin < s.length() && end >= 0 && end <= s.length()) {
if (s.substring(begin, end).equals(r.before)) {
s.replace(begin, end, r.after);
}
}
}
return s.toString();
}
If your list is not sorted, you need to sort it first using Collections.sort().
I used this code for testing:
public static void main(String[] args) {
List<Replacement> replacements = List.of(
new Replacement(0, "num", "String"),
new Replacement(4, "foo", "bar"));
System.out.println(replaceRanges("num foo", replacements)); // Output: String bar
System.out.println(replaceRanges("num_fooBar", replacements)); // Output: String_barBar
System.out.println(replaceRanges("num_f", replacements)); // Output: String_f
System.out.println(replaceRanges("", replacements)); // Output:
System.out.println(replaceRanges("foonum", replacements)); // Output: foonum
}
You could replace your original string one by one and keep in mind that you have to shift the start position (because you could replace the small substring to the bigger substring)
public String replaceRanges(String text, List<Replacement> replacements) {
for(int i = 0; i < replacements.size(); i++) {
Replacement replacement = replacements.get(i);
String firstPart = text.substring(0, replacement.start);
String secondPart = text.substring(replacement.start, text.length());
String updatedSecondPart = secondPart.replace(replacement.before, replacement.after);
text = firstPart + updatedSecondPart;
updateStart(i + 1, replacements, updatedSecondPart.length() - secondPart.length());
}
return text;
}
privat void updateStart(int startIndex, List<Replacement> replacements, int shift) {
for( int i = startIndex; i < replacements.size(); i++) {
Replacement r = replacements.get(i);
r.start += shift;
}
}
Using this method you can process:
Replacement r1 = new Replacement(0, "hi", "Hello");
Replacement r2 = new Replacement(2, "lo", "p");
Sting result = replaceRanges("hi louie!", asList(r1, r2)); //result = 'Hello puie!'
Related
I have a string which I want to split after every n characters and store the same in an array of strings, but this should ignore all the whitespaces.
For example I have a string as follows,
String str = "This is a String which needs to be splitted after every 10 characters";
The output should be,
["This is a Str", "ing which nee", "ds to be split", "ted after ev", "ery 10 chara", "cters"]
(Edit) --> I am using the function below. How can I store this in an array of Strings.
As seen in the output it ignores indexes of all the whitespaces. Is there any way to do it in java.
public static String test(int cnt, String string) {
AtomicInteger n = new AtomicInteger(cnt);
return string
.chars()
.boxed()
.peek(value -> {
if (!Character.isWhitespace(value)) {
n.decrementAndGet();
}
})
.takeWhile(value -> n.get() >= 0)
.map(Character::toString)
.collect(Collectors.joining());
I have used a standard approach with looping through the string and counting chars:
public static void main(String[] args) throws ParseException {
String str = "This is a String which needs to be splitted after every 10 characters";
System.out.println(split(str, 10));
}
public static List<String> split(String string, int splitAfter) {
List<String> result = new ArrayList<String>();
int startIndex = 0;
int charCount = 0;
for (int i = 0; i < string.length(); i++) {
if (charCount == splitAfter) {
result.add(string.substring(startIndex, i));
startIndex = i;
charCount = 0;
}
// only count non-whitespace characters
if (string.charAt(i) != ' ') {
charCount++;
}
}
// check if startIndex is less than string length -> if yes, then last element wont be 10 characters long
if (startIndex < string.length()) {
result.add(string.substring(startIndex));
}
return result;
}
And the result differs slightly from what you posted, but looking at your expected result, it doesn't quite match the description anyways:
[This is a Str, ing which ne, eds to be spl, itted after, every 10 cha, racters]
In this program, I am trying to return a new string that is composed of new letters that were added and old letters if the didn't fit the constraints. I am stuck in terms of I don't know how to fix my code so that it prints correctly. Any help or suggestions is greatly appreciated!
Here are some examples:
str: "asdfdsdfjsdf", word: "sdf", c: "q"
should return "aqdqjq", I'm getting "asdqqq"
str: "aaaaaaaa", word: "aaa", c: "w"
should return "wwaa", as of right now my code only returns "ww"
public static String replaceWordWithLetter(String str, String word, String c)
String result = "";
int index = 0;
while (index < str.length() )
{
String x = str.substring(index, index + word.length() );
if (x.equals(word))
{
x = c;
index = index + word.length();
}
result = result + x;
index++;
}
if (str.length() > index)
{
result = result + str.substring(index, str.length() - index);
}
return result;
}
You seem to be overcomplicating this. You can simply use the replace() method:
public static String replaceWordWithLetter(String str, String word, String c) {
return str.replace(word, c);
}
Which when called as:
replaceWordWithLetter("asdfdsdfjsdf", "sdf", "q")
Produces the output:
aqdqjq
The problem with your current method is that if the substring is not equal to word, then you will append as many characters as there are in word, and then only move up one index. If you will not be replacing the sequence, then you only need to append one character to result. Also it is much more efficient to use a StringBuilder. Also as noted if the String is not divisible by word.length(), this will throw a StringIndexOutOfBoundsError. To solve this you can use the Math.min() method to ensure that the substring does not go out of bounds. Original method with fixes:
public static String replaceWordWithLetter(String str, String word, String c) {
StringBuilder result = new StringBuilder();
int index = 0;
while (index < str.length() )
{
String x = str.substring(index, Math.min(index + word.length(), str.length()));
if (x.equals(word))
{
result.append(c);
index = index + word.length();
}
//If we aren't replacing, only add one char
else {
result.append(x.charAt(0));
index++;
}
}
if (str.length() > index)
{
result.append(str.substring(index, str.length() - index));
}
return result.toString();
}
Found the fix to my issue using #GBlodgett's code:
String result = "";
int index = 0;
while (index <= str.length() - word.length() )
{
String x = str.substring(index, index + word.length() );
if (x.equals(word))
{
result = result + c;
index = index + word.length();
}
else {
result = result + x.charAt(0);
index++;
}
}
if (str.length() < index + word.length())
{
result = result + (str.substring(index));
}
return result;
}
You can use String.replaceAll() method.
example:
public class StringReplace {
public static void main(String[] args) {
String str = "aaaaaaaa";
String fnd = "aaa";
String rep = "w";
System.out.println(str.replaceAll(fnd, rep));
System.out.println("asdfdsdfjsdf".replaceAll("sdf", "q"));
}
}
Output:
wwaa
aqdqjq
I have started to write a code that would reverse every second set of 4 characters. eg. 1234567890987654. The result would be displayed as ("1234" "8765" "9098" "4567"). This would then be multiplied as in "1234" * "8765" * "9098" * "4567".
this code doesn't work and I would like some help.
My code currently is
public static void main(String[] args) {
String input = "1234567890987654";
System.out.println(result);
public static int reverse(String a) {
String newa = "";
String str = a;
char ch;
String[] array = str.split("(?<=\\G.{2})");
a = "array[]";
for (int i = 0 ; i < a.length() ; i=i+2) {
ch = a.charAt(i);
newa = ch + newa;
//System.out.println(newcardNum);
}
return newa;
}
Thanks in adavance
Let's start by creating a proper test framework (at least a toy testing framework) -
public static void main(String[] args) {
String input = "1234567890987654";
String expected = "1234" + "8765" + "9098" + "4567";
String result = reverse(input);
if (result.equals(expected)) {
System.out.println("result matches expected result");
} else {
System.out.println("result does not match expected result");
}
System.out.printf("input='%s', result = '%s'%n", input, result);
}
Now we can tell when the result we receive matches our expected result, and what the input and output String(s) are.
Next, we need to fix your reversing algorithm. You want to get 4 character then reverse 4 characters, so each iteration is 8 characters. Something like,
public static String reverse(String a) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < a.length(); i += 8) { // <-- increment by 8.
sb.append(a.substring(i, i + 4)); // <-- pass 1,4
// get characters 4 to 8
StringBuilder sb2 = new StringBuilder(a.substring(i + 4, i + 8));
// reverse and append
sb.append(sb2.reverse().toString());
}
return sb.toString();
}
Output is
result matches expected result
input='1234567890987654', result = '1234876590984567'
Edit Based on your comments below (and edited question), add something like this to main
String[] arr = new String[4];
long calc = 1; // <-- int would overflow
for (int count = 0, i = 0; i < result.length(); count++, i += 4) {
arr[count] = result.substring(i, i + 4);
calc *= Integer.parseInt(arr[count]);
}
System.out.printf("Array = %s, multiplication = %d%n", Arrays.toString(arr), calc);
And now the output is
result matches expected result
input='1234567890987654', result = '1234876590984567'
Array = [1234, 8765, 9098, 4567], multiplication = 449411337361660
Ok, this is an interview question. And no it's not a duplicate of this question.
Given 3 strings - str1, str2, str3:
str1 = "spqrstrupvqw"
str2 = "sprt"
str3 = "q"
We've to find the minimum window in str1, which contains all characters from str2 in any order, but no character from str3. In this case the answer would be: "strup".
I've come up with this code:
static String minimumWindow(String str1, String str2, String str3) {
class Window implements Comparable<Window> {
int start;
int end;
public Window(int start, int end) {
this.start = start;
this.end = end;
}
public int getEnd() {
return end;
}
public int getStart() {
return start;
}
public int compareTo(Window o) {
int thisDiff = end - start;
int thatDiff = o.end - o.start;
return Integer.compare(thisDiff, thatDiff);
}
#Override
public String toString() {
return "[" + start + " : " + end + "]";
}
}
// Create Sets of characters for "contains()" check
Set<Character> str2Chars = new HashSet<>();
for (char ch: str2.toCharArray()) {
str2Chars.add(ch);
}
Set<Character> str3Chars = new HashSet<>();
for (char ch: str3.toCharArray()) {
str3Chars.add(ch);
}
// This will store all valid window which doesn't contain characters
// from str3.
Set<Window> set = new TreeSet<>();
int begin = -1;
// This loops gets each pair of index, such that substring from
// [start, end) in each window doesn't contain any characters from str3
for (int i = 0; i < str1.length(); i++) {
if (str3Chars.contains(str1.charAt(i))) {
set.add(new Window(begin, i));
begin = i + 1;
}
}
int minLength = Integer.MAX_VALUE;
String minString = "";
// Iterate over the windows to find minimum length string containing all
// characters from str2
for (Window window: set) {
if ((window.getEnd() - 1 - window.getStart()) < str2.length()) {
continue;
}
for (int i = window.getStart(); i < window.getEnd(); i++) {
if (str2Chars.contains(str1.charAt(i))) {
// Got first character in this window that is in str2
// Start iterating from end to get last character
// [start, end) substring will be the minimum length
// string in this window
for (int j = window.getEnd() - 1; j > i; j--) {
if (str2Chars.contains(str1.charAt(j))) {
String s = str1.substring(i, j + 1);
Set<Character> sChars = new HashSet<>();
for (char ch: s.toCharArray()) {
sChars.add(ch);
}
// If this substring contains all characters from str2,
// then only it is valid window.
if (sChars.containsAll(str2Chars)) {
int len = sChars.size();
if (len < minLength) {
minLength = len;
minString = s;
}
}
}
}
}
}
}
// There are cases when some trailing and leading characters are
// repeated somewhere in the middle. We don't need to include them in the
// minLength.
// In the given example, the actual string would come as - "rstrup", but we
// remove the first "r" safely.
StringBuilder strBuilder = new StringBuilder(minString);
while (strBuilder.length() > 1 && strBuilder.substring(1).contains("" + strBuilder.charAt(0))) {
strBuilder.deleteCharAt(0);
}
while (strBuilder.length() > 1 && strBuilder.substring(0, strBuilder.length() - 1).contains("" + strBuilder.charAt(strBuilder.length() - 1))) {
strBuilder.deleteCharAt(strBuilder.length() - 1);
}
return strBuilder.toString();
}
But it doesn't work for all the test cases. It does work for the example given in this question. But when I submitted the code, it failed for 2 test cases. No I don't know the test cases for which it failed.
Even after trying various sample inputs, I couldn't find a test case for which it fails. Can someone take a look as to what is wrong with the code? I would really appreciate if someone can give a better algorithm (Just in pseudo-code). I know this is really not the optimized solution though.
str1 = "spqrstrupvqw"
str2 = "sprt"
str3 = "q"
We're looking for the minimum sub-string from str1 that contain all str2 characters (assume ordered) and no characters from str3 ..
i = 1 .. str1.length
cursor = 1 .. str2.length
The solution must be on the form:
str2.first X X .. X X str2.last
So to check for that sub-string we use a cursor over str2, but we also have the constraint of avoiding str3 characters, so we have:
if str3.contain(str1[i])
cursor = 1
else
if str1[i] == str2[cursor]
cursor++
Goal check is:
if cursor > str2.length
return solution
else
if i >= str1.length
return not-found
And for optimization, you can skip to the next look-ahead which is:
look-ahead = { str2[cursor] or { X | X in str3 }}
In case str2 is not ordered:
i = 1 .. str1.length
lookup = { X | X in str2 }
The solution must be on the form:
str2[x] X X .. X X str2[x]
So to check for that sub-string we use a check-list str2, but we also have the constraint of avoiding str3 characters, so we have:
if str3.contain(str1[i])
lookup = { X | X in str2 }
else
if lookup.contain(str1[i])
lookup.remove(str1[i])
Goal check is:
if lookup is empty
return solution
else
if i >= str1.length
return not-found
And for optimization, you can skip to the next look-ahead which is:
look-ahead = {{ X | X in lookup } or { X | X in str3 }}
Code
class Solution
{
private static ArrayList<Character> getCharList (String str)
{
return Arrays.asList(str.getCharArray());
}
private static void findFirst (String a, String b, String c)
{
int cursor = 0;
int start = -1;
int end = -1;
ArrayList<Character> stream = getCharList(a);
ArrayList<Character> lookup = getCharList(b);
ArrayList<Character> avoid = getCharList(c);
for(Character ch : stream)
{
if (avoid.contains(ch))
{
lookup = getCharList(b);
start = -1;
end = -1;
}
else
{
if (lookup.contains(ch))
{
lookup.remove(ch)
if (start == -1) start = cursor;
end = cursor;
}
}
if (lookup.isEmpty())
break;
cursor++;
}
if (lookup.isEmpty())
{
System.out.println(" found at ("+start+":"+end+") ");
}
else
{
System.out.println(" not found ");
}
}
}
Here is working Java code tested on various test cases.
The algorithm basically uses a sliding window to examine different windows within which an answer may lie. Each character in the string str2 is analyzed at most twice. Thus the running time of the algorithm is linear, ie O(N) in the lengths of the three strings. This is infact the most optimal solution for this problem.
String str1 = "spqrstrupvqw";
String str2 = "sprt";
String str3 = "q";
char[] arr = str1.toCharArray();
HashSet<Character> take = new HashSet<Character>();
HashSet<Character> notTake = new HashSet<Character>();
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
void run()throws java.lang.Exception{
System.out.println(str1 + " " + str2 + " " + str3);
//Add chars of str2 to a set to check if a char has to be taken in O(1)time.
for(int i=0; i<str2.length(); i++){
take.add(str2.charAt(i));
}
//Add chars of str3 to a set to check if a char shouldn't be taken in O(1) time.
for(int i=0; i<str3.length(); i++){
notTake.add(str3.charAt(i));
}
int last = -1;
int bestStart = -1;
int bestLength = arr.length+1;
// The window will be from [last....next]
for(int next=last+1; next<arr.length; next++){
if(notTake.contains(arr[next])){
last = initLast(next+1); //reinitialize the window's start.
next = last;
}else if(take.contains(arr[next])){
// take this character in the window and update count in map.
if(last == -1){
last = next;
map.put(arr[last], 1);
}else{
if(!map.containsKey(arr[next])) map.put(arr[next], 1);
else map.put(arr[next], map.get(arr[next])+1);
}
}
if(last >= arr.length){ // If window is invalid
break;
}
if(last==-1){
continue;
}
//shorten window by removing chars from start that are already present.
while(last <= next){
char begin = arr[last];
// character is not needed in the window, ie not in set "take"
if(!map.containsKey(begin)){
last++;
continue;
}
// if this character already occurs in a later part of the window
if(map.get(begin) > 1){
last++;
map.put(begin, map.get(begin)-1);
}else{
break;
}
}
// if all chars of str2 are in window and no char of str3 in window,
// then update bestAnswer
if(map.size() == str2.length()){
int curLength = next - last + 1;
if(curLength < bestLength){
bestLength = curLength;
bestStart = last;
}
}
}
if(bestStart==-1){
System.out.println("there is no such window");
}else{
System.out.println("the window is from " + bestStart + " to " + (bestStart + bestLength-1));
System.out.println("window " + str1.substring(bestStart, bestStart+bestLength));
}
}
// Returns the first position in arr starting from index 'fromIndex'
// such that the character at that position is in str2.
int initLast(int fromIndex){
// clear previous mappings as we are starting a new window
map.clear();
for(int last=fromIndex; last<arr.length; last++){
if(take.contains(arr[last])){
map.put(arr[last], 1);
return last;
}
}
return arr.length;
}
Moreover, your code fails on many trivial test cases. One of them is when str1 = "abc", str2 = "ab", str3 = "c".
PS. If you are having a hard time understanding this code, first try reading this easier post which is very similar to the problem that has been asked.
What about using a regular expression?
String regex = ".*((?=[^q]*s)(?=[^q]*p)(?=[^q]*r)(?=[^q]*t)[sprt][^q]+([sprt])(?<!ss|pp|rr|tt))";
Matcher m = Pattern.compile(regex).matcher("spqrstrupvqw");
while (m.find()) {
System.out.println(m.group(1));
}
This prints out:
strup
This can also be wrapped in a method which generates dynamically the regular expression for variable inputs:
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatchString {
public static void main(String[] args) {
System.out.println(getMinimalSubstrings("spqrstrupvqw", "sprt", "q"));
System.out.println(getMinimalSubstrings("A question should go inside quotations.", "qtu", "op"));
System.out.println(getMinimalSubstrings("agfbciuybfac", "abc", "xy"));
}
private static List<String> getMinimalSubstrings(String input, String mandatoryChars, String exceptChars) {
List<String> list = new ArrayList<String>();
String regex = buildRegEx(mandatoryChars, exceptChars);
Matcher m = Pattern.compile(regex).matcher(input);
while (m.find()) {
list.add(m.group(1));
}
return list;
}
private static String buildRegEx(String mandatoryChars, String exceptChars) {
char[] mandChars = mandatoryChars.toCharArray();
StringBuilder regex = new StringBuilder("[^").append(exceptChars).append("]*(");
for (char c : mandChars) {
regex.append("(?=[^").append(exceptChars).append("]*").append(c).append(")");
}
regex.append("[").append(mandatoryChars).append("][^").append(exceptChars).append("]+([").append(mandatoryChars).append("])(?<!");
for (int i = 0; i < mandChars.length; i++) {
if (i > 0) {
regex.append("|");
}
regex.append(mandChars[i]).append(mandChars[i]);
}
regex.append("))");
return regex.toString();
}
}
This prints out:
[strup]
[quest]
[agfbc, bfac]
I have a two dimensional string array look like this:
The first column contains characters of many strings, other columns are extra data for character. I want to search a string (maybe change to array character) in this array to get all match indexes (start - end). For example, when I search with key "next", the result should be [5 - 8], [13 - 16] (the highlight parts in image above). Shortly, I need a method look like this:
public static List<Interval> search(String searchText, String[][] data, int columnsCount, int rowCount){
// Convert search text to String array
String[] searchArr = getStringArray(searchText);
// then search in data
}
// where Interval is:
public class Interval{
public int start;
public int end;
}
Is there any fast way to search like this,cause my data is very large?
Thanks in advance!
I would recommend to adapt the String[][] to a CharSequence. Then you are free to do everything you can do with a CharSequence and this also means that you can use java.util.regex.Matcher to search for the string and you don't need to implement an own search algorithm.
For example:
public class Main {
public static void main(String[] args) {
String[][] array2d = createArray();
int charSeqColumn = 0;
CharSequence charSequnce = new Array2DColumnCharSequnce(array2d, charSeqColumn);
System.out.println(charSequnce.toString());
Pattern patttern = Pattern.compile("ext");
Matcher matcher = patttern.matcher(charSequnce);
while (matcher.find()) {
String matchGroup = matcher.group();
int start = matcher.start();
int end = matcher.end() - 1;
String msg = MessageFormat.format("{0} matched at: [{1}] - [{2}]", matchGroup, start, end);
System.out.println(msg);
}
}
private static String[][] createArray() {
String[][] array2d = new String[2][10];
array2d[0][0] = "N";
array2d[0][1] = "e";
array2d[0][2] = "x";
array2d[0][3] = "t";
array2d[0][4] = " ";
array2d[0][5] = "N";
array2d[0][6] = "e";
array2d[0][7] = "x";
array2d[0][8] = "t";
array2d[0][9] = " ";
array2d[1][0] = "H";
array2d[1][1] = "e";
array2d[1][2] = "l";
array2d[1][3] = "l";
array2d[1][4] = "o";
array2d[1][5] = "W";
array2d[1][6] = "o";
array2d[1][7] = "r";
array2d[1][8] = "l";
array2d[1][9] = "d";
return array2d;
}
}
will output
Next Next
ext matched at: [1] - [3]
ext matched at: [6] - [8]
I would implement the CharSequence adaption like this
class Array2DColumnCharSequnce implements CharSequence {
private int column;
private String[][] array2d;
private int endIndex;
private int startIndex;
public Array2DColumnCharSequnce(String[][] array2d, int column) {
this(array2d, column, 0, array2d[column].length);
this.array2d = array2d;
this.column = column;
}
public Array2DColumnCharSequnce(String[][] array2d, int column,
int startIndex, int endIndex) {
this.array2d = array2d;
this.column = column;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public int length() {
return endIndex - startIndex;
}
public char charAt(int index) {
String charString = array2d[column][startIndex + index];
return charString.charAt(0);
}
public CharSequence subSequence(int start, int end) {
Array2DColumnCharSequnce array2dColumnCharSequnce = new Array2DColumnCharSequnce(
array2d, column, start, end);
return array2dColumnCharSequnce;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder(this);
return sb.toString();
}
}
Note:
The Array2DColumnCharSequnce is just a quick implementation and it does not address exception handling yet nor it addresses what happens when there are more than one char in a string column.
Why to use a CharSequence decorator
The difference with adapting the array to a CharSequence to other approaches is that you use a standard java interface that can be re-used with many other classes and thus is very flexible.
Some often used standard java classes that take a CharSequence as parameter
String.contains(CharSequence s)
String.contentEquals(CharSequence cs)
String.replace(CharSequence target, CharSequence replacement)
Appendable.append(CharSequence csq)
StringBuffer.append(CharSequence s)
StringBuilder.append(CharSequence s)
See the full list here.
Use the code above and try this to see how flexibe the decorator is.
public static void main(String[] args) {
String[][] array2d = createArray();
CharSequence charSequnce = new Array2DColumnCharSequnce(array2d, 0);
boolean contentEquals = "Next Next ".contentEquals(charSequnce);
System.out.println(contentEquals);
CharSequence column1CharSequnce = new Array2DColumnCharSequnce(array2d, 1);
String replaced = "I want to say Next Next ".replace(charSequnce, column1CharSequnce);
System.out.println(replaced);
}
will output
true
I want to say HelloWorld
Finally everyone has to decide what he/she wants and what fits the situation. I prefer implementations that give me more options if I can get them "almost" for free.
It is similar to search a subString in a String.
e.g.
A B C D N E X T J H J N E N E X T O
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
So the answer should be [4-7] and [13-16].
public static List<Integer> findIndexes(String source, String toFind){
List<Integer> list = new LinkedList<Integer>();//it will return the starting indexes of the found substring, we can easily find the end e=index by adding the length of the other.
int start = 0;
while(start < source.length()){
if(source.charAt(start)==toFind.charAt(0)){//if the char is same then find whether the whole toFind string is present or not.
if(isMatch(source, toFind, start)){//if it is found than increment the source pointer to the end after the toFind string
list.add(start);
start = start+toFind.length();
continue;
}
}
start++;
}
return list;
}
private static boolean isMatch(String s1, String s2, int srcIndex){
int desIndex = 0;
while(desIndex<s2.length() && s1.charAt(srcIndex)==s2.charAt(desIndex)){
srcIndex++;
desIndex++;
}
if(desIndex==s2.length()){
return true;
}
return false;
}
And sample driver program:
public static void main(String[] args) {
String s1="abcdnextponexnextpour";
String s2 = "next";
List<Integer> list = findIndexes(s1, s2);
for(int i : list){
System.out.println(i);
}
}
It will output the indexes:
4
13
i.e. you can add the length of the toFind String to calculate the last index.
This is your solution:
void main(String a[][],String k){
String m="";
for(int i=0;i<a.length;i++)
m+=a[i][0];
int n=0,x;
while(n<m.length()){
n=m.indexOf(k,n);
x=n+k.length();
System.out.println(n+"-"+x);
n=x;
}
}
void main(String a[][],char k){
for(int i=0;i <a.length;i++)
if(a[i][0]==k)System.out.println(i);
}
it extracts the first strings of the dda and searches it.
you may generate the value n and x as class interval and include it in list.
I would implement search as follows -
public static List<Interval> search(
String searchText, String[][] data) {
List<Interval> al = new ArrayList<>();
if (searchText != null) {
searchText = searchText.trim().toUpperCase();
char[] toMatch = searchText.toCharArray();
for (int i = 0; i < data.length; i++) {
if (data[i] != null && data.length > i
&& data[i].length > 0
&& data[i][0].charAt(0) == toMatch[0]) {
boolean matched = true;
for (int t = 1; t < toMatch.length; t++) {
if (i + t > data.length
|| data[i + t][0].charAt(0) != toMatch[t]) {
i += (t - 1);
matched = false;
break;
}
}
if (matched) {
Interval interval = new Interval();
interval.start = i - 1;
interval.end = interval.start + (toMatch.length - 1);
al.add(interval);
}
}
}
}
return al;
}
And, I would modify Interval to add a toString() like this
public String toString() {
return String.valueOf(start) + "-" + end;
}
Finally, to test it I would use this main method.
public static void main(String[] args) {
String[][] test = { { "N" }, { "A" }, { "N" },
{ "A" }, { "T" }, { "A" }, { "N" }, { "E" },
{ "X" }, { "T" }, { "E" }, { "R" }, { "N" },
{ "B" }, { "N" }, { "E" }, { "X" }, { "T" } };
List<Interval> al = search("next", test);
for (Interval i : al) {
System.out.println(i);
}
}
And I did receive this output -
5-8
13-16