How to compare without getting negative value when char is a space - java

Beginner here, We were assigned an assignment to find common consonants in two different strings. This code works perfectly if there is no space in the input but in this assignment we are taking inputs from our user and they are first and last names. If there is no space I get correct value of common characters but when there is a space in between first and last names it will give me an index out of bounds error because the space makes it a negative number. Any help would be nice thank you.
public static int commonCharacters(String string1, String string2) {
final int alphabetLength = 26;
int count = 0;
int[] counting1 = new int[alphabetLength];
int[] counting2 = new int[alphabetLength];
Arrays.fill(counting1, 0);
Arrays.fill(counting2, 0);
for (char c : string1.toCharArray()) {
c = Character.toLowerCase(c);
counting1[c - 'a']++;
}
for (char c : string2.toCharArray()) {
c = Character.toLowerCase(c);
counting2[c - 'a']++;
}
for(int i = 0; i < alphabetLength; i++) {
System.out.printf(String.valueOf(counting1[i]),counting2[i]);
count += Math.min(counting1[i], counting2[i]);
}
return count == 0 ? 1 :count;
}
}

you can trim space at the end of string string1 = string1.trim();

Here is some changes to your code. You just need if statement to check if the character is an alphabet. You do not need Arrays.fill because in Java array values are initialized to zero.
You wrote the assignment is about calculating consonants but your code calculates all common alphabets.
public static int commonCharacters(String string1, String string2) {
final int alphabetLength = 26;
int count = 0;
string1 = string1.toLowerCase();
string2 = string2.toLowerCase();
int[] counting1 = new int[alphabetLength];
int[] counting2 = new int[alphabetLength];
for (char c : string1.toCharArray()) {
if (c < 'a' || c > 'z') {
continue;
}
counting1[c - 'a']++;
}
for (char c : string2.toCharArray()) {
if (c < 'a' || c > 'z') {
continue;
}
counting2[c - 'a']++;
}
for(int i = 0; i < alphabetLength; i++) {
System.out.printf("%c %d %d%n", 'a' + i, counting1[i], counting2[i]);
count += Math.min(counting1[i], counting2[i]);
}
return count;
}

Related

Split a string not knowing its length without using split()

We don't know the string length until the user enters it but the input format is like number-number-number...
The numbers don't have the same number of digits.
Consider this input
10000-20-150-2-12345-2-1-450000-30-2-50
I'm only allowed to use Scanner(System.in) and save this in a string but not allowed to use parseInt or Integer.valueOf or toCharArray or arrays or split function to extract the numbers into an array.
How can I make a split function and use it?
I thought about for loop and charAt(i)=='-' though but I don't know how to get the numbers.
In order to parse a string into a int, you can use :
// Parse string to int without using Integer.parseInt() or Integer.valueOf()
public static int stringToInteger(String str) {
int answer = 0, factor = 1;
for (int i = str.length()-1; i >= 0; i--) {
answer += (str.charAt(i) - '0') * factor; // '0' is to get the ascii code of 0
factor *= 10;
}
return answer;
}
In your processing code :
You can know the result array length with (java 8) :
int[] result = new int[userInput.chars().filter(ch -> ch == '-').count() + 1];
And you just have to iterate over the userInput String using charAt(n) method and stock the char in a StringBuilder until you get a "-", and then call the stringToInteger method to add the int in the array :
StringBuilder sb = new StringBuilder();
int resultIndex = 0;
char c;
for(int i=0 ; i< userInput.length(); i++) {
char c = userInput.charAt(i);
if(c == '-') {
result[resultIndex++] = stringToInteger(sb.toString());
sb.setLength(0); // Empty the stringBuilder
}
else {
sb.append(c); // Add char in the stringBuilder
}
}
Here's an example using nothing fancy, just String.charAt():
String input = "10000-20-150-2-12345-2-1-450000-30-2-50";
String curValue = "";
for(int i=0; i<input.length(); i++) {
char c = input.charAt(i);
if (!(c == '-')) {
curValue = curValue + c;
}
else {
// ... do something with curValue ...
System.out.println(curValue);
// reset curValue
curValue = "";
}
}
if (curValue.length() > 0) {
// ... do something with curValue ...
System.out.println(curValue);
}
We just iterate over the characters and accumulate them in "curValue" until you hit a dash. Then you process what is in "curValue" and reset it back to a blank string. After iterating all characters you need to process the last value left in "curValue".

The value of length when replacing space with %20

I am working on a problem of replacing spaces with %20 from Cracking the Coding Interview 5th edition:
Write a method to replace all spaces in a string with '%20'. You may assume that the string has sufficient space at the end of the string to hold the additional characters, and that you are given the "true" length of the string. (Note: if implementing in Java, please use a character array so that you can perform this operation in place)
The algorithm I have is:
public static void replaceSpaces(String input, int length) {
char[] str = input.toCharArray();
int spaceCount = 0;
for(int i = length - 1; i >= 0; i--){
if(str[i] == ' ') {
spaceCount++;
}
}
int newLength = length + spaceCount * 2;
str[newLength] = '\0';
for(int i = length - 1; i >= 0; i--) {
if(str[i] == ' ') {
str[newLength - 1] = '0';
str[newLength - 2] = '2';
str[newLength - 3] = '%';
newLength = newLength - 3;
System.out.println(str);
} else {
str[newLength - 1] = str[i];
newLength = newLength - 1;
System.out.println(str);
}
}
}
Printing out each step of the function, here are my outputs:
Mr John Smith h
Mr John Smith th
Mr John Smith ith
Mr John Smithmith
Mr John SmitSmith
Mr John S%20Smith
Mr John n%20Smith
Mr Johnhn%20Smith
Mr Johohn%20Smith
Mr JoJohn%20Smith
Mr%20John%20Smith
Mr%20John%20Smith
Mr%20John%20Smith
I have two questions:
We know the new length of the string is 17. What I do not understand is, why we need to have [newLength - 1] instead of [newLength]. We are interested in replacing the current index, no? Or is it because the new length is 17, but when converted to indices, it's actually 16 (0th index).
What is the purpose of: str[newLength] = '\0';
We don't all have that book, but from a pending edit, I see that the exact question is:
Write a method to replace all spaces in a string with '%20'. You may assume that the string has sufficient space at the end of the string to hold the additional characters, and that you are given the "true" length of the string. (Note: if implementing in Java, please use a character array so that you can perform this operation in place)
From Cracking the Coding Interview 5th edition
So, it says that your input argument should be a char[].
Since you're changing the length of the text, your method would need to return the new length.
Question 1:
We know the new length of the string is 17. What I do not understand is, why we need to have [newLength - 1] instead of [newLength]. We are interested in replacing the current index, no? Or is it because the new length is 17, but when converted to indices, it's actually 16 (0th index).
You answered it yourself. With a length of 17, the indices are 0 to 16. If the array is only 17 long, accessing index 17 with throw an IndexOutOfBoundsException.
Question 2:
What is the purpose of: str[newLength] = '\0';
None whatsoever. It's is invalid and has no purpose in Java. Remove it.
Java Strings have a length(). In C, strings are zero-terminated, but not in Java.
To test the code, try running it with this:
char[] buffer = { 'M','r',' ','J','o','h','n',' ','S','m','i','t','h','*','*','*','*' };
int inLen = 13;
System.out.println("buffer: '" + new String(buffer) + "'");
System.out.println("inLen : " + inLen);
System.out.println("input : '" + new String(buffer, 0, inLen) + "'");
int outLen = replaceSpaces(buffer, inLen);
System.out.println("outLen: " + outLen);
System.out.println("result: '" + new String(buffer, 0, outLen) + "'");
Output should be:
buffer: 'Mr John Smith****'
inLen : 13
input : 'Mr John Smith'
outLen: 17
result: 'Mr%20John%20Smith'
Accessing input[17] in the method would throw IndexOutOfBoundsException.
Here is one possible implementation based on the shown code, that follows the quoted text, and stop processing once all spaces are replaced.
public static int replaceSpaces(char[] str, int length) {
int spaceCount = 0;
for (int i = length - 1; i >= 0; i--)
if (str[i] == ' ')
spaceCount++;
int shift = spaceCount * 2;
int newLength = length + shift;
for (int i = newLength - 1; shift > 0; i--) {
char c = str[i - shift];
if (c != ' ') {
str[i] = c;
} else {
str[i] = '0';
str[--i] = '2';
str[--i] = '%';
shift -= 2;
}
}
return newLength;
}
This produces the expected output from the test code above.
Code posted below works good. Cheers.
Sample Output
package StringAndArray;
public class Question_Four_Replace_Spaces {
public static void main(String[] args) {
String string = "Mr Shubham Dilip Yeole";
char[] array = string.toCharArray();
System.out.println("\n\nInput : " +string);
System.out.println("\n\nResult: "+method_1(array,string.length()));
method_1(array,string.length());
}
private static String method_1(char[] array, int length) {
int spaceCount = 0;
for(int i=0; i<array.length; i++){
if(array[i]==' ') spaceCount++;
}
int count = 0;
int newLength = length + spaceCount*2;
char[] newArray = new char[newLength];
for(int i= 0; i<array.length; i++){
if(array[i]==' '){
newArray[count++] = '%';
newArray[count++] = '2';
newArray[count++] = '0';
}else{
newArray[count] = array[i];
count++;
}
}
String newString1 = new String(newArray);
return newString1;
}
}
I believe that your direct questions have been answered in the comments, so here instead I will focus on issues with the method as written.
Ignoring the fact that this functionality already exists in the base String class (and many other 3rd party string utility classes), we can still write a basic string replacement function. The function as written in the question does not appear to be written for Java, and does not return any value, which since Strings are immutable means that the function cannot possibly be fulfilling its name.
Instead, we need to create a new array which we copy the existing characters to while replacing any spaces we encounter with %20. We then return this array as a new String. Conveniently, Java has a class which encapsulates a variable size array of characters that we can use to assemble our new String called StringBuilder.
So a simpler and working (but not optimized) replacement function in Java may look like:
public static String replaceSpaces(String input)
{
if (input == null) return null;
// New string builder with some padding to account for replacements...
// Padding was chosen pretty arbitrarily, there are certainly better values.
StringBuilder builder = new StringBuilder(input.length() + 128);
for (int i = 0; i < input.length(); i++)
{
char c = input.chatAt(i);
if (c == ' ') {
builder.append("%20");
} else {
builder.append(c);
}
}
return builder.toString();
}
It may be more optimal to convert the entire String to a char[] at the beginning, and iterate over the array instead of using String.charAt(i). And we could probably choose a more appropriate padding for the StringBuilder by multiplying the length of the existing string by some constant based on the expected number of spaces. For very large strings it could even make sense to first count the number of spaces before declaring our array, but those optimizations are left as an exercise for the reader.
#Test public void replaceTest() {
String s = "Mr John Smith ";
char[] chars = s.toCharArray();
int length = 13;
char[] chars1 = subString(chars, length);
//actualString = actualString.replace(" ", "%20");
Assert.assertEquals(replace(chars1, "%20"), "Mr%20John%20Smith");
}
private char[] subString(char[] chars, int length) {
char[] newChar = new char[length];
for (int i = 0; i < length; i++) {
newChar[i] = chars[i];
}
return newChar;
}
private String replace(char[] chars, String s) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == ' ') {
builder.append(s);
} else {
builder.append(chars[i]);
}
}
return builder.toString();
}
public static String urlify(String s1, int truelength) {
int countspaces = 0;
char[] charobj = s1.toCharArray();
for (int i = truelength - 1; i < charobj.length; i++) {
if (charobj[i] == ' ') {
countspaces++;
}
}
for (int i = truelength - 1; i >= 0; i--) {
if (charobj[i] == ' ' && countspaces != 0) {
for (int j = truelength - 1; j > i; j--) {
char temp = charobj[j];
charobj[j + 2] = temp;
}
countspaces = countspaces - 2;
charobj[i] = '%';
charobj[i + 1] = '2';
charobj[i + 2] = '0';
truelength = truelength + 2;
}
}
return String.valueOf(charobj);
}

Counting number of times a letter occurs in a string without using libraries

My professor says I can't use libraries and stuff. I have my code with libraries:
String phrase = keyboard.nextLine(); //Input.
int addr = phrase.length();
Map<Character, Integer> numChars = new HashMap<Character, Integer>(Math.min(addr, 26)); //there are 26 character in our alphabet. It makes a map and maps our the characters.
for (int i = 0; i < addr; ++i)//this area reads the string then, tells how many times each character appeared. Loops for each chracter.
{
char charAt = phrase.charAt(i);
if (!numChars.containsKey(charAt))
{
numChars.put(charAt, 1);
}
else if (numChars.containsKey(charAt))
{
numChars.put(charAt, 0);
}
else
{
numChars.put(charAt, numChars.get(charAt) + 1);
}
}
System.out.println(phrase);//outputs phrase written by user.
System.out.println(numChars);//outputs results of the code above
// this code reads which one appeared the most.
int FreqChar = 0;
char frequentCh = ' ';
for (int f = 0; f < phrase.length(); f++)
{
char poop = phrase.charAt(f);
int banana = 0;
for (int j = phrase.indexOf(poop); j != -1; j = phrase.indexOf(poop, j + 1))
{
frequentCh++;
}
if (banana > FreqChar)
{
FreqChar = banana;*/
Here is my program without the libraries so far. I need help translating this into arrays.
import java.util.*;
public class LetCount
{
public static final int NUMCHARS = 26; //26 chars in alphabet.
// int addr(char ch) returns the equivalent integer address for the letter
// given in ch, 'A' returns 1, 'Z' returns 26 and all other letters return
// their corresponding position as well. felt this is important.
public static int addr(char ch)
{
return (int) ch - (int) 'A' + 1;
}
// Required method definitions for (1) analyzing each character in an input
// line to update the appropriate count; (2) determining most frequent letter;
// (3) determining least frequent letter; and (4) printing final results
// should be defined here.
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in); // for reading input
int[] count = new int [NUMCHARS]; // count of characters
String phrase = keyboard.nextLine(); //Input.
int addr = phrase.length();
for(char ch = 'A'; ch <= 'Z'; ch++)
{
}
}
This is easier to put here than in comments, but it's not really an answer :)
You've got a great start - rather than going through the letters and finding matches, go through the string and increment your letter counter each time you encounter a letter (yeah, that sounds weird in my head too).
Convert the string to lower or upper case first, you only need to count the letter, not whether it's lower or upper based upon your existing code.
If you just have to count all the alphabets in a given String and store it in an array, try this:
String str = phrase.toUpperCase();
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
int charPositionInArray = c - 'A';
if(charPositionInArray < 26){
count[charPositionInArray] += 1;
}
}
Also, the index of an array starts from 0, so I assume you want the count for 'A' to be stored in count[0], i.e., the first position in the array.
Also, this code does nothing for any character that is not an alphabet.

I'm curious how i would grab a char that is the smallest/biggest out of the rest in said string without using ARRAYS

I'm just having a hard time grasping this concept.
each char has a different ASCII value, so how do i grab the lowest value or the highest value?
and if i passed an empty string to my method for all of this min() would just get thrown an error or would it return a 0?
i wrote a test driver that should pass if my min method returns w as the minimum, which is just a stub method right now, character in that string.
final String PASS = "Pass";
final String FAIL = "Fail";
L05A lab5 = new L05A();
int testNum = 1;
String tst = ""; // test empty string
String result = FAIL;
System.out.println("\nTesting min\n");
tst = "";
char ch = lab5.min(tst);
result = (ch == '!') ? PASS : FAIL;
System.out.println(testNum + ": " + result);
++testNum;
tst = "zyxw"; //would return w?
ch = lab5.min(tst);
result = (ch == 'w') ? PASS : FAIL;
System.out.println(testNum + ": " + result);
++testNum;
So how would i scan that string i pass to return the smallest char?
At first i thought i could use str.charAt(0); but silly me, that just returns the first index of the string, so i'm very confused! Any help would be great to develop this min method
I SHOULD SPECIFY THAT WE ARE NOT USING ANY FORM OF ARRAYS[] ON THIS ASSIGNMENT
UNFORTUNATELY.. :(
It's pretty simple:
Convert the string to a char array using String.toCharArray
Convert the array to a Collection<Character>
Pass the collection to Collections.min and max from java.util.Collections
For example:
String test = "test";
List<Character> strArr = new ArrayList<Character>(test.length());
for (char c : test.toCharArray()) strArr.add(c);
System.out.println(Collections.min(strArr)); // prints "e"
EDIT Ok, so now you say you can't use Arrays, so you just do this instead:
String test = "test";
char[] chars = test.toCharArray();
char max = Character.MIN_VALUE;
char min = Character.MAX_VALUE;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
max = max > c ? max : c;
min = min < c ? min : c;
}
System.out.println(min);
And, finally, if you can't use an array (like char[]) then you just drop the toCharArray call, and start the loop like this:
for (int i = 0; i < test.length(); i++) {
char c = test.charAt(i);
get char array out of string
iterate over it
define temp int variable assign to 0
compare ASCII of char to temp var and assign temp var to ascii if temp var is smaller/bigger(based on min max value you need from that function)
once the loop is over, you have what you want in that temp var
You should sort the array first:
Arrays.sort(arr);
Then your minimum value will be its first element:
int minimum = arr[0];
Do note that Arrays.sort does sorting in-place and returns nothing.
I expect there is a utility class which will do this for you, but what you could do is call toCharArray on the string, iterate over the array it returns and look for the smallest char (char is effectively a number so comparisons like < > <= >= etc will work on it)
edit:
String foo = "ksbvs";
final char[] chars = foo.toCharArray();
// create a variable to bung the smallest char in
// iterate over the array chars
// compare the current char to the smallest char you have seen so far, update if it's smaller
public class TestCharASCIIValue {
public static void main(String[] args) {
String slogan = "Programming Java Makes me go nutts"; // The String under test
int maxASCII = 0; // As minimum value for a character in ASCII is 0.
int minACSII = 255; // As maximum value for a character in ASCII is 255
int stringLength = slogan.length();
for(int i =0; i < stringLength; i++) {
int tempASCII = slogan.codePointAt(i);
if(tempASCII > maxASCII)
maxASCII = tempASCII;
else if (tempASCII < minACSII)
minACSII = tempASCII;
}
System.out.println("Max : " + maxASCII + " MIN : " + minACSII);
char maxChar = (char)maxASCII;
char minChar = (char) minACSII;
System.out.println("MaxChar : "+maxChar +"\t MinChar : " + minChar);
}
}
OUTPUT :
Max : 118 MIN : 32
MaxChar : v MinChar : (blank space)
EDIT : As per your Query, If you want to test only for max or min valued char then you can use this.
public class TestCharASCIIValue {
public static void main(String[] args) {
String slogan = "Programming Java Makes me go nutts";
char maxChar = (char)getMaxChar(slogan);
char minChar = (char)getMinChar(slogan);
System.out.println("MaxChar : "+maxChar +"\t MinChar : " + minChar);
}
private static int getMaxChar(String testString) {
int maxASCII = 0;
int stringLength = testString.length();
if(stringLength == 0) {
return -1;
}
for(int i =0; i < stringLength; i++) {
int tempASCII = testString.codePointAt(i);
if(tempASCII > maxASCII)
maxASCII = tempASCII;
}
return maxASCII;
}
private static int getMinChar(String testString) {
int minASCII = 255;
int stringLength = testString.length();
if(stringLength == 0) {
return -1;
}
for(int i =0; i < stringLength; i++) {
int tempASCII = testString.codePointAt(i);
if(tempASCII < minASCII)
minASCII = tempASCII;
}
return minASCII;
}
}

Java - Counting how many characters show up in another string

I am comparing two strings, in Java, to see how many characters from the first string show up in the second string. The following is some expectations:
matchingChars("AC", "BA") → 1
matchingChars("ABBA", "B") → 2
matchingChars("B", "ABBA") → 1
My approach is as follows:
public int matchingChars(String str1, String str2) {
int count = 0;
for (int a = 0; a < str1.length(); a++)
{
for (int b = 0; b < str2.length(); b++)
{ char str1Char = str1.charAt(a);
char str2Char = str2.charAt(b);
if (str1Char == str2Char)
{ count++;
str1 = str1.replace(str1Char, '0');
}
}
}
return count;
}
I know my approach is not the best, but I think it should do it. However, for
matchingChars("ABBA", "B") → 2
My code yields "1" instead of "2". Does anyone have any suggestion or advice? Thank you very much.
Assuming that comparing "AABBB" with "AAAABBBCCC" should return 15 (2*3 + 3*3 + 0*3) then:
For each string make a Map from the character of the string to the count of characters.
Compute the intersection of the keysets for the two maps.
For each element in the keyset accumulate the product of the values. Print the result.
This is linear in the size of the two strings.
Is it ok to supply working code on homework problems?
public long testStringCount() {
String a = "AABBBCCC";
String b = "AAABBBDDDDD";
Map<Character,Integer> aMap = mapIt(a);
Map<Character,Integer> bMap = mapIt(b);
Set<Character> chars = Sets.newHashSet(aMap.keySet());
chars.addAll(bMap.keySet());
long result = 0;
for (Character c : chars) {
Integer ac = aMap.get(c);
Integer bc = bMap.get(c);
if (null != ac && null != bc) {
result += ac*bc;
}
}
return result;
}
private Map<Character, Integer> mapIt(String a) {
Map<Character,Integer> result = Maps.newHashMap();
for (int i = 0; i < a.length(); i++) {
Character c = a.charAt(i);
Integer x = result.get(c);
if (null == x) {
x = 0;
}
x++;
result.put(c, x);
}
return result;
}
Clearly you have to make sure you only count unique characters from string 1. You're double-counting B because you're counting B's twice, once for each occurrence in string 1.
Well your code is only showing 1 because of this line:
str1 = str1.replace(str1Char, '0');
That's turning "ABBA" into "A00A" - so the second B doesn't get seen.
Perhaps you should turn the second string into a HashSet<Character> instead... then you could just use something like:
int count = 0;
for (int i = 0; i < str1.length; i++)
{
if (otherSet.contains(str1.charAt(i))
{
count++;
}
}
It's not clear what result you want to get from "ABBA" / "CBCB" - if it's 2 (because there are 2 Bs) then the above approach will work. If it's 4 (because each of the 2 Bs in the first string matches 2 Bs in the second string) then all you need to do is get rid of your replace call.
EDIT: With the clarifications, it sounds like you could just do this:
for (int a = 0; a < str1.length(); a++)
{
for (int b = 0; b < str2.length(); b++)
{
if (str1.charAt(a) == str2.charAt(b))
{
count++;
// Terminate the inner loop which is iterating over str2,
// and move on to the next character in str1
break;
}
}
}
Your solution works, but is quadratic. If all characters are below 256, then you can do something like this:
int matching(String s1, String s2) {
int[] count1 = frequencies(s1);
int[] count2 = frequencies(s2);
sum = 0;
for(int i = 0; i< 256; i++) {
sum += count1[i]*count2[i] != 0 ? Math.max(count1[i], count2[i]) : 0;
}
return sum;
}
int[] frequencies(String s) {
int[] ret = new int[256];
for(char c : s) {
int[c]+=1;
}
}
Otherwise, you'll need a multiset.

Categories

Resources