How to search for a pattern in a sequence of chars? - java

How would you set up a nested loop to search a sequence of chars for every occurrence of a pattern? This is what I have so far, but it's only showing one occurrence and giving an indexoutofbounds error. How can I fix it?
int i = 0;
while (i < data.size()) {
if (patternString.charAt(0) == data.get(i)) {
i++;
int j = 0;
while (patternString.charAt(j) == data.get(i)) {
j++;
System.out.println(j) ;
if (j == patternString.length()) {
System.out.println("Found pattern " + "at index " + (i));
}
}
} else { i++;}
}

You're likely getting an IndexOutOfBounds error because of not checking whether i and j are within bounds before accessing data and patternString.
There are more consice ways to do this as mentioned, but if you still want to do the pattern search "manually", you can try this:
int j = 0;
for (int i = 0; i < data.size(); i++) {
if (patternString.charAt(j) == data.get(i)) {
while (j < patternString.length() && i < data.size() && //indices checks
patternString.charAt(j) == data.get(i) ) {
j++;
i++;
}
if (j == patternString.length()) {
i -= patternString.length(); //set i back to the start of the pattern
System.out.println("Found pattern " + "at index " + (i));
}
j = 0;
}
}

You can just use String#indexOf:
int index = 0;
while (index != -1) {
// this line replaces your code
index = data.indexOf(patternString, index);
// a result of -1 means pattern was not found
if (index != -1) {
System.out.printf("%s found at index %d%n", patternString, index);
}
}

Related

Longest Palindromic Substring on Java (leetcode)

In leetcode I tried to solve the "Longest Palindromic Substring" task. Here is the code:
public String longestPalindrome(String s) {
String str = "";
for(int i = 0; i < s.length(); i++)
{
for(int j = 1 + i; j < s.length() + 1; j++)
{
String sub = s.substring(i, j);
if(isPalindrome(sub) && sub.length() > str.length())
{
str = s.substring(i, j);
}
}
}
return str;
}
public static boolean isPalindrome(String s)
{
if(s.length() < 2)
return true;
else
for(int i = 0; i < s.length() / 2; i++)
{
if(!(s.charAt(i) == s.charAt(s.length() - 1 - i)))
return false;
}
return true;
}
It works when I run it in Eclipse, but when I want to submit the solution to leetcode, it shows me an error:
Submission Result: Time Limit Exceeded
Last executed input:
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee...
Can you tell me, what's my problem?
your code is taking too much time for leetcode
for(int j = 1 + i; j < s.length() + 1; j++){
String sub = s.substring(i, j);
if(isPalindrome(sub) && sub.length() > str.length()){
str = s.substring(i, j);
}
}
in this loop you call 2 times s.substring(i, j); you can start by calling it 1 time
for(int j = 1 + i; j < s.length() + 1; j++){
String sub = s.substring(i, j);
if(isPalindrome(sub) && sub.length() > str.length()){
str = sub;
}
}
then you can search on internet :
https://www.geeksforgeeks.org/longest-palindrome-substring-set-1/
you have 2 methods brute force and optimize
You're answer is taking an insane amount of time to run. Instead of the brute force approach try to optimize it.
This is a better solution if you've trouble dealing with the dynamic approach:
class Solution {
public String longestPalindrome(String s) {
if(s == null || s.length() < 1)
return "";
int start = 0;
int end = 0;
for(int i=0; i<s.length(); i++)
{
int l1 = fromMiddle(s,i,i);
int l2 = fromMiddle(s,i,i+1);
int l = Math.max(l1,l2);
if(l > end - start)
{
start = i - ((l-1)/2);
end = i + (l/2);
}
}
return s.substring(start, end+1);
}
public int fromMiddle(String s, int left, int right)
{
if(s == null || left > right)
return 0;
while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right))
{
left--;
right++;
}
return right-left-1;
}
}

Need help to solve the hackerrank challenge

I'm trying to solve an "Almost Sorted" challenge in hackerrank the problem is:
Given an array with elements, can you sort this array in ascending order using only one of the following operations?
Swap two elements.
Reverse one sub-segment.
Input Format
The first line contains a single integer, , which indicates the size of the array.
The next line contains integers separated by spaces.
Sample Input #1
2
4 2
Sample Output #1
yes
swap 1 2
Sample Input #2
3
3 1 2
Sample Output #2
no
Sample Input #3
6
1 5 4 3 2 6
Sample Output #3
yes
reverse 2 5
I tried to solve the challenge and my code is working but it seems it's to slow for big arrays.
Kindly asking you to help me to find a better solution for mentioned problem.
Below is my code:
import java.util.*;
public class Solution
{
private static int[] arr;
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int N = in.nextInt();
arr = new int[N];
for (int i = 0; i < N; i++)
{
arr[i] = in.nextInt();
}
if (IsSorted(arr))
{
System.out.println("yes");
return;
}
if(CheckSingleSwap(arr))
return;
if(CheckSingleReverse(arr))
return;
System.out.println("no");
}
private static boolean CheckSingleReverse(int[] arr)
{
int length = arr.length;
int limit = length - 2;
int current = 1;
List<Integer> indexes = new ArrayList<Integer>();
while (current < limit)
{
for (int i = 0; i < length; i++)
{
int temp = current + i;
for (int j = i; j <= temp && temp < length; j++)
{
indexes.add(j);
}
if (IsSorted(ReverseArrayPart(arr, indexes)))
{
System.out.println("yes");
System.out.println("reverse " + (indexes.get(0) + 1) + " " + (indexes.get(indexes.size() - 1) + 1));
return true;
}
indexes.clear();
}
current++;
}
return false;
}
private static int[] ReverseArrayPart(int[] arr, List<Integer> indexes)
{
int[] result = new int[arr.length];
int[] arrayPart = new int[indexes.size()];
int j = 0;
for (int i = 0; i < arr.length; i++)
{
if (indexes.contains(i))
{
arrayPart[j] = arr[i];
j++;
}
result[i] = arr[i];
}
for(int i = 0; i < arrayPart.length / 2; i++)
{
int temp = arrayPart[i];
arrayPart[i] = arrayPart[arrayPart.length - i - 1];
arrayPart[arrayPart.length - i - 1] = temp;
}
j = 0;
for (int i = 0; i < result.length; i++)
{
if (indexes.contains(i))
{
result[i] = arrayPart[j];
j++;
}
}
return result;
}
private static boolean CheckSingleSwap(int[] arr)
{
int count = 0;
int[] B = Arrays.copyOf(arr, arr.length);
Arrays.sort(B);
List<Integer> indexes = new ArrayList<Integer>();
for(int i = 0; i < arr.length; i++)
{
if(arr[i] != B[i])
{
count++;
indexes.add(i+1);
}
}
if(count > 2)
return false;
System.out.println("yes");
System.out.println("swap " + indexes.get(0) + " " + indexes.get(1));
return true;
}
private static boolean IsSorted(int[] arr)
{
int length = arr.length;
for (int i = 0; i < length - 1; i++)
{
if (arr[i] > arr[i + 1])
{
return false;
}
}
return true;
}
}
For the following code, pass in A as the original array and B as the sorted array.
CheckSingleSwap:
Instead of adding the indices to another list, store the first swap you encounter, and keep going; if you find the corresponding other swap, then store it and record the finding; if you find a different swap, exit with false. At the end if you've recorded the finding, print the corresponding indices.
private static boolean CheckSingleSwap(int[] A, int[] B)
{
int L = A.length;
int firstSwap = -1, secondSwap = -1;
for(int i = 0; i < L; i++)
{
if(A[i] != B[i])
{
if (firstSwap == -1)
firstSwap = i;
else if (secondSwap == -1 && A[i] == B[firstSwap] && A[firstSwap] == B[i])
secondSwap = i;
else
return false;
}
}
if (firstSwap != -1 && secondSwap != -1)
{
System.out.println("yes");
System.out.println("swap " + (firstSwap + 1) + " " + (secondSwap + 1));
return true;
}
System.out.println("array is already sorted!");
return false; // or whatever you decide to do; maybe even an exception or enumerated type
}
CheckSingleReverse:
You are doing WAY too much here! You seem to be brute forcing every single possible case (at first glance).
What you can do instead is to find the region where all the numbers are different. If there are more than two of these, or two which are separated by more than one element, then return false immediately.
The reason for the "more than one" thing above is because of odd-number length regions - the middle element would be the same. If you find such two regions, treat them as one. Then you can proceed to find out if the region is reversed.
private static boolean CheckSingleReverse(int[] A, int[] B)
{
// find region
int L = A.length;
int diffStart = -1, diffEnd = -1; boolean mid = false, found = false;
for (int i = 0; i < L; i++)
{
if (A[i] != B[i])
{
if (found)
{
if (i - diffEnd == 2 && !mid)
{
mid = true;
found = false;
diffEnd = -1;
}
else
return false;
}
else if (diffStart == -1)
diffStart = i;
}
else
if (diffStart != -1 && diffEnd == -1)
{
found = true;
diffEnd = i - 1;
}
}
if (diffEnd == -1)
{
if (A[L - 1] != B[L - 1])
diffEnd = L - 1;
else if (!found)
{
System.out.println("array is already sorted!");
return false;
}
}
// find out if it's reversed
int count = (diffEnd - diffStart + 1) / 2;
for (int i = 0; i < count; i++)
{
int oneEnd = diffStart + i, otherEnd = diffEnd - i;
if (!(A[oneEnd] == B[otherEnd] && A[otherEnd] == B[oneEnd]))
return false;
}
System.out.println("yes");
System.out.println("reverse " + (diffStart + 1) + " " + (diffEnd + 1));
return true;
}
Just to give you an idea of the performance boost, on ideone.com, with an array length of 150, the original implementation of CheckSingleReverse took 1.83 seconds, whereas the new one took just 0.1 seconds. With a length of 250, the original actually exceeded the computational time limit (5 seconds), whereas the new one still took just 0.12 seconds.
From this it would seem that your implementation takes exponential time, whereas mine is linear time (ignoring the sorting).
Funnily enough, with an array size of 3 million I'm still getting around 0.26 seconds (ideone's execution time fluctuates a bit as well, probs due to demand)

Binary to decimal, error message

I wrote a program that convert a binary number to decimal number.
When I run the program with some binary number, the program give me the decimal number but with an error message.
my code:
public class ohad {
public static void main(String[] args) {
String bin = "10011";
int length = bin.length();
int j = 0;
int sum = 0;
if (length != 0) {
for (int i=0; i < bin.length(); i++){
if (bin.charAt(i) == '0' || bin.charAt(i) == '1'){
for (int t = (length - 1); t >= 0; t--){
String s = bin.charAt(j) + "";
sum = (int)(sum + (Integer.valueOf(s)) * (Math.pow(2, t)));
j++;
}
System.out.println(sum);
}
else {
System.out.println("illegal input.");
}
}
} else {
System.out.println("illegal input.");
}
}
}
error message:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 5
at java.lang.String.charAt(String.java:646)
at ohad.main(ohad.java:15)
I think it's something with my j index. What should I do?
What should I do?
I would use Integer.parseInt(String,int) like
String bin = "10011";
System.out.println(Integer.parseInt(bin, 2));
Output is
19
Do you need j index? Looking at this quickly, I think you can use i index instead j.
String s = bin.charAt(j) + "";
String s = bin.charAt(i) + "";
You need to reset your j variable.
in the second iteration of the i for loop that is for (int i=0; i < bin.length(); i++){
j goes out of bounds as it is not set to zero again try the following code :
for (int i=0; i < bin.length(); i++){
j=0; // add this
if (bin.charAt(i) == '0' || bin.charAt(i) == '1'){
for (int t = (length - 1); t >= 0; t--){
String s = bin.charAt(j) + "";
sum = (int)(sum + (Integer.valueOf(s)) * (Math.pow(2, t)));
j++;
}
System.out.println(sum);
} else {
System.out.println("illegal input.");
}
}
While Elliott's answer is absolutely correct and gives a much easier way of solving the problem of converting a binary number to its decimal equivalent, it does not tell you what is causing the error.
You are correct that the exception is thrown because of the j variable, the issue lies in that the j variable is never set back to 0 when the inner loop (with index variable t). I changed your code to reflect this:
for (int t = (length - 1); t >= 0; t--){
String s = bin.charAt(j) + "";
sum = (int)(sum + (Integer.valueOf(s)) * (Math.pow(2, t)));
j++;
}
j = 0; //this is the added code
System.out.println(sum);
This prevents the exception being thrown however causes another issue with the loop being called again, printing each time until you hit 95. I'll let you fix this problem.
You've got one loop too much. That's why j keeps increasing causing the error message.
Delete the t loop:
public static void main(String[] args) {
String bin = "10011";
int length = bin.length();
int j = 0;
int sum = 0;
if (length != 0) {
for (int i = length - 1; i >= 0; i--) {
if (bin.charAt(i) == '0' || bin.charAt(i) == '1') {
String s = bin.charAt(j) + "";
sum = (int) (sum + (Integer.valueOf(s)) * (Math.pow(2, i)));
j++;
} else {
System.out.println("illegal input.");
}
}
System.out.println(sum);
} else {
System.out.println("illegal input.");
}
}

Trying to search a grid of characters in java for a specific word. How can I search from right to left after searching from left to right?

I have the following code to search a grid of characters below from left to right to find a word. This works perfectly.
// Left to Right
public static String findLeftToRight (char[][]board, String word) {
char[] letters = word.toCharArray();
for (int i = 0; i < board.length; i++){
for (int j = 0; j < board[i].length; j++) {
boolean found = true;
for (int k = 0; k < letters.length; k++) {
if ((j+k >= board[i].length) || (letters[k] != board[i][j+k])) {
found = false;
break;
}
}
if (found) {
return "String " + word + " found in row=" + i + " col=" +j;
}
}
}
return "String " + word + " not found";
} // end findLeftToRight
However, I cannot figure out how to search from right to left. Below is my attempt at searching from right to left, but it does not work. Can someone tell me what I'm doing wrong?
// Right to Left
public static String findRightToLeft (char[][]board, String word) {
char[] letters = word.toCharArray();
for (int i = board.length-1; i > -1; i--){
for (int j = board[i].length-1; j > -1; j--) {
boolean found = true;
for (int k = 0; k < letters.length; k++) {
if ((j+k <= board[i].length) || (letters[k] != board[i][j+k])) {
found = false;
break;
}
}
if (found) {
return "String " + word + " found in row=" + i + " col=" +j;
}
}
}
return "String " + word + " not found";
} // end findLeftToRight
if ((j+k <= board[i].length) || (letters[k] != board[i][j+k])) {
also needs to be reversed:
if ((j - k < 0) || (letters[k] != board[i][j-k])) {

Nested loop construction

This is part of my homework. All I need is a bit of advice. I need to write some nested loop constructs, to print the following:
"122333444455555"
"+**+++****+++++"
"--***++++-----******+++++++"
Here is my code to print the first set of symbols
public static void main (String[] args)
{
int i,j;
for(i=1;i<6;++i)
{
for(j=1;j<i+1;++j)
{
System.out.print(i);
}
}
}
This works perfectly fine. I'm just having trouble figuring out the second and third set of symbols. Apologies for my lack of experience, I'm fairly new to Java.
One solution is:
final String[] arr = {"*", "+"};
And in your inner loop:
System.out.print(arr[i % 2]);
The % (Modulo) operator is responsible of the switches between * and + symbols:
For even i it'll be *, otherwise it'll be +.
Output: "+**+++****+++++".
(Regarding the second output, I'll not show you the solution, but it's very similar to this one once you understand it).
public static void main(String[] args) throws IOException {
int i, j;
for (i = 1; i < 6; ++i) {
for (j = 1; j < i + 1; ++j) {
System.out.print(i);
}
}
System.out.println();
for (i = 1; i < 6; i++) {
if (i % 2 == 1) {
for (j = 1; j < i + 1; ++j){
System.out.print("+");
}
} else {
for (j = 1; j < i + 1; ++j){
System.out.print("*");
}
}
}
System.out.println();
for (i = 2; i < 8; i++) {
if (i % 3 == 1) {
for (j = 1; j <= i; ++j){
System.out.print("+");
}
} else if (i % 3 == 2) {
for (j = 1; j <= i; ++j){
System.out.print("-");
}
} else {
for (j = 1; j <= i; ++j){
System.out.print("*");
}
}
}
}
Cycle #1:
You have to print out numbers from one to five and each number N has to be printed out N times.
for (i = 1; i < 6; ++i) { // this would set `i` to numbers from 1-5
for (j = 1; j < i + 1; ++j) { // for each cycle (next number) it prints
//it out N times where N is the cycle number. 1 is the first cycle,
//2 is the second and so on.
Cycle #2:
Same problem but instead of printing out number of the cycle you have to print out + or * based on if the cycle number is odd or even.
To check if the number is even you can use:
int number = 1;
if(number % 2 == 0){ // is true if the number is even
This checks whats the remainder from the division of number by two.
Cycle #3:
Same as #2 but you start from the second cycle, not from the first and you check for the remainder after division by 3.
If I understand, the third set is composed by sequence of "-*+" so:
String sequence = "-*+";
String s = "+**+++****+++++";
int seqI = 0;
for(i=0; i != s.size(); ++i) {
for(j=0; j < i+2; ++j) {
System.out.print(sequence[seqI]);
}
if(seqI < sequence.size()) {
++seqI;
} else {
seqI = 0;
}
}
You can define a function like this:
public static char Output(int i, int mode)
{
if (mode == 1)
{
return (char) i;
}
else if (mode == 2)
{
if (i % 2 == 0)
{
return '+';
}
else
{
return '*';
}
}
else if (mode == 3)
{
if (i % 3 == 0)
{
return '-';
}
else if (i % 3 == 1)
{
return '*';
}
else
{
return '+';
}
}
}
And use it just like:
for (int mode = 1 ; mode < 4 ; mode++)
{
for (int i = 1 ; i < 6 ; i++)
{
for (int j = 0 ; j < i + (int)(mode / 3) ; j++)
{
System.out.println(Output(i, mode));
}
}
}
Note: Yes! Actually my code is hard to read, but if you try to read it, you will learn something more than other answers!

Categories