I am trying to solve a problem from leet code. I have written a method for that. This works perfectly in local Eclipse, but when I submitted this solution at leetcode it says time limit exceeded.
Can someone suggest to me something I can alter in the code below to make it work faster? I am also able put input string in this post.
Code:
public String longestPalindrome(String s) {
if(s.equals("")) return "";
if(s.length()==1) return s;
if(s.length()==2) {
if(s.charAt(0) == s.charAt(1))
return s;
}
char[] ch = s.toCharArray();
Set<Integer> set = new HashSet<Integer>();
int maxP=0;String maxPalin="";
for(int i =2;i < s.length();i++){
if((ch[i-1]==ch[i] || ch[i-2] == ch[i]) && !set.contains(i) ){
int loop;
if(ch[i-1]==ch[i]){
loop=i-1;
}
else{
loop=i-2;
}
for(int k =i,l=loop; l>=0 && k<s.length();k++,l--){
if(ch[k]!= ch[l]){
if(maxP < s.substring(l+1, k).length())
maxPalin=s.substring(l+1, k);
maxP=s.substring(l+1, k).length();
set.add(i);
i=2;
break;
}
if(l==0){
if(maxP < s.substring(0, k+1).length())
maxPalin=s.substring(0, k+1);
maxP=s.substring(0, k+1).length();
set.add(i);
i=2;
break;
}
if(k== s.length()-1){
if(maxP < s.substring(l, s.length()).length())
maxPalin=s.substring(l, s.length());
maxP=s.substring(l, s.length()).length();
set.add(i);
i=2;
break;
}
}
}
}
return maxPalin;
}
Input:
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
Loop over the characters, for all positions check if the next character is the same as the current (e.g. 'f','f') or the character after and the character before are the same (e.g. 'f','g','f').
If that is the case, loop backward and forward and compare the characters until you find two that don't match.
Compare the length of the string with the longest you've found so far, if it is longer, save it.
Go to the next character.
You can also exit the loop if you have found a palindrom where length/2 is larger than the number of characters left.
Related
I'm working on CodingBat for class and can't figure out why my code isn't working. It passes all of the tests that it lists out but then doesn't pass the "other tests". If you could help me figure out what's wrong that would be really helpful. Here is the problem:
Given a string, count the number of words ending in 'y' or 'z' -- so the 'y' in "heavy" and the 'z' in "fez" count, but not the 'y' in "yellow" (not case sensitive). We'll say that a y or z is at the end of a word if there is not an alphabetic letter immediately following it. (Note: Character.isLetter(char) tests if a char is an alphabetic letter.)
Here are the tests that it listed and I passed.
countYZ("fez day")
countYZ("day fez")
countYZ("day fyyyz")
countYZ("day yak")
countYZ("day:yak")
countYZ("!!day--yaz!!")
countYZ("yak zak")
countYZ("DAY abc XYZ")
countYZ("aaz yyz my")
countYZ("y2bz")
countYZ("zxyx")
Here is the code I have so far. (I know I could have done it cleaner by converting to lower case but I only realized that afterwards.)
public int countYZ(String str) {
int count = 0;
str = str.toLowerCase();
for (int i=0; i<str.length()-1; i++) {
if (!Character.isLetter(str.charAt(i)) && i>0 && (str.substring(i-1,i).equals("y") || str.substring(i-1,i).equals("z")))
{ count++; }
}
if (str.endsWith("y") || str.endsWith("z")) { count++; }
return count;
}
The problem: The way you have set up your logic, your loop looks up until one character before the end of the String and then you check the last character with your if statement. However, your loop only effectively checks the char before i, so you are not checking a char. A String that this will fail on is:
"y z "
(Notice the extra space at the end. It can be any other non letter character, which is defined as the ending of the prior word)
This String should return 2, but returns 1. The easy fix is to change your loop to:
for (int i=0; i<str.length(); i++)
Perhaps a better approach:
Right now you have a mess of boolean conditions to see if the character before is a non alphabetic, if the character at i is alphabetic and so on. If I were you I would simply use toLower(), and then split on any non alphabetic characters. Then for each String in the split array, use the endsWith function to easily check if it ends with z or y. Here's one possible solution:
public int countYZ(String str) {
if(str == null) return 0;
str = str.toLowerCase();
int count = 0;
for(String s : str.split("[^a-z]")) {
if(s.endsWith("y") || s.endsWith("z")) {
count++;
}
}
return count;
}
Or java 8+ you can simply do:
public int countYZ(String str) {
if(str == null) return 0;
return (int)Arrays.stream(str.toLowerCase().split("[^a-z]"))
.filter(e -> e.endsWith("y") || e.endsWith("z"))
.count();
}
Which solves all the test case:
Link to problem
Cleaning up your code will make it be easier to read and to debug.
Don't Repeat Yourself! Anytime you find yourself writing the same piece of code you are introducing potential bugs due to simple typing errors. Instead, you can move all the checks into a single method, and use equalsIgnoreCase to check if a given character matches Y or Z:
public static boolean isYOrZ(String s) {
if(s.equalsIgnoreCase("y") || s.equalsIgnoreCase("z")) return true;
else return false;
}
Right now, your code fails for null strings and for empty strings, so add a check before doing any processing:
int count = 0;
if(str == null || str.length() == 0) //check null first or you will get NPE!
return count;
Finally, you can update your code with the new helper method you created. If you understand how regex works, it's easier to use String.split() to process your words:
public static int countYZ(String str) {
int count = 0;
if(str == null || str.length() == 0) {
return count;
}
String[] words = str.split("[^A-z]"); //"not an alphabetic letter immediately following it"
for(String word : words) {
if(word.length() > 0) { //sanity check
if(isYOrZ(word.substring(word.length()-1))) {
++count;
}
}
}
return count;
}
Now you can test, write as many weird test cases that you can think of. For example, a huge string of spaces, an empty string, etc. Here are a few I tried:
System.out.println(countYZ("heavY yummy TASTY yellow zed buzz"));
System.out.println(countYZ(""));
System.out.println(countYZ(null));
System.out.println(countYZ("fiZz yay"));
System.out.println(countYZ("zzzZZza yyy"));
System.out.println(countYZ("z"));
System.out.println(countYZ(" "));
System.out.println(countYZ("heavy&testy#!##BuzZ")); //3
Which gives:
4
0
0
2
1
1
0
3
I'm trying to determine if a word entered differs by one character in a text file. I have code that works, but unfortunately only for words that are two characters or less which obviously isn't very useful, and the code itself looks a bit messy. Here's what I have so far:
if(random.length() == word.length()){
for(int i = 0; i < random.length(); i++){
if( (word.charAt(i) == random.charAt(i))){
str += word+"\n";
count++;
}
}
}
With random being the word that was entered by the user, and word being the word to search for in the text file.
If I changed my second if statement to something along the lines of
if( (word.charAt(i) == random.charAt(i)) && (word.charAt(i -1) == random.charAt(i-1)))
and if I change int i to be = 1 instead, I seem to get more of what I'm looking to accomplish, but then my code is searching for only if the first two letters are the same and not if the last two are as well, which it should be doing.
I assume you need a function like this? I just wrote and tested it.
static boolean equals(String word1, String word2, int mistakesAllowed) {
if(word1.equals(word2)) // if word1 equals word2, we can always return true
return true;
if(word1.length() == word2.length()) { // if word1 is as long as word 2
for(int i = 0; i < word1.length(); i++) { // go from first to last character index the words
if(word1.charAt(i) != word2.charAt(i)) { // if this character from word 1 does not equal the character from word 2
mistakesAllowed--; // reduce one mistake allowed
if(mistakesAllowed < 0) { // and if you have more mistakes than allowed
return false; // return false
}
}
}
}
return true;
}
Your code seems to be working to me, you just may be interpreting its results incorrectly.
This may be more obvious:
int count = 0; if(random.length() == word.length()) {
for(int i = 0; i < random.length(); i++)
{
if( (word.charAt(i) != random.charAt(i) ))
{
if(count == 0)
{
System.out.println("Found first difference!");
}
if(count != 0)
{
System.out.println("Strings are more than one letter different!");
}
count++;
}
} }
If you want to check Strings of different lengths, you'll need to delete characters from the longer one until it's the same size as the shorter.
For example:
If String1 = "abc";
and String2 = "zzzabcdef";
You'll need to delete 6 characters from the second string and test for every combination of 6 characters deleted. So you would want to test the strings: def, cde, abc, zab, zza, zzz, zzb, zzc, zzd, zze, zzf, zaf, zae, zad, zac, zab, zza, zzf, zze, ..., ..., on and on, the list is of size 9 choose 6, so it's definitely not optimal or recommended.
You can however, check to see if a string which is one character longer than the other is just the other string with one added letter. To do this, you want a for loop to grab two substring from 0 to i, and from i+1 to the end. This will leave out the ith character, and looping for the size of the string - 1, will give you first the full string, then the string without the first letter, then missing the second letter, and so on. Then test that substring in the same fashion we did above.
Comment if this was not what you're looking for.
EDIT
To see how many words in a file are one letter different than a variable word, you need to loop through the file, getting each word. Then testing if that was string was one letter off. It would be something like this:
String testAgainst = "lookingForWordsOneLetterDifferentThanThisString";
int words = 0;
Scanner scan = new Scanner(fileName);
while(scan.hasNext())
{
String word = scan.next();
if( isOneDifferent(word, testAgainst) )
{
words++;
}
System.out.println("Number of words one letter different: " + words);
}
public boolean isOneDifferent(String word, String testAgainst)
{
if(word.length() != testAgainst.length())
{
return false;
}
int diffs = 0;
for(int i = 0; i < word.length(); i++)
{
if(word.charAt(i) != testAgainst.charAt(i))
{
diffs++;
}
if(diffs > 1)
{
return false;
}
}
if(diffs == 1)
{
return true;
}
else
{
return false;
}
}
Hi I need some help with my internship test task. I've read it a couple of times and I can't even say that I'm surely know what I need to do. So the task is:
You must generate a string of random length consisting of random ASCII characters. After that you need to replace all entries of '1' with 'Q' and 'Q' with '1' in it. To complete the task you are allowed to change one substring with another as many times as you want. For example as a result of changing "ww" -> "wert" the string "wwwwwQ" will become "wertwertwQ". Write a program which does required changes in the most optimal way (doing minimum amount of replacements).
I've already implemented string generation and i simply don't know what to do next. As said in the header, i need to do this using Java. Could you please offer me some way to solve this task?
As i said what i've already done is genString() which generates a char array for me and a replace() method which does what intended but it not uses substrings so it seems that this task should be done another way.
public static char[] genString()
{
int n = rand.nextInt(50) + 1;
char[] arr = new char[n];
for (int i = 0; i<n; i++)
{
arr[i] = (char)(rand.nextInt(95) + 33);
}
return arr;
}
public static void replace(char[] arr)
{
for (int i = 0; i < arr.length; i++)
{
arr[i] = (arr[i] == 'Q') ? '1'
: (arr[i] == '1' ) ? 'Q'
: arr[i];
}
}
What i actually don't understand is that how the substrings could be used there. I don't understand how going from "wwwwwQ" to "wertwertwQ" -like replacements will help me replace the 'Q' in it
To make the fewest replacements, I would use a stream-based approach:
StringBuilder sb = new StringBuilder(str);
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == 'Q') {
sb.setCharAt(i, '1');
} else if (str.charAt(i) == '1') {
sb.setCharAt(i, 'Q');
}
}
return sb.toString();
Using a StringBuilder make manipulating the string a lot more efficient, because a new string doesn't have to be created every time you change a letter.
well, try this code:
public String Replace(String theString, String first, String Second)
{
String result ="";
result=theString.replace(first, Second);
return result;
}
Example of using:
System.out.println(Replace("wwwwwQ", "ww", "wert"));// result will be: wertwertwQ
I hope it will help you, best regards
So I am trying to figure out if two strings when combined together are a substring of a permutation of another string.
I have what I believe to be a working solution but it is failing some of the JUnit test cases and I dont have access to the ones that it is failing on.
here is my code with one test case
String a="tommarvoloriddle";
String b="lord";
String c="voldemort";
String b= b+c;
char[] w= a.toCharArray();
char[] k= b.toCharArray();
Arrays.sort(k);
Arrays.sort(w);
pw.println(isPermuation(w,k)?"YES":"NO");
static boolean isPermuation(char[] w, char[] k)
{
boolean found=false;
for(int i=0; i<k.length; i++)
{
for(int j=i; j<w.length; j++)
{
if(k[i]==w[j])
{
j=w.length;
found=true;
}
else
found=false;
}
}
return found;
}
any help getting this to always produce the correct answer would be awesome and help making it more efficient would be great too
What you have is not a working solution. However, you don't explain why you thought it might be, so it's hard to figure out what you intended. I will point out that your code updates found unconditionally for each inner loop, so isPermutation() will always return the result of the last comparison (which is certainly not what you want).
You did the right thing in sorting the two arrays in the first place -- this is a classic step which should allow you to efficiently evaluate them in one pass. But then, instead of a single pass, you use a nested loop -- what did you intend here?
A single pass implementation might be something like:
static boolean isPermutation(char[] w, char[] k) {
int k_idx=0;
for(w_idx=0; w_idx < w.length; ++w_idx) {
if(k_idx == k.length)
return true; // all characters in k are present in w
if( w[w_idx] > k[k_idx] )
return false; // found character in k not present in w
if( w[w_idx] == k[k_idx] )
++k_idx; // character from k corresponds to character from w
}
// any remaining characters in k are not present in w
return k_idx == k.length;
}
So we are only interested in whether the two combined strings are a subset of a permutation of another string, meaning that the lengths can in fact differ. So let's say we have:
String a = "tommarvoloriddle";
String b = "lord";
String c = "voldemort";
char[] master = a.ToCharArray();
char[] combined = (b + c).ToCharArray();
Arrays.Sort(master);
Arrays.Sort(combined);
System.out.println(IsPermutation(master, combined) ? "YES" : "NO");
Then our method is:
static boolean IsPermutation(char[] masterString, char[] combinedString)
{
int combinedStringIndex = 0;
int charsFound = 0;
int result = 0;
for (int i = 0; i < masterString.Length; ++i) {
result = combinedString[combinedStringIndex].CompareTo(masterString[i]);
if (result == 0) {
charsFound++;
combinedStringIndex++;
}
else if (result < 0) {
return false;
}
}
return (charsFound == combinedString.Length);
}
What the above method does: it starts comparing characters of the two strings. If we have a mismatch, that is, the character at the current masterString index does not match the character at the current combinedString index, then we simply look at the next character of masterString and see if that matches. At the end, we tally the total number of characters matched from our combinedString, and, if they are equal to the total number of characters in combinedString (its length), then we have established that it is indeed a permutation of masterString. If at any point, the current character in masterString is numerically greater than the current character in combinedString then it means that we will never be able to match the current character, so we give up. Hope that helps.
If two Strings are a permuation of the other you should be able to do this
public static boolean isPermuted(Strign s1, String s2) {
if (s1.length() != s2.length()) return false;
char[] chars1 = s1.toCharArray();
char[] chars2 = s2.toCharArray();
Arrays.sort(chars1);
Arrays.sort(chars2);
return Arrays.equals(chars1, chars2);
}
This means that when sorted the characters are the same, in the same number.
Good day stack overflow.
I'm a noob in using regex and here is my problem - I need to check a password if it contains 4 consecutive characters. so far what I have just covered is regarding the digits. Here is my regex:
ascending digits - ^.?(?:0123|1234|2345|3456|4567|5678|6789).$
descending digits - ^.?(?:9876|8765|7654|6543|5432|4321|3210).$
This works only for the digits. I know this is already an overkill in regex so I dont want to do it with the letters. It will be waaay too overkill if I do that.
abcdblah //true because of abcd
helobcde //true because of bcde
dcbablah //true beacause of dcba
heloedcb //true because of edcb
Any help would be highly appreciated. Thanks stackoverflow.
The answer is simple: don't use regexes.
Use this approach:
iterate over each letter (of course, skip the last tree letters)
iterate over the next three letters and check for ascending order
if they all were ascending return true.
iterate over the next three letters and check for descending order
if they all were descending return false.
return false
In code, this would look like this (untested code):
public boolean checkForAscendingOrDescendingPart(String txt, int l)
{
for (int i = 0; i <= txt.length() - l; ++i)
{
boolean success = true;
char c = txt.charAt(i);
for (int j = 1; j < l; ++j)
{
if (((char) c + j) != txt.charAt(i + j))
{
success = false;
break;
}
}
if (success) return true;
success = true;
for (int j = 1; j < l; ++j)
{
if (((char) c - j) != txt.charAt(i + j))
{
success = false;
break;
}
}
if (success) return true;
}
return false;
}
Good luck!
StackOverflow :)
here is an idea that doesn't use regex:
all characters have an ansi value and usually consecutive. so abcd should have let's say the following ansi values:64,65,66,67
pseudocode:
for (i=string.start;i<string.end-4;i++) {
check=string.substring(i,4);
c1=check.substring(0,1);
c2=check.substring(1,1);
c3=check.substring(2,1);
c4=check.substring(3,1);
if (c1.ansival==c2.ansival+1 && c2.ansival==c3.ansival+1 && c3.ansival==c4.ansival+1) {
return false;
} else {
return true;
}
}
also repeat in reverse order (c1.ansival+1==c2.ansival) for descending order
There is no way to solve this using regexes apart from the "overkill" solution of listing each of the possible sequences you want to match. Regexes are not expressive enough to offer a better solution.
This is my solution. It uses only a single loop.
Keep in mind that you'll need more logic if you want to constrain it to pure ASCII.
static boolean isWeak(String pass) {
Character prev = null;
Boolean asc = null;
int streak = 0;
for (char c : pass.toCharArray()) {
if (prev != null) {
switch (c - prev) {
case -1:
if (Boolean.FALSE.equals(asc)) streak++;
else { asc = false; streak = 2; }
break;
case 1:
if (Boolean.TRUE.equals(asc)) streak++;
else { asc = true; streak = 2; }
break;
default: asc = null; streak = 0;
}
if (streak == 4) return true;
}
prev = c;
}
return false;
}
Consider this
String s = "aba";
for (int i = 0; i < s.length() - 1; i++) {
if (!(Character.isLetter(c1) && Character.isLetter(c2))) {
//reject
}
if ((int)s.charAt(i) > (int)s.charAt(i + 1))) {
//reject
}
}
for s the if statement would be true so you could reject it. If s was abc then the if statement would never be true.
The code above using the > checks for ascending order. Use < for descending order