Why am I getting whitespaces in StringBuilder in Java? - java

I wrote a method that returns a rotated StringBuilder with a given key. However, although it is working fine, it's adding white spaces within the StringBuilder.
public static StringBuilder rotateCipher(String plain, int key) {
int keyTemp = key;
char[] rotatedChar = new char[plain.length()];
StringBuilder builder = new StringBuilder();
for (int i = 0; i < plain.length(); i++) {
rotatedChar[i] = plain.charAt(key);
key++;
if (key == plain.length()) {
builder.append(String.valueOf(rotatedChar));
builder.append(plain.substring(0, keyTemp + 1));
break;
}
}
return builder;
}
Output: nopqrstuvwxyz abcdefghijklmn

The reason for the whitespace is that the array rotatedChar does not have all it's elements filled. By default, a char[] contains only (char)0 elements.
When you call this method with the parameters "abcdefghijklmnopqrstuvwxyz", 13 then only the first 13 elements of rotatedChar get filled, then you hit the if-condition and break out of the loop. That means you have the remaining 13 elements left as 0s, which is a nonprintable character, so it appears as whitespace.
It's a bit hard to suggest which part to change here because as Gabe pointed out in the comments, the solution only requires 2 calls to substring.
If you really want to use loops, maybe this can be an approach:
for (int i = 0; i < plain.length(); i++) {
rotatedChar[i] = plain.charAt(key);
key++;
if (key == plain.length()) {
//this "restarts" taking chars from the beginning of the string
key = 0;
}
}
return String.valueOf(rotatedChar);

Related

Remove a Character From String in Java

I'm trying to concatenate a string with itself and remove all capital letters from the resultant string.
Here is my code:
public String removeCapitals(String A) {
StringBuilder B = new StringBuilder(A+A);
int n = B.length();
for(int i=0; i<n; i++){
if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
B.deleteCharAt(i);
}
}
return B.toString();
}
I'm getting Exception saying:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6
at java.lang.AbstractStringBuilder.charAt(AbstractStringBuilder.java:237)
at java.lang.StringBuilder.charAt(StringBuilder.java:76)
at Solution.removeCapitals(Solution.java:10)
at Main.main(Main.java:190)
Can someone help me to understand the issue.
If at least one removal succeeds, at some point your code will attempt to access an invalid index that exceeds the length of a StringBuilder.
It happens because the variable n remain unchanged. You should change the condition to be bound to the current size of StringBuilder and decrement the index at each removal, or iterate backwards (as shown in another answer).
Also condition B.charAt(i)>='A' && B.charAt(i)<='Z' can be replaced with:
Character.isUpperCase(b.charAt(i))
Which is more descriptive.
That's how it might look like:
public static String removeCapitals(String a) {
StringBuilder b = new StringBuilder(a + a);
for (int i = 0; i < b.length(); i++) {
if (Character.isUpperCase(b.charAt(i))) {
b.deleteCharAt(i); // which can be combined with the next line `b.deleteCharAt(i--);` - previous value of `i` would be used in the call `deleteCharAt()` and variable `i` will hold a value decremented by 1
i--;
}
}
return b.toString();
}
Method deleteCharAt() runs in a linear time, because it shifts all subsequent characters in the underlying array bytes. Each upper-case letter will trigger these shifts and in the worst case scenario, it would result in the quadratic overall time complexity O(n ^ 2).
You make your method more performant and much more concise without using loops and StringBuilder. This code will run in a linear time O(n).
public static String removeCapitals(String a) {
return a.replaceAll("\\p{Upper}", "").repeat(2);
}
When you delete a character you change the length of the StringBuilder. But n still has the original length. So you will eventually exceed the size of the StringBuilder. So start from the end and move backwards. That way, any deletions will come after (based on relative indices) the next position so the index will be within the modified StringBuilder size. In addition, deleting from the end is more efficient since there is less copying to do in the StringBuilder.
public String removeCapitals(String A) {
StringBuilder B = new StringBuilder(A+A);
int n = B.length();
for(int i=n-1; i>=0; i--){
if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
B.deleteCharAt(i);
}
}
return B.toString();
}
If just remove Capital characters from a string. Alternative solution just create another method replaceAll() + regex
private static String removeCapitals(String A){
if (!A.isEmpty() && !A.equals("")) {
String B = A + A;
String newStr = B.replaceAll("([A-Z])", "");
return newStr;
} else {
return null;
}
}
Shorter solution to your task.
String a = "ABcdEF";
String b = "";
for (int i = 0; i < a.length(); i++) {
if(a.toLowerCase().charAt(i) == a.charAt(i))
b+=a.charAt(i);
}
System.out.println(b);
By changing to .toUpperCase() you'll get rid of the lower case ones.

Replacing the letters of a String with blank if they are found in another

I am working on an assignment and this part is tripping me up.
Construct cipher1 by first filling in the matrix with the unique letters from the first key.
For example, if the key is “testkey”, then fill in the key with the letters T, E, S, K, Y.
Do not fill in repeated characters from the key. Then fill the matrix with the remaining characters of the alphabet (again, skipping Q).
Do not repeat any characters that appeared in the key. So, for “testkey”, cipher1 looks like this: "
The cypher is a 5 by 5 array usually filled with the letters of the alphabet minus 'q'.
So if my key is testkey, the cipher will now be filled with "TESKYABCDFGHIJLMNOPRUVWXZ" instead of "ABCDEFGHIJKLMNOPRSTUVWXYZ".
I thought something like this would work but it doesn't.
for (int i = 0; i < key.length(); i++)
{
key.toCharArray();
alphabet.replace(key[i], "");
}
The key variable being a string "TESTKEY" and the alphabet variable also being a string containing "ABCDEFGHIJKLMNOPRSTUVWXYZ".
Looking at it now that code is obviously flawed and now I'm just stuck. Please any one give the suggestion to me
Try this :
public static void main(String[] args) {
String testS = "testkey";
String key = "ABCDEFGHIJKLMNOPRSTUVWXYZ";
testS = testS.toUpperCase() + key;
testS = removeDuplicates(testS);
System.out.println(testS);
}
static String removeDuplicates(String string) {
StringBuilder noDuplicateChars = new StringBuilder();
for (int i = 0; i < string.length(); i++) {
String letter = string.substring(i, i + 1);
if (noDuplicateChars.indexOf(letter) == -1) {
noDuplicateChars.append(letter);
}
}
return noDuplicateChars.toString();
}
If from some reason you don't want to use StringBuilder, you can change the implementation of removeDuplicates to :
static String removeDuplicates(String string) {
String noDuplicates = new String("");
for (int i = 0; i < string.length(); i++) {
if (!noDuplicates.contains("" + string.charAt(i))) {
noDuplicates += "" + string.charAt(i);
}
}
return noDuplicates;
}
You can use LinkedHashSet. In for loop add key characters and in second loop add alphabet characters. Then iterate through set elements and build string.
Note that method add do not place element if it already exist in the set, hence no additional checks are needed.
You just need to use regular expression;
example: 1 - key
input: testkey
code: `String newString = input.replaceAll("(.)\\1{1,}", "$1").toUpperCase();`
output: TESKY
Example 2; Concat newString with the alphapatical string
input: testkey + "ABCDEFGHIJKLMNOPRSTUVWXYZ";
code: `String FinalString = input.replaceAll("(.)\\1{1,}", "$1").toUpperCase();`
output: TESKYABCDFGHIJLMNOPRUVWXZ

Java find difference between characters in StringBuffer

I'm working on an Anagram program and I'm currently working on a method called diff which should return a StringBuffer containing the chars that are in the first StringBuffer but not in the second one. So for example if the StringBuffers are abba and acca, then my diff method should return bb. So far I currently have loop with an if statement but it's not working. Any help would be appreciated. Thanks
public StringBuffer diff(){
StringBuffer diffVal = null;
for (int i =0; i < sBuffer1.length(); i++){
String let1 = String.valueOf(sBuffer1);
if (sBuffer2.indexOf(let1) == -1 ){
}
}
return diffVal;
I think you are trying to use a loop to examine one character by one character in sBuffer1. But String let1 = String.valueOf(sBuffer1); gives you the entire string of sBuffer1.
What you need is String let1 = sBuffer1.substring(i, i + 1) to take a single character from sBuffer1 to check if it exists in sBuffer2.
For example:
public static StringBuffer diff(StringBuffer sBuffer1, StringBuffer sBuffer2) {
StringBuffer diffVal = new StringBuffer();
for (int i = 0; i < sBuffer1.length(); i++) {
String let1 = sBuffer1.substring(i, i + 1); // get the character from sBuffer1
if (sBuffer2.indexOf(let1) == -1) {
diffVal.append(let1); // append the character to the diff
}
}
return diffVal;
}
ok this might work, your logic was a little bit wrong, this code is straight forward. search for the character if it doesn't exist in the second string buffer add it to the result SF.
public StringBuffer diff(){
StringBuffer diffVal = new StringBuffer();//initialize before you use it.
for (int i =0; i < sBuffer1.length(); i++){
String let1 = String.valueOf(sBuffer1.charAt(i))//get the character at the ith position.
if (sBuffer2.indexOf(let1) == -1 ){
diffVal.append(let1);
}
}
return diffVal;
}
Try this.
StringBuilder diffVal= new StringBuilder();
StringBuffer sBuffer1 = new StringBuffer("abbad");//input 1
StringBuffer sBuffer2 = new StringBuffer("acca");//input 2, you can ignore if you have already passed/defined these
for (int i =0; i < sBuffer1.length(); i++){
if(i >= sBuffer2.length()){//handles difference in input string length
diffVal.append(sBuffer1.substring(i, sBuffer1.length()));
break;
}
if (sBuffer1.charAt(i) != sBuffer2.charAt(i)) {
diffVal.append(sBuffer1.charAt(i));
}
}
System.out.println(diffVal);// I am printing it here
the out put is : bbd
One recommendation here is use StringBuilder if you the strings you are using here are not required to be synchronized

Removing duplicates from a string

I am trying to remove duplicates from a String in Java. Here i what I have tried
public void unique(String s)
{
// put your code here
char[]newArray = s.toCharArray();
Set<Character> uniquUsers = new HashSet<Character>();
for (int i = 0; i < newArray.length; i++) {
if (!uniquUsers.add(newArray[i]))
newArray[i] =' ';
}
System.out.println(new String(newArray));
}
Problem with this is when I try to remove the duplicate I replace it with a space. I tried replacing the duplicate with '' but it cannot be done or I cant set the duplicate place to null. What is the best way to do this?
If you use regex, you only need one line!
public void unique(String s) {
System.out.println(s.replaceAll("(.)(?=.*\\1)", ""));
}
This removes (by replacing with blank) all characters that found again later in the input (by using a look ahead with a back reference to the captured character).
If I understand your question correctly, perhaps you could try something like:
public static String unique(final String string){
final StringBuilder builder = new StringBuilder();
for(final char c : string.toCharArray())
if(builder.indexOf(Character.toString(c)) == -1)
builder.append(c);
return builder.toString();
}
You can use BitSet
public String removeDuplicateChar(String str){
if(str==null || str.equals(""))throw new NullPointerException();
BitSet b = new BitSet(256);
for(int i=0;i<str.length();i++){
b.set(str.charAt(i));
}
StringBuilder s = new StringBuilder();
for(int i=0;i<256;i++){
if(b.isSet(i)){
s.append((char)i);
}
}
return s.toString();
}
You can roll down your own BitSet like below:
class BitSet {
int[] numbers;
BitSet(int k){
numbers = new int[(k >> 5) + 1];
}
boolean isSet(int k){
int remender = k & 0x1F;
int devide = k >> 5;
return ((numbers[devide] & (1 << remender)) == 1);
}
void set(int k){
int remender = k & 0x1F;
int devide = k >> 5;
numbers[devide] = numbers[devide] | (1 << remender);
}
}
This will work for what you are attempting.
public static void unique(String s) {
// r code here
char[] newArray = s.toCharArray();
Set<Character> uniqueUsers = new HashSet<>();
for (int i = 0; i < newArray.length; i++) {
uniqueUsers.add(newArray[i]);
}
newArray = new char[uniqueUsers.size()];
Iterator iterator = uniqueUsers.iterator();
int i = 0;
while (iterator.hasNext()) {
newArray[i] = (char)iterator.next();
i++;
}
System.out.println(new String(newArray));
}
without changing almost anything in your code, change the line
System.out.println(new String(newArray));
for
System.out.println( new String(newArray).replaceAll(" ", ""));
the addition of replaceAll will remove blanks
import java.util.*;
class StrDup{
public static void main(String[] args){
String s = "abcdabacdabbbabbbaaaaaaaaaaaaaaaaaaabbbbbbbbbbdddddddddcccccc";
String dup = removeDupl(s);
}
public static String removeDupl(String s){
StringBuilder sb = new StringBuilder(s);
String ch = "";
for(int i = 0; i < sb.length(); i++){
ch = sb.substring(i,i+1);
int j = i+1;
int k = 0;
while(sb.indexOf(ch,j)!=-1){
k = sb.indexOf(ch,j);
sb.deleleCharAt(k);
j = k;
}
}
return sb.toString();
}
}
In the code above, I'm doing the following tasks.
I'm first converting the string to a StringBuilder. Strings in Java are immutable, which means they are like CDs. You can't do anything with them once they are created. The only thing they are vulnerable to is their departure, i.e. the end of their life cycle by the garbage collector, but that's a whole different thing. Foe example:
String s = "Tanish";
s + "is a good boy";
This will do nothing. String s is still Tanish. To make the second line of code happen, you will have to assign the operation to some variable, like this:
s = s + "is a good boy";
And, make no mistake! I said strings are immutable, and here I am reassigning s with some new string. But, it's a NEW string. The original string Tanish is still there, somewhere in the pool of strings. Think of it like this: the string that you are creating is immutable. Tanish is immutable, but s is a reference variable. It can refer to anything in the course of its life. So, Tanish and Tanish is a good boy are 2 separate strings, but s now refers to the latter, instead of the former.
StringBuilder is another way of creating strings in Java, and they are mutable. You can change them. So, if Tanish is a StringBuilder, it is vulnerable to every kind of operation (append, insert, delete, etc.).
Now we have the StringBuilder sb, which is same as the String s.
I've used a StringBuilder built-in method, i.e. indexOf(). This methods finds the index of the character I'm looking for. Once I have the index, I delete the character at that index.
Remember, StringBuilder is mutable. And that's the reason I can delete the characters.
indexOf is overloaded to accept 2 arguments (sb.indexOf(substr ,index)). This returns you the position of the first occurrence of string within the sb, starting from index.
In the example string, sb.indexOf(a,1) will give me 4. All I'm trying to say to Java is, "Return me the index of 'a', but start looking for 'a' from index 1'. So, this way I've the very first a at 0, which I don't want to get rid of.
Now all I'm doing inside the for loop is extracting the character at ith position. j represents the position from where to start looking for the extracted character. This is important, so that we don't loose the one character we need. K represents the result of indexOf('a',j), i.e. the first occurrence of a, after index j.
That's pretty much it. Now, as long as we have a character ch lying in the string (indexOf(....) returns -1, if it can't find the specified character (...or the string as i specified before) as a duplicate, we will obtain it's position (k), delete it using deleteCharAt(k) and update j to k. i.e., the next duplicate a (if it exists) will appear after k, where it was last found.
DEMONSTRATION:
In the example I took, let's say we want to get rid of duplicate cs.
So, we will start looking for the first c after the very first c, i.e. index 3.
sb.indexOf("c",3) will give us 7, where a c is lying. so, k = 7. delete it, and then set j to k. Now, j = 7. Basically after deleting the character, the succeeding string shifts to left by 1. So, now at 7th pos we have d, which was at 8 before. Now, k = indexOf("c",7) and repeat the entire cycle. Also, remember that indexOf("c",j) will start looking right from j. which means if c, is found at j, it will return j. That's why when we extracted the first character, we started looking from position 1 after the character's position.
public class Duplicates {
public static void main(String[] args) {
String str="aabbccddeeff";
String[] str1 = str.split("");
ArrayList<String> List = new ArrayList<String>
Arrays.asList(str1);
List<String> newStr = List.stream().distinct().collect(Collectors.toList());
System.out.print(newStr);
}
}

Finding characters in a string

i'm doing an encoding program where i'm supposed to delete every character in the string which appears twice. i've tried to traverse through the string but it hasn't worked. does anyone know how to do this? Thanks.
public static String encodeScrambledAlphabet(String str)
{
String newword = str;
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
newword += alphabet;
newword = newword.toUpperCase();
for (int i = 0, j = newword.length(); i < newword.length() && j >=0; i++,j--)
{
char one = newword.charAt(i);
char two = newword.charAt(j);
if (one == two)
{
newword = newword.replace(one, ' ');
}
}
newword = newword.replaceAll(" ", "");
return newword;
}
Assuming that you would like to keep only the first occurrence of the character, you can do this:
boolean seen[65536];
StringBuilder res = new StringBuilder();
str = str.toUpperCase();
for (char c : str.toCharArray()) {
if (!seen[c]) res.append(c);
seen[c] = true;
}
return res.toString();
The seen array contains flags, one per character, indicating that we've seen this character already. If your characters are all ASCII, you can shrink the seen array to 128.
Assuming by saying deleting characters that appears twice, you mean AAABB becomes AAA, below code should work for you.
static String removeDuplicate(String s) {
StringBuilder newString = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
String s1 = s.substring(i, i + 1);
// We need deep copy of original String.
String s2 = new String(s);
// Difference in size in two Strings gives you the number of
// occurences of that character.
if(s.length() - s2.replaceAll(s1, "").length() != 2)
newString.append(s1);
}
return newString.toString();
}
Efficiency of this code is arguable :) It might be better approach to count the number of occurences of character by a loop.
So, from the code that you've shown, it looks like you aren't comparing every character in the string. You are comparing the first and last, then the second and next to last. Example:
Here's your string:
THISISTHESTRINGSTRINGABCDEFGHIJKLMNOPQRSTUVWXYZ
First iteration, you will be comparing the T at the beginning, and the Z at the end.
Second iteration, you will be comparing the H and the Y.
Third: I and X
etc.
So the T a the beginning never gets compared to the rest of the characters.
I think a better way to do this would be to to do a double for loop:
int length = newword.length(); // This way the number of iterations doesn't change
for(i = 0; i < length; i++){
for(j = 0; j < length; j++){
if(i!=j){
if(newword.charAt(i) == newword.charAt(j)){
newword.replace(newword.charAt(i), ' ');
}
}
}
}
I'm sure that's not the most efficient algorithm for it, but it should get it done.
EDIT: Added an if statement in the middle, to handle i==j case.
EDIT AGAIN: Here's an almost identical post: function to remove duplicate characters in a string

Categories