How to take a 1's complement of a binary String - java

I have a String of length >10^4 which has only binary numbers.
How can I take 1's complement of it ?
Example- Sting a = "0101"
I want String b = "1010"
Is there any better method other than replacing every character using StringBuffer/StringBuilder?

I suggest to avoid reinventing the wheel you use BigInteger. It’s not method gives you almost what you want, only it gives you a negative number when applied to a positive one. To get back into positive, add 2^n where n is the length of the original string:
String a = "0101";
BigInteger twoToLength = new BigInteger("2").pow(a.length());
String b = twoToLength.add(new BigInteger(a, 2).not()).toString(2);
System.out.println(b);
This prints:
1010
The argument 2 to the constructor and toString() is an radix indicating binary numbers.
We are not quite there yet: if the original string has leading ones, the leading zeroes in the result are not printed. You will have to prepend these manually to get the same string length as you had originally. I think the easiest way to do this is to add 2^(n+1) instead of 2^n so we are sure there is at least one 1 bit in front of the bits we really care about. So we remove this bit only after converting back to a string:
String a = "0101";
int length = a.length();
// add a couple of more bits in front to make sure we have a positive number
BigInteger twoToLengthPlus1 = BigInteger.ONE.shiftLeft(length + 1);
String b = twoToLengthPlus1.add(new BigInteger(a, 2).not()).toString(2);
// remove extra bits from the front again
b = b.substring(b.length() - length);
With this change 1010 becomes 0101.

Does it have to be a String? If a CharSequence is enough, you can do this:
public class BinaryComplementCharSequence implements CharSequence {
private final String source;
public BinaryComplementCharSequence(String source) {
this.source = source;
}
#Override
public int length() {
return source.length();
}
#Override
public char charAt(int index) {
switch (source.charAt(index)) {
case '0':
return '1';
case '1':
return '0';
default:
throw new IllegalStateException();
}
}
#Override
public CharSequence subSequence(int start, int end) {
return new BinaryComplementCharSequence(source.substring(start, end));
}
#Override
public String toString() {
return new StringBuilder(length()).append(this).toString();
}
}
If you really need a String, call toString() (but that uses a StringBuilder again).

You've already figured it out: use a StringBuilder and replace every bloody char individually.
You could also use a char array: char ca[] = str.toCharArray() to extract the characters, modify individual chars in ca, String newstr =new String(ca) to pack the array back into a String. Might be slightly faster.
Take your pick.

Every char check with '1' and invert:
char[] charsConverted = new char[a.length()];
char[] charArray = a.toCharArray();
for (int i = 0; i < charArray.length; i++) {
boolean b = charArray[i] == '1';
charsConverted[i] = !b ? '1' : '0';
}
String b= String.valueOf(charsConverted);

Related

Java - Help converting letter to integer, adding 5, then converting back to letter

First off, here is my code so far
public int encrypt() {
/* This method will apply a simple encrypted algorithm to the text.
* Replace each character with the character that is five steps away from
* it in the alphabet. For instance, 'A' becomes 'F', 'Y' becomes '~' and
* so on. Builds a string with these new encrypted values and returns it.
*/
text = toLower;
encrypt = "";
int eNum = 0;
for (int i = 0; i <text.length(); i++) {
c = text.charAt(i);
if ((Character.isLetter(c))) {
eNum = (int) - (int)'a' + 5;
}
}
return eNum;
}
(text is the inputted string by the way. And toLower makes the string all lower case to make it easier converting.)
I got most of my assignment done, but one part of it is tasking me with moving every letter inputted 5 spaces over. A becomes F, B becomes G, etc.
So far from I got the letter converted to a number, but I am having trouble adding to it and then returning it back to a letter.
When I run the program and I enter my input such as "abc" I get '8'. It just adds them all up.
Any help would be much appreciated, and I can post the full code if necessary.
Few issues -
First of all - eNum = (int) - (int)'a' + 5; you do not need the first (int) - i believe, you can just do - eNum = (int)c + 5; . Your expression would always result in a negative integer.
Instead of returning eNum you should convert it to character and add it to a string and return the string at end (or you can create a character array of same length as string , keep storing the characters in the array, and return a string created from the character array).
Instead of using a in the condition , you should use c which denotes the current character at the ith index.
I am guessing not all of the variables in your code are member variables (instance variables) of the class , so you should define them with a datatype in your code.
Example changes to your code -
String text = toLower; //if toLower is not correct, use a correct variable to get the data to encrypt from.
String encrypt = "";
for (int i = 0; i <text.length(); i++) {
char c = text.charAt(i);
if ((Character.isLetter(c))) {
encrypt += (char)((int)c + 5);
}
}
return encrypt;
//Just a quick conversion for testing
String yourInput = "AbC".toLowerCase();
String convertedString = "";
for (int i = 0; i <text.length(); i++) {
char c = yourInput.charAt(i);
int num = Character.getNumericValue(c);
num = (num + 5)%128 //If you somehow manage to pass 127, to prevent errors, start at 0 again using modulus
convertedString += Integer.toString(num);
}
System.out.println(convertedString);
Hope this is what you're looking for.
Try something like this, I believe this has several advantages:
public String encrypt(String in) {
String workingCopy = in.toLowerCase();
StringBuilder out = new StringBuilder();
for (int i = 0; i < workingCopy.length(); i++) {
char c = workingCopy.charAt(i);
if ((Character.isLetter(c))) {
out.append((char)(c + 5));
}
}
return out.toString();
}
This code is a little bit verbose, but perhaps then it is easier to follow. I introduced the StringBuilder because it is more efficient than doing string = string + x

Java- Palindrome Program

I have been assigned to complete a palindrome program. However, I cannot use the charAt method.
Typically, I'd be able to solve this fairly quickly. However, since I cannot use charAt, I have no clue as to how I should go about doing this.
My idea is to take the length of the string, divide it by two (however this limits me to strings only with an even number of chars) then convert the substrings into int's and then finally compare the two int's.
This is my code thus far-
public static boolean isPal(String s)
{
int length = s.length();
int math = length / 2;
String side1 = s.substring(1,math);
String side2 = s.substring(math, length);
int s1 = Integer.parseInt(side1);
int s2 = Integer.parseInt(side2);
if(s1 == s2){
return true;
} else {
return false;
}
}
However, I have realized that this might not, and probably is not, the best way to handle the situation. I am currently running into this error-
Exception in thread "main" java.lang.NumberFormatException: For input string: "i"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at Palindrome.isPal(Lab08st.java:47)
at Lab08st.main(Lab08st.java:20)
I believe it is because I need a for loop of sorts.
However, having inadequate Java experience, I am unsure.
I am open to any and all suggestions. (So long as they do not require charAt)
Use this:
public static boolean isPal(String s) {
char[] chars = s.toCharArray();
int len = chars.length;
for (int i = 0; i < len ; i++) {
if(chars[i] != chars[len-i-1] ){
return false;
}
}
return true;
}
Your approach is flawed in several ways:
Integer.parseInt(String) only works on optionally-signed digit strings that represent base-10 numbers representable as type int. Your function will utterly fail on non-numeric inputs, and on inputs that are too large for the halves to be represented as ints (some 19-20-character inputs; all longer inputs).
Your function will fail on any input having an odd number of characters, because you cannot split such inputs evenly into halves.
Your logic is flawed anyway. It would judge "1010" a palindrome (which it isn't), and it would judge "1001" not a palindrome (though it is one).
You can pick out the input String's characters one-by-one via a variety of techniques, among them:
You can get the characters in a char[] via String.toCharArray(), as has elsewhere been suggested.
You can consume the input via a series of substring() invocations.
You can use a StringCharacterIterator to iterate over the characters
Since it's not clear why you are not permitted to use charAt(), here's an approach that altogether avoids relying on indexing:
import java.text.StringCharacterIterator;
// ...
public static boolean isPal(String s)
{
StringCharacterIterator it = new StringCharacterIterator(s);
String reversed = ""
for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
reversed = c + reversed;
}
return reversed.equals(s);
}
There are more efficient approaches, but that one is clear and simple.
Or here's one that doesn't rely (explicitly) on any classes other then String, but does use the indexes 0 and 1:
public static boolean isPal(String s)
{
String tail = s;
String reversed = ""
while (tail.length() > 0) {
reversed = tail.substring(0, 1) + reversed;
tail = tail.substring(1);
}
return reversed.equals(s);
}
Or since you had the idea of splitting the String into two, perhaps that was directed by your instructor? Are you perhaps studying recursion? Because you can also reverse the input string via a recursive algorithm: (1) split the string in two (as evenly as possible works best); (2) recursively reverse each half; (3) put the reversed halves back together in the opposite order. (Implementation left as an exercise.)
With all that said, do note that Reticality's one-liner using StringBuilder.reverse() is better on all counts if it satisfies the requirements.
My Solution-
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String str = "pappap";
String sp = str.toLowerCase();
char[] ch = sp.toCharArray();
int len = ch.length;
int lastIndex = ch.length-1;
int count = 1;
int first = 0;
int last = sp.length()-1;
for(; first < last ;){
if(ch[first] == ch[last] ){
first= first+1;
last= last-1;
}
else{
count = 0;
break;
}
}
String result = (count == 1) ? "Palindrome" : "Not a palindrome " ;
System.out.println(result);
}
}
If you are checking to see if a number, given to you as a string, is a palindrome, then you might use math to do it. Use an algorithm that compares the least significant with the most significant digit, then remove those to digits and continue. If there are an odd number of digits then you don't need to compare that middle digit with anything -- you just need the number of digits / 2 steps.
This code left as an exercise because it is homework.

Putting strings into byte arrays

I created the byte array but don't know if this is the way you put strings of numbers into it. I am new to this byte array and am having trouble knowing if I did it right.
public class AdditionOnlyInt implements BigInt
{
private byte[] data;
public AdditionOnlyInt(String number)
{
data = new byte[number.length()];
number.replace("0","");
int i = 0;
int counter = number.length();
while(i<number.length())
{
data[i] = (byte) number.charAt(counter);
i++;
}
}
}
I have to get rid of the leading zeros then put the number in the array from least significant to most significant that is the reason for the counter variable
Try this..
public class AdditionOnlyInt implements BigInt
{
private byte[] data;
public AdditionOnlyInt(String number)
{
data = new byte[number.length()];
String num=number.replace("0","");
int i = 0;
int counter = number.length()-1;
while(counter>=0)
{
data[i++] = Byte.parseByte(String.valueOf(num.charAt(counter--)));
}
}
}
Well this is a bug:
number.replace("0","");
Firstly, it doesn't do anything: String is immutable, so all String methods return a new string, so you must assign the return value:
number = number.replace("0","");
Secondly, this with remove all zeroes - leading or otherwise. Not what you want. To remove leading zeroes, do this:
number = number.replaceAll("^0+","");
This uses a regex to target just the leading zeroes.
Finally, if you're trying to represent the digits of a number, use int[] and to get the integer value of a character, subtract '0':
int[] data;
data[i] = number.charAt(counter) - '0'; // '0' --> 0, '1' --> 1, '2' --> 2 etc
Make those changes and see if you get closer.

If a String contains a certain letter an exact amount of times

In Java, is there a way of saying .. for example "Does this word contain a Z three times?"
I'm guessing there could be some clever char value?
String word = "pizzaz"
// Check if word contains three z's
boolean b = word.contains("SOME CLEVER CHAR VALUE??");
If possible, could an integer value be used when passing through the "amount of times" i.e.
int letterAmount = 3;
You can use a regex to do that. Following your example:
word.matches(".*(z.*){3}.*")
it returns true if your string has 3 z's.
A somewhat expensive and roundabout way to count single-character matches is as follows:
String s = "pizzaz";
int numMatches = s.length() - s.replaceAll("z", "").length();
When the length of the string with all "z"s removed is subtracted from the length of the original string, you end up with the number of zs in the original string.
Using Apache Commons:
boolean hasThreeZs = StringUtils.countMatches("pizzaz", "z") == 3;
or using Spring's version of StringUtils
boolean hasThreeZs = StringUtils.countOccurrencesOf("pizzaz", "z") == 3;
Depending on the size of the string, another option is to just walk through the string, counting characters:
public static boolean contansCharCount(String s, char targetC, int targetCount) {
char[] sArray = s.toCharArray();
int actualCount = 0;
for(char c : sArray)
actualCount = (c == targetC) ? actualCount + 1 : actualCount;
return (actualCount == targetCount);
}
This takes O(N) time.
String word = "pizzaz";
System.out.println(word.replaceAll("[^z]","").equals("zzz"));

Parsing a string of binary into text/characters

I am probably overlooking something silly, but I've never had to deal with binary in code and thought it'd be a good idea to practice it in an encryption program, for kicks.
Long story short, I'm able to convert a string into binary (in the form of a string), but can't figure out how to do the reverse.
Right now, I have something like this:
public static String bytesToString(String bytes){
int i = bytes.length()/8;
int pos = 0;
String result = "";
for(int j=0; j<i; j++){
String temp = bytes.substring(pos,pos+8);
byte b = (byte) Integer.parseInt(temp);
result = result + Byte.toString(b);
pos++;
}
System.out.println("Result: " + result);
return result;
}
I think the bytes are being parsed as literal numbers. What am I missing?
Edit: To clarify, I will previously have parsed a string of text into bits and written them to a string. I want to split this string into bytes and parse them back into letters. It would take "011010000110010101111001" and return "hey".
How about using Integer.parseInt(text, 2)? As in,
public static int binaryToInt(String binary)
{
return Integer.parseInt(binary, 2);
}
I'm not sure why your binaryToString method both takes and returns a string.
Integer.parseInt(temp) will attempt to read temp as a number and return the corresponding int. For example, Integer.parseInt("123") returns 123
EDIT: Be aware that the binary value of a character or text depends on the encoding you are using. For example "hi" is 0110100001101001 in ASCII but it may not in UTF-16 or UTF-32. And Java encodes characters into UTF-16 characters: see http://download.oracle.com/javase/6/docs/api/java/lang/String.html
(for this reason Java chars are 16-bit unsigned integers).
So your bytesToString method must treat input differently depending on the encoding of the input. Or you may write it specifically for ASCII characters, and maybe rename it to, say, asciiBytesToString
You'd better see:
constructor String(byte[])
http://download.oracle.com/javase/6/docs/api/java/lang/String.html
Integer.parseInt(String s, int radix) http://download.oracle.com/javase/6/docs/api/java/lang/Integer.html
public class BinaryStringToChars {
public static void main(String[] args) {
String bin = "011010000110010101111001";
StringBuilder b = new StringBuilder();
int len = bin.length();
int i = 0;
while (i + 8 <= len) {
char c = convert(bin.substring(i, i+8));
i+=8;
b.append(c);
}
System.out.println(b.toString());
}
private static char convert(String bs) {
return (char)Integer.parseInt(bs, 2);
}
}
You need to advance 8 digits at a time, not digit by digit. Otherwise you are reusing bits. Also, you need to tell Integer.parseInt() what radix you want to use, since parseInt(String val) cannot really detect binary (you want Integer.parseInt(String val, int radix). You also need to choose a character encoding to convert bytes into characters (they are not the same thing!). Assuming ISO-8859-1 is ok:
public static String bytesToString(String bytes){
int i = bytes.length()/8;
int pos = 0;
String result = "";
byte[] buffer = new byte[i];
for(int j=0; j<i; j++){
String temp = bytes.substring(pos,pos+8);
buffer[j] = (byte) Integer.parseInt(temp, 2);
pos+=8;
}
result = new String(buffer, "ISO-8859-1");
System.out.println("Result: " + result);
return result;
}

Categories