What's wrong with my code about swapping adjacent characters? - java

The question: Write a method called swapPairs that accepts a String as a parameter and returns that String with each pair of adjacent letters reversed. If the String has an odd number of letters, the last letter is unchanged. For example, the call swapPairs("example") should return "xemalpe" and the call swapPairs("hello there") should return "ehll ohtree".
public static String swapPairs(String s) {
String t="";
if(s.length()%2==0) {
for (int i=0;i<s.length()/2;i++) {
t+=s.charAt(2*i+1)+s.charAt(2*i);
}
}
else {
for (int i=0;i<s.length()/2;i++) {
t+=s.charAt(2*i+1)+s.charAt(2*i);
}
t+=s.charAt(s.length()-1);
}
return t;
}

You can use only 1 for cycles like:
public static String swapPairs(String s) {
StringBuilder t = new StringBuilder();
for(int i = 0; i < s.length() - 1; i += 2) {
t.append(s.charAt(i + 1));
t.append(s.charAt(i));
}
if(s.length() % 2 == 1) { //appending the last character if needed
t.append(s.charAt(s.length() - 1));
}
return t.toString();
}
Also using StringBuilder is a nice idea :)

String#charAt returns a char. Adding two chars will result in another char (because char is a numeric type), not in a String as you seem to expect. The compiler should give you an error message in that direction.
You could use String#substring instead.

You could just amend your method to use a StringBuilder instead and change it something like:
sb.append(s.charAt((2 * i) + 1)).append(s.charAt(2 * i));

Related

Find the amount of occurances of a character in a string recursively (java)

I am trying to write a method which returns the number of times the first character of a string appears throughout the string. This is what I have so far,
public int numberOfFirstChar0(String str) {
char ch = str.charAt(0);
if (str.equals("")) {
return 0;
}
if ((str.substring(0, 1).equals(ch))) {
return 1 + numberOfFirstChar0(str.substring(1));
}
return numberOfFirstChar0(str);
}
however, it does not seem to work (does not return the correct result of how many occurrences there are in the string). Is there anything wrong with the code? Any help is appreciated.
This uses 2 functions, one which is recursive. We obtain the character at the first index and the character array from the String once instead of doing it over and over and concatenating the String. We then use recursion to continue going through the indices of the character array.
Why you would do this I have no idea. A simple for-loop would achieve this in a much easier fashion.
private static int numberOfFirstChar0(String str) {
if (str.isEmpty()) {
return 0;
}
char[] characters = str.toCharArray();
char character = characters[0];
return occurrences(characters, character, 0, 0);
}
private static int occurrences(char[] characters, char character, int index, int occurrences) {
if (index >= characters.length - 1) {
return occurrences;
}
if (characters[index] == character) {
occurrences++;
}
return occurrences(characters, character, ++index, occurrences);
}
Java 8 Solution
private static long occurrencesOfFirst(String input) {
if (input.isEmpty()) {
return 0;
}
char characterAtIndexZero = input.charAt(0);
return input.chars()
.filter(character -> character == characterAtIndexZero)
.count();
}
Here is a simple example of what you are looking for.
Code
public static void main(String args[]) {
//the string we will use to count the occurence of the first character
String countMe = "abcaabbbdc";
//the counter used
int charCount=0;
for(int i = 0;i<countMe.length();i++) {
if(countMe.charAt(i)==countMe.charAt(0)) {
//add to counter
charCount++;
}
}
//print results
System.out.println("The character '"+countMe.charAt(0)+"' appears "+ charCount+ " times");
}
Output
The character 'a' appears 3 times

How to detect middle 3 characters from an odd number string that is inputted using a scanner? [duplicate]

I'm trying to take the last three chracters of any string and save it as another String variable. I'm having some tough time with my thought process.
String word = "onetwotwoone"
int length = word.length();
String new_word = id.getChars(length-3, length, buffer, index);
I don't know how to use the getChars method when it comes to buffer or index. Eclipse is making me have those in there. Any suggestions?
Why not just String substr = word.substring(word.length() - 3)?
Update
Please make sure you check that the String is at least 3 characters long before calling substring():
if (word.length() == 3) {
return word;
} else if (word.length() > 3) {
return word.substring(word.length() - 3);
} else {
// whatever is appropriate in this case
throw new IllegalArgumentException("word has fewer than 3 characters!");
}
I would consider right method from StringUtils class from Apache Commons Lang:
http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#right(java.lang.String,%20int)
It is safe. You will not get NullPointerException or StringIndexOutOfBoundsException.
Example usage:
StringUtils.right("abcdef", 3)
You can find more examples under the above link.
Here's some terse code that does the job using regex:
String last3 = str.replaceAll(".*?(.?.?.?)?$", "$1");
This code returns up to 3; if there are less than 3 it just returns the string.
This is how to do it safely without regex in one line:
String last3 = str == null || str.length() < 3 ?
str : str.substring(str.length() - 3);
By "safely", I mean without throwing an exception if the string is nulls or shorter than 3 characters (all the other answers are not "safe").
The above code is identical in effect to this code, if you prefer a more verbose, but potentially easier-to-read form:
String last3;
if (str == null || str.length() < 3) {
last3 = str;
} else {
last3 = str.substring(str.length() - 3);
}
String newString = originalString.substring(originalString.length()-3);
public String getLastThree(String myString) {
if(myString.length() > 3)
return myString.substring(myString.length()-3);
else
return myString;
}
If you want the String composed of the last three characters, you can use substring(int):
String new_word = word.substring(word.length() - 3);
If you actually want them as a character array, you should write
char[] buffer = new char[3];
int length = word.length();
word.getChars(length - 3, length, buffer, 0);
The first two arguments to getChars denote the portion of the string you want to extract. The third argument is the array into which that portion will be put. And the last argument gives the position in the buffer where the operation starts.
If the string has less than three characters, you'll get an exception in either of the above cases, so you might want to check for that.
Here is a method I use to get the last xx of a string:
public static String takeLast(String value, int count) {
if (value == null || value.trim().length() == 0 || count < 1) {
return "";
}
if (value.length() > count) {
return value.substring(value.length() - count);
} else {
return value;
}
}
Then use it like so:
String testStr = "this is a test string";
String last1 = takeLast(testStr, 1); //Output: g
String last4 = takeLast(testStr, 4); //Output: ring
This method would be helpful :
String rightPart(String text,int length)
{
if (text.length()<length) return text;
String raw = "";
for (int i = 1; i <= length; i++) {
raw += text.toCharArray()[text.length()-i];
}
return new StringBuilder(raw).reverse().toString();
}
The getChars string method does not return a value, instead it dumps its result into your buffer (or destination) array. The index parameter describes the start offset in your destination array.
Try this link for a more verbose description of the getChars method.
I agree with the others on this, I think substring would be a better way to handle what you're trying to accomplish.
You can use a substring
String word = "onetwotwoone"
int lenght = word.length(); //Note this should be function.
String numbers = word.substring(word.length() - 3);
Alternative way for "insufficient string length or null" save:
String numbers = defaultValue();
try{
numbers = word.substring(word.length() - 3);
} catch(Exception e) {
System.out.println("Insufficient String length");
}
This method will return the x amount of characters from the end.
public static String lastXChars(String v, int x) {
return v.length() <= x ? v : v.substring(v.length() - x);
}
//usage
System.out.println(lastXChars("stackoverflow", 4)); // flow

Java: Palindrome Finding Taking Too Long; How to Optimize?

I've written a function to find whether a given string (stripped of spaces) is a palindrome. Unfortunately, it takes too long to run. Any ideas how I can make the below code run faster? (I'm timing out on LeetCode's Online Judge):
public class Solution {
public boolean checkIfPalindrome(String s) {
if (s.length() == 0 || s.length() == 1) {
return true;
}
//if first letter == last letter
char first = s.charAt(0);
char second = s.charAt(s.length() - 1);
if (first == second) {
String shorterString = s.substring(1, s.length() - 1);
return isPalindrome(shorterString);
} else {
return false;
}
}
public String onlyCharacters(String s) {
String toReturn = "";
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
toReturn += c;
}
}
return toReturn;
}
public boolean isPalindrome(String s) {
s = onlyCharacters(s);
return checkIfPalindrome(s);
}
}
This isn't the most optimal way of finding if a string is palindrome or not.
Just loop through n/2 iterations (where n is length of string) and check if character at position i is equal to character at position n-i
If the length of the string s is n then s will be a palindrome if
s[i]=s[n-1-i] for i in range [0,ceil(n/2)] // 0 based index
Code:
public static boolean checkIfPalindrome(String s) {
for(int i=0;i<s.length()/2;i++) {
if(s.charAt(i)!=s.charAt(s.length()-i-1)) {
return false;
}
}
return true;
}
It's an algorithm method called "divide and conquer". But in this case is just to make it n/2 instead of n.
Here is a suitable algorithm that might just help :
1.For i = 1 to n/2
2.If string[i] = string[n-1] then continue in the loop
3.Else break and return false
4.return true
If n is the length of the input string, your code takes O(n^2) operations. This may surprise you because there are no nested loops in your code, but both the substring method and the += operator for Strings require the creation of a new String, which requires copying its contents.
To see this in action, I have inserted
System.out.println(s);
into the isPalindrome() and checkIfPalindrome() methods, and invoked
isPalindrome("doc, note: i dissent. a fast never prevents a fatness. i diet on cod");
This produces the following output:
docnoteidissentafastneverpreventsafatnessidietoncod
ocnoteidissentafastneverpreventsafatnessidietonco
ocnoteidissentafastneverpreventsafatnessidietonco
cnoteidissentafastneverpreventsafatnessidietonc
cnoteidissentafastneverpreventsafatnessidietonc
noteidissentafastneverpreventsafatnessidieton
noteidissentafastneverpreventsafatnessidieton
oteidissentafastneverpreventsafatnessidieto
oteidissentafastneverpreventsafatnessidieto
teidissentafastneverpreventsafatnessidiet
teidissentafastneverpreventsafatnessidiet
eidissentafastneverpreventsafatnessidie
eidissentafastneverpreventsafatnessidie
idissentafastneverpreventsafatnessidi
idissentafastneverpreventsafatnessidi
dissentafastneverpreventsafatnessid
dissentafastneverpreventsafatnessid
issentafastneverpreventsafatnessi
issentafastneverpreventsafatnessi
ssentafastneverpreventsafatness
ssentafastneverpreventsafatness
sentafastneverpreventsafatnes
sentafastneverpreventsafatnes
entafastneverpreventsafatne
entafastneverpreventsafatne
ntafastneverpreventsafatn
ntafastneverpreventsafatn
tafastneverpreventsafat
tafastneverpreventsafat
afastneverpreventsafa
afastneverpreventsafa
fastneverpreventsaf
fastneverpreventsaf
astneverpreventsa
astneverpreventsa
stneverprevents
stneverprevents
tneverprevent
tneverprevent
neverpreven
neverpreven
everpreve
everpreve
verprev
verprev
erpre
erpre
rpr
rpr
p
p
That's quite a wall of text we are asking the computer to compute! We also see that every String is created twice. That's because you needlessly invoke onlyCharacters() in every iteration.
To avoid creating intermediary String instances, you can use a String Builder:
String onlyCharacters(String s) {
StringBuilder toReturn = new StringBuilder();
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
toReturn.append(c);
}
}
return toReturn.toString();
}
Also, it turns out a StringBuilder has a cool method called reverse(), so we can simplify your program to:
boolean isPalindrome(String s) {
StringBuilder letters = new StringBuilder();
for (Character c : s.toCharArray()) {
if (Character.isLetter(c)) {
letters.append(c);
}
}
StringBuilder reversedLetters = new StringBuilder(letters).reverse();
return onlyLetters.equals(reversedLetters);
}
This code only creates 2 StringBuilder objects rather than n Strings, and is therefore about n/2 times faster than your code.
I found this to be faster than any other answer so far:
public class Solution {
public boolean isPalindrome(String s) {
for (int low = 0, high = s.length() - 1;; low++, high--) {
char cLow = 0, cHigh = 0;
// Find the next acceptable character for the increasing index.
while (low < high && !Character.isLetterOrDigit(cLow = s.charAt(low))) {
low++;
}
// Find the previous acceptable character for the decreasing index.
while (low < high && !Character.isLetterOrDigit(cHigh = s.charAt(high))) {
high--;
}
if (low >= high) {
// All previous character comparisons succeeded and we have a palindrome.
return true;
}
if (Character.toUpperCase(cLow) != Character.toUpperCase(cHigh)) {
// This is not a palindrome.
return false;
}
}
}
}
You have only one object: your original String. Every character is tested until we get acceptable characters (Character.isLetter). Then only those are compared.
No temporary object, no superflous checks. Straight to the goal: it does one thing but does it well.
Note: this answers the actual Leetcode OJ answer by checking alphanumerics instead of only letters and by not caring about the case.
You may use this StringBuilder.reverse() to check Palindrome:
private boolean isPalindrome(String str) {
StringBuilder strBuilder = new StringBuilder(str);
return str.equals(strBuilder.reverse().toString());
}

StackOverflowError when trying to find the reverse of a string using recursion in java

I'm trying to use recursion to find the reverse of a string, but I get a stackoverflowerror when I run my code. I'm new to recursion so I'm not sure what I need to do to fix it.
public static String reverse(String string) {
int index = 0;
if(string == null){
return " ";
}
else if(index < string.length()) {
char a;
a = string.charAt(index);
index += 1;
return a + reverse(string);
}
return " ";
}
This is not how recursion should work, because you are just passing the same string over and over again. You could use recursion, but there are two approaches for your problem.
Get the last character and call the method with a string that doesn't have the last character, like so:
public String reverse(final String string) {
if (string != null && !string.isEmpty()) {
final int length = string.length();
final char character = string.charAt(length - 1));
final String result = reverse(string.substring(0, length - 2));
if (result != null)
return String.valueOf(character) + result;
return String.valueOf(character);
}
return null;
}
I should not that I have not tested this, but the point is that I am changing the string passed and have a mechanism to detect when to quit calling my own method.
The second method is to do this without recursion, because you can accomplish this with some for loops and such. But for the sake of learning, check 1 :P
There are a number of problems. I've added some comments to try to help.
public static String reverse(String string) {
int index = 0;
if(string == null){
return " ";
}
/* This will always be true because index is always zero */
else if(index < string.length()) {
char a;
/* This gets the character at position zero */
a = string.charAt(index);
/* This increments zero by 1 */
index += 1;
/* This takes the character and then calls reverse again (the recursion.
The problem is that you are passing the full string in and so every time
you recurse, index will be zero again and the string will be exactly the same length.
So no exit criterion will ever be triggered.
As such this is an infinite recursion. */
return a + reverse(string);
}
return " ";
}
I would suggest considering the following:
On the last recursive call, i.e. when you start to "pop back" through each of the recursive calls, what is it that you expect to trigger this?
If you decide that on every recursive call you are going to shorten the string by removing the first character, then the last call would be an empty string.
On the other hand, if you decide that your last call will be that the index variable equals the string length, then you will want to consider passing in an extra parameter (the index) and increasing this by one on every recursive call.
The piece you seem to be missing is passing the index into your function. Also, you need to return the current character at the end when you recurse. I think you wanted something like
private static String reverse(String string, int index) {
if (string != null && index < string.length()) {
char a = string.charAt(index);
return reverse(string, index + 1) + a;
}
return "";
}
Then your method in the public interface can call that function with an initial index of 0 like
public static String reverse(String string) {
return reverse(string, 0);
}
Of course, in real code I would prefer StringBuilder and something like
public static String reverse(String string) {
StringBuilder sb = new StringBuilder(string);
return sb.reverse().toString();
}
You're initializing variables "index and a" each time the recursive method get called. Initialize all of the variable outside the method block.
Try this function..
public static String reverse(String str){
if(str.length()<=0||str.length()==1)
return str;
return reverse(str.substring(1))+str.charAt(0);
}

Testing toString but it's failing?

Using this code:
public String toString()
{
StringBuilder s = new StringBuilder();
for (int i = 0; i < length; i++)
{
s.append(i).append(":").append(arr[i]).append(", ");
}
s.delete(s.length()-2, s.length()-1);
return s.toString();
}
is not passing this test:
#Test
public void testToString()
{
BetterArray<String> b = new BetterArray<String>();
assertEquals("", b.toString());
b.add("hello");
assertEquals("0:hello", b.toString());
b.add("bye");
assertEquals("0:hello, 1:bye", b.toString());
b.add("adios");
assertEquals("0:hello, 1:bye, 2:adios", b.toString());
}
It needs to start out as an empty string (""), am i doing that correctly? I'm new to StringBuilder. I'm using the s.delete to remove the trailing comma and space
This will cause a java.lang.StringIndexOutOfBoundsException in the case of empty string since you will not have comma and trailing space.
s.delete(s.length()-2, s.length()-1);
You're only deleting the comma, the delete line needs to be s.delete(s.length()-2, s.length());.
(By convention, the end index of a range points 1 past the last element of the range. This is the same for String.substring() for example.)
Here's one way to do what you want that doesn't rely on any math tricks. If the length is zero, the method returns an empty string.
public String toString() {
StringBuilder s = new StringBuilder();
for (int i = 0; i < length; i++) {
s.append(i);
s.append(":");
s.append(arr[i]);
if (i < (length - 1)) s.append(", ");
}
return s.toString();
}

Categories