Moving pointers VS. Just iterating the string - java

I am a beginner in preparing interview questions. I recently have a question about iterating a string.
When dealing with questions like "Valid Palindrome" and similar questions, we usually have 2 ways to solve the question.
We either keep updating pointers until we find the target char:
s = s.toLowerCase();
int lo = 0;
int hi = s.length() - 1;
while(hi > lo){
while(lo < hi && !Character.isLetterOrDigit(s.charAt(lo))) lo ++;
while(hi > lo && !Character.isLetterOrDigit(s.charAt(hi))) hi --;
if(s.charAt(lo) != s.charAt(hi)) return false;
lo ++;
hi --;
}
return true;
Or just iterating the string (from leetcode discussion):
int head = 0, tail = s.length() - 1;
char cHead, cTail;
while(head <= tail) {
cHead = s.charAt(head);
cTail = s.charAt(tail);
if (!Character.isLetterOrDigit(cHead)) {
head++;
} else if(!Character.isLetterOrDigit(cTail)) {
tail--;
} else {
if (Character.toLowerCase(cHead) != Character.toLowerCase(cTail)) {
return false;
}
head++;
tail--;
}
}
return true;
I am not sure which method is better in terms of big O analysis and which one to use during an interview?
Thanks in advance!

The second is better.
The first also treats lo == hi and
repeats the condition of the outer loop.
Also charAt is repeated for the same index. (Though in the second cTail might not have been gotten.)
The second is less complex, lazier, handling small cases, small steps, easily verifiable.
The second could be written in nicer style as:
//char cHead, cTail;
while(head <= tail) {
char cHead = s.charAt(head);
char cTail = s.charAt(tail);
As a declaration inside a loop is no overhead, just a single stack variable is reserved for a variable.

Related

Java - Trying to print all of the coincidences of a binary search

This is my current search method:
public static int search(int[] array, int numero) {
int start = 0;
int end = array.length - 1;
int center;
while (start <= end) {
center = (start + end) / 2;
if (array[center] == numero) {
return center;
} else if (array[center] < numero) {
start = center + 1;
} else {
end = center - 1;
}
}
return -1;
}
It searches from user input numero into a previously bubble sorted Array that's found in the Main method.
What I'm trying to figure out is how to print ALL of the coincidences found in the array, and not just the first one found.
I was thinking about adding results to a List and then returning that to Main, but as I tried that an endless loop happened at the first result found, causing it to add itself to the List repeatedly until the program crashes.
Assuming that you know the basic theory behind binary searches, separate it into 3 steps.
Search using binary search methods.
once a match is found, scan up from that point, until you find a non matching element.
Scan down, adding to a result list, until you find a non
matching element.
If you don't need to care about occurrence order, you could combine steps 2 and 3 and just scan up adding to the list, and scan down adding to the list, since due to the sorting, everything you hit is guaranteed to match until it doesn't.
If you do care about occurrence order, step 2 could be optimised by jumping ahead and checking, and writing a modified binary search that searches for a transition of matching/notmatching instead of a match.
This could be further optimised by keeping statistics or profiling, to find the perfect jump distance, or basing it off of the last up-most check.
actually it's easy because the list is already sorted, the numbers you expect to find are adjacent.
just like Ryan's answer, I'll put some code
public static List<Integer> searchAll (int[] array, int numero){
int firstMatchIndex = search( array, numero);
List<Integer> results = new ArrayList<Integer>():
results.add(firstMatchIndex);
boolean left = true;
while( left){
int i = firstMatchIndex - 1;
if(i<0 || array[i] != numero){
left = false;
}else{
results.add(i);
}
}
boolean right = true;
while( right){
int i = firstMatchIndex + 1;
if(i>array.length || array[i] != numero){
right = false;
}else{
results.add(i);
}
}
}

How to re-write or modify this code to work the same but without using a break statement

How can I get the following code work without using break statement?
I updated and added i = child to bottom of the while loop. I'm also adding these additional comments because someone edited my post and now I can't update it because I need to add more comments. Please don't alter my question. Those comments are there for extra insight. It also hinders my ability to edit my question or update my code.
private void percDown(int [] a, int i, int n) {
numOfCalls++;
int child = 0;
int tmp = a[i];
while(leftChild(i) < n) {
child = leftChild(i);
if( child != n - 1 && a[child] < a[child + 1]){
numOfComparisons++;
child++;
}
if( tmp < a[child]){
numOfComparisons++;
a[i] = a[child];
}
else
break;
i= child;
a[i] = tmp;
}
}
Just set n = 0; instead, or Integer.MIN_VALUE if these values can go negative. That will stop your loop. But don't be averse to break statements. They are used all the time out here in the real world.
Try this while condition:
while(leftChild(i) < n && (( leftChild(i) != n - 1 && a[leftChild(i)] < a[leftChild(i) + 1]) || tmp < a[leftChild(i)]))
Basically I have clubbed both your if conditions in the while condition. Everything else remains the same.
Your code is in structure like this:
while(A) {
B;
if(C){
D;
} else {
break;
}
E;
}
To tidy it up a bit; it can be written as
while(A) {
B;
if(C){
D;
E;
} else {
break;
}
}
To avoid using break, it can be done by:
while(A && !C) {
B;
if(C){
D;
E;
}
}
(You may make up a meaningful boolean flag to represent C so that it is more readable instead of putting a long, complex, hard-to-read predicate in while condition.)

How do I add logic to a sorted array delete algorithm to account for a "node not found" scenario?

I was assigned to write a delete algorithm for my sorted array structure. It continues to be a source of problems for my program because, in certain instances, it is completing the delete when it should be returning False for "node not found". So the delete function works, but it does it even when the node is not found. Where is the flaw in my logic?
public boolean delete(String targetListing)
{
int low = 0;
int high = next - 1;
int i = (low + high) / 2;
//check to see if target listing is the same as the current node key field
while(data[i].getName().compareToIgnoreCase(targetListing) != 0 && high != low)
{
if(data[i].getName().compareToIgnoreCase(targetListing) >= 1)
{
high = i - 1; //eliminate the bottom of the array
}
else
{
low = i + 1; //eliminate the top of the array
}
i = (low + high) / 2;
}
//this is my logic to determine if the node was found or not
//I also tried if(low == high) but sometimes that would be true at the
//at the position that the node was found
if(i == next || i < 0)
{
return false; //node not found
}
for(int j = i; j < next - 1; j++)
{
data[j] = data[j + 1];
}
next = next - 1;
data[next] = null;
return true;//node found and deleted
If anyone could also point me to a good example of a sorted array delete algorithm that accounts for a node not found scenario I would really appreciate it. I would have thought that would be a very easy thing to find, but I am having a hard time finding it.
Simplest answer: Replace your if(i == next || i < 0) with if(data[i].getName().compareToIgnoreCase(targetListing) != 0) -- in other words, check that you've actually found a match rather than simply having narrowed down to a single possibility.

How do I make a boolean method using a string?

This is what I have so far, I managed to reach here with several hours of work. The problem with my code is that if i give it a string "abcefg" it will verify the first two characters and returns it as true. I want the code to do it for all of my characters. I thought that putting the limit as x.length() would do the thing, but for some reason, it won't work.
public static boolean ConsecutiveCheckerAscending(String x) {
x = x.toLowerCase();
for (int i = 0; i < x.length() - 1; i++) {
if ((int)x.charAt(i) + 1 != ((int)x.charAt(i + 1)))
{
return false;
}
}
return true;
}
public static boolean ConsecutiveCheckerDescending(String x) {
x = x.toLowerCase();
for (int i = 0; i < x.length() - 1; i++) {
if((int)x.charAt(i) - 1 != ((int)x.charAt(i + 1)))
{
return false;
}
}
return true;
}
You have a variety of issues here.
Firstly, you can eventually go out of bounds with the charAt(i + 1) calls (check your loop condition).
Secondly, how can you possibly return true in the body of the for-loop? You haven't checked all of the characters yet!
I think you're making this overly complicated, though. All you need to do in order to check that two contiguous (i.e. next to each other in the string) characters are consecutive is
Math.abs(s.charAt(i) - s.charAt(i + 1)) == 1
You actually don't even need a cast. What we're doing is checking that the "distance" between the two characters is 1.
Just apply that to every contiguous pair of characters in the string, and return false if it isn't satisfied somewhere along the line. If you exit the loop without ever returning false, you can return true.
You cannot know for sure if the string is consecutive until the end of the method, so you cannot return true in the middle. At most you can return false when you find that string is not consecutive.
To give more advice, what do you mean by "consecutive"? Is adgkm consecutive? Looking at the current code it would look like it; all you check is the order of the characters. Is abcdcbcd consecutive? Usually "consecutive" means there are no gaps.
In both if and else statements you having return statement, So the method will return after first check. You have to give return only for the exit condition. don't give for both if and else
Wrote it in a rush, but it'd look something like this.-
public static boolean ConsecutiveChecker(String x) {
boolean consecutive = true;
x = x.toLowerCase();
for (int i = 0; i < x.length() - 1; i ++) {
if ((int) x.charAt(i) + 1 != ((int) x.charAt(i + 1))) {
consecutive = false;
break;
}
}
return consecutive;
}

some weird stff im running into on java

So im working on java codingbat and this is the question:
Given a string, look for a mirror image (backwards) string at both the beginning and end of the given string.
In other words, zero or more characters at the very begining of the given string, and at the very end of the string in reverse order (possibly overlapping).
For example:
the string "abXYZba" has the mirror end "ab". mirrorEnds("abXYZba") → "ab" mirrorEnds("abca") → "a" mirrorEnds("aba") → "aba" .
My code passed all the test except for the other test, which is not specified. I dont know what's wrong with it.
public String mirrorEnds(String string) {
String input = string, mirror = "";
int length = string.length();
for (int n = 0; n < (length+1) / 2; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}else if(length%2 == 1 && n == (length - 1)/2){
// System.out.println("length/2 = " );
return input;
}
else {
mirror += input.charAt(n);
}
}
return mirror;
}
You were correct in not needing to go though the entire word, but your logic is more complex than it needs to be, making it harder to find and fix the problem. The root cause of the test failure is in the last return statement. It must return string if the loop completes without breaking. You can fix your code by changing break; to return mirror; and changing the last return mirror; to return input;
The test that is failing is one like this:
mirrorEnds("abba") -> "abba"
A much simpler version of your code can be created like this:
public String mirrorEnds(String string) {
int len = string.length();
for (int i=0; i < len/2; ++i)
if (string.charAt(i) != string.charAt(len - 1 - i))
return string.substring(0, i);
return string;
}
mirrorEnds("abba")?
Anyways, I'm sure you could come up with a better question name than "some weird stuff"...
Since you are dividing n by 2 in your loop termination condition, it will end when halfway through the word. This is enough to tell the word is a palindrome, but not enough to build your output correctly. You have a condition handling palindrome with odd numbers of letter, but not even numbers of letters. I believe the failing test will be of the form "abba", where I believe what you have will return "ab", instead of "abba".
If you change you loop to:
for (int n = 0; n < length; n++) {
I believe it should be doing what you want. This also makes the short circuit case unnecessary, so:
for (int n = 0; n < length; n++) {
if (input.charAt(n) != input.charAt(length - n - 1)) {
break;
}
else {
mirror += input.charAt(n);
}
}
The first test I tried was with the string "abba" which fails. It returns ab, and not abba. As femtoRgon mentioned, you're not going through the entire word, which may some times be necessary. femtoRgon's solution works, as well as taking a slightly different approach to iterating through the word as follows:
public String mirrorEnds(String string) {
boolean matches = true;
StringBuilder mirrorEnd = new StringBuilder();
int index = 0;
while (matches && index < string.length()) {
if (string.charAt(index) == string.charAt(string.length() - index - 1))
mirrorEnd.append(string.charAt(index));
else
matches = false;
index++;
}
return mirrorEnd.toString();
}
public String mirrorEnds(String string) {
String comp="";
for(int i=0; i<string.length(); i++){
if(string.charAt(i)==string.charAt(string.length()-(i+1)))
comp= comp+ string.charAt(i);
else break;
}
return comp;
}

Categories

Resources