Java replacing character in string from the back - java

I was having some problem when trying to replace certain character with ASCII character in the string.
So let's say I got this string "CCCCCCC". After perform some method, it will become "CCCCCCa". Then the second time I will be checking the second last character and perform some method to get "CCCCCca". Then third time will be checking the third last character and so on and repeat for 7 times.
for (int i = 0; i < 256; i++){
plaintext = plaintext .substring(0,plaintext .length() - counter) + Character.toString((char)i);
}
I used a for loop to loop through all 256 ASCII characters. The counter will be incremented after I performed some decryption. So basically for the first time, it will be -1 (which is the last character) then second time will be -2 (which is the second last character) and so on for the substring.
Let me put it this way, for the first time, I want all 256 ASCII appended to the end of my 7 bytes string. Then after I perform some decryption, the string will become CCCCCCCa. So when I loop for the second time, I will replace my second last character in the string with all 256 ASCII. And after some decryption, the string will become CCCCCC(a. Then I loop until there is no more C in the string.
However, I am getting String index out of range: -1 error message. Is there any other way to replace the last character of a string with decreased size by 1 after each for loop?
Thanks in advance.

First, don't forget the rest.
plaintext = plaintext.substring(0,plaintext .length() - counter)
+ Character.toString((char)i)
+ plaintext.substring(plaintext .length() - counter + 1) ; //TO add the rest
Then, you need to check if counter is not larger than plaintext.length()
for (int i = 0; i < 256 && counter <= plaintext.length(); i++){
I would suggest to use String.toCharArray() and iterate from the end, this would be much easier.
char[] array = plaintext.toCharArray();
for(int i = array.length - 1, char c = 0; i >= 0; --i){
array[i] = c++;
}
Example of both code: (using 'a' as a first character instead of 0)
public static void main(String[] args) {
String plaintext = "CCCCCC";
for (int i = 'a', counter = 1; i < 256 && counter <= plaintext.length(); i++, ++counter) {
plaintext = plaintext.substring(0, plaintext.length() - counter)
+ Character.toString((char) i)
+ plaintext.substring(plaintext.length() - counter + 1);
}
System.out.println(plaintext);
plaintext = "CCCCCC"; //fedcba
char[] array = plaintext.toCharArray();
char c = 'a';
for (int i = array.length - 1; i >= 0; --i) {
array[i] = c++;
}
System.out.println(new String(array)); //fedcba
}
fedcba
fedcba

Related

Hash only LETTERS using Horner's method in java

I understand how Horner's method in hashing works but I am having issues hashing a string that may contain non-alphabetical characters and I want to hash just the alphabetical characters. I want to ignore non-alphabetical characters and hash just alphabetic characters
Here's is the code I have done for this but doesn't work entirely
private int hash(String key){
int constant = 27;
int lastHashValue = key.charAt(0); //convert the first char to ascii first
//because for each character we multiply the constant by the
// hash code by the constant.
for(int i = 1; i < key.length(); i++){
if( Character.isLetter(key.charAt(i)) ){ //checks if it is a letter
lastHashValue = (key.charAt(i) + (constant * lastHashValue) ) % array.length;
}
}
return lastHashValue;
}
Here is the issue I have: What if the first character is a non-alphabetic character. How do I ignore it? (knowing that we need to get the first character hash code to move to the next).
You can initialize lastHashValue to 0 and start looping at index 0.
int lastHashValue = 0;
for(int i = 0; i < key.length(); i++){
if( Character.isLetter(key.charAt(i)) ){ //checks if it is a letter
lastHashValue = (key.charAt(i) + (constant * lastHashValue) ) % array.length;
}
}

Delete all matching pairs of a character from a string

I'm trying to make a code that deletes the repeated characters. For example - if we have a string "aabacdc", we want to make it as "abd". If the character exists twice in the string, then we delete both characters as we did in the above example. The 'a' occurs 3 times in our string, so we just deleted the 2 a and left 1 remaining.
What I'm trying to do in this code is use two nested for loops - first for loop to compare the first character with the other characters. If the character has a duplicate in the string, then just delete both the characters. How can I fix this code?
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String str2 = input.nextLine();
StringBuilder str = new StringBuilder(str2);
for (int k = 0; k < str.length() - 1; k++) {
for (int i = 1; i < str.length() - 1; i++) {
if (str.charAt(k) == str.charAt(i)) {
str.deleteCharAt(k);
str.deleteCharAt(i);
}
}
}
System.out.println(str);
}
My interpretation of what you're trying to do based on your expected output is that you want to remove characters from the string 1 pair at a time. So if there is an odd number of a character in the string, 1 should remain, and if there's an even number 0 should remain.
Any time you're removing elements from a structure while you're iterating by index, you need to loop over the structure backwards, so that the index values don't shift as you delete elements. This means you should only delete elements which the outer loop is currently at, or has already seen (i.e. only delete elements at indexes >= i).
Scanner input = new Scanner(System.in);
String str = input.nextLine();
StringBuilder sb = new StringBuilder(str);
for (int i = sb.length() - 2; i >= 0; i--) {
for (int j = i + 1; j < sb.length(); j++) {
if (sb.charAt(i) == sb.charAt(j)) {
sb.deleteCharAt(j);
sb.deleteCharAt(i);
break;
}
}
}
System.out.println(sb);
Ideone Demo

Vowel check - array out of bounds error

I'm trying to write a program which accepts a word in lowercase, converts it into uppercase and changes the vowels in the word to the next alphabet. So far, I've done this:
import java.util.*;
class prg11
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
System.out.println("Enter a word in lowercase.");
String word = sc.next();
word = word.toUpperCase();
int length = word.length();
char ch[] = new char[length+1];
for (int i = 0; i<=length; i++)
{
ch[i] = word.charAt(i);
if("aeiou".indexOf(ch[i]) == 0)
{
ch[i]+=1;
}
}
String str = new String(ch);
System.out.println(str);
}
}
The code compiles fine. But, when I run the program and enter a word, say 'hey', the word is printed in uppercase only. The vowels in it (in this case, 'e'), do not get changed to the next alphabet.
How do I resolve this? TIA.
Need to change three places, according to the code in the question.
word = word.toUpperCase();
int length = word.length();
// yours: char ch[] = new char[length + 1];
// resulting array needs to be as same length as the original word
// if not, there will be array index out of bound issues
char ch[] = new char[length];
// yours: for (int i = 0; i<=length; i++)
// need to go through valid indexes of the array - 0 to length-1
for (int i = 0; i < length; i++) {
ch[i] = word.charAt(i);
// yours: if ("aeiou".indexOf(ch[i]) == 0) {
// two problems when used like that
// 1. indexOf() methods are all case-sensitive
// since you've uppercased your word, need to use AEIOU
// 2. indexOf() returns the index of the given character
// which would be >= 0 when that character exist inside the string
// or -1 if it does not exist
// so need to see if the returned value represents any valid index, not just 0
if ("AEIOU".indexOf(ch[i]) >= 0) {
ch[i] += 1;
}
}
Here's a little concise version. Note the changes I've done.
String word = sc.next().toUpperCase();
char ch[] = word.toCharArray();
for (int i = 0; i < ch.length; i++) {
if ("AEIOU".indexOf(ch[i]) >= 0) {
ch[i] += 1;
}
}
Java doc of indexOf().
public int indexOf(int ch)
Returns the index within this string of the first occurrence of the specified character.
If a character with value ch occurs in the character sequence represented by this String object,
then the index (in Unicode code units) of the first such occurrence is returned.
For values of ch in the range from 0 to 0xFFFF (inclusive), this is the smallest value k such that:
this.charAt(k) == ch
is true. For other values of ch, it is the smallest value k such that:
this.codePointAt(k) == ch
is true. In either case, if no such character occurs in this string, then -1 is returned.
Parameters:
ch - a character (Unicode code point).
Returns:
the index of the first occurrence of the character in the character sequence represented by this object,
or -1 if the character does not occur.
I think this should do it, let me know if it doesn't
public class prg11 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter a word.");
String word = sc.next();
sc.close();
word = word.toUpperCase();
int length = word.length();
char ch[] = new char[length+1];
for (int i = 0; i<length; i++) {
ch[i] = word.charAt(i);
if("AEIOU".indexOf(ch[i]) > -1) {
ch[i]+=1;
}
}
String str = new String(ch);
System.out.println(str);
}
}
Let me know if it works.
Happy coding ;) -Charlie
Use:
for (int i = 0; i<length; i++)
instead as the last index is length-1.
use for (int i = 0; i<=length-1; i++) instead of for (int i = 0; i<=length; i++) and if("AEIOU".indexOf(ch[i]) != -1) instead of if("aeiou".indexOf(ch[i]) == 0)
reason
1.array index starts from 0 that's why length-1
2. As you already made your string in upper case so check condition on "AEIOU"
3. every non-vowel character will return -1 so use if("AEIOU".indexOf(ch[i]) != -1)
"aeiou".indexOf(ch[i]) == 0 will only match 'a' characters (since that is the character at index 0). You should be looking for any index that is greater than -1. Additionally, since you've already converted the string to uppercase, you should be checking against "AEIOU" instead of "aeiou".

Given a string S and a string T, count the number of distinct subsequences of T in S

Hi All: can someone explain to me how this algorithm works? I fail to understand the mechanism. Thanks.
Problem: Given a string S and a string T, count the number of distinct subsequences of T in S.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
Here is an example:
S = "rabbbit", T = "rabbit"
Return 3.
Solution:
public int numDistincts(String S, String T)
{
int[][] table = new int[S.length() + 1][T.length() + 1];
for (int i = 0; i < S.length(); i++)
table[i][0] = 1;
for (int i = 1; i <= S.length(); i++) {
for (int j = 1; j <= T.length(); j++) {
if (S.charAt(i - 1) == T.charAt(j - 1)) {
table[i][j] += table[i - 1][j] + table[i - 1][j - 1];
} else {
table[i][j] += table[i - 1][j];
}
}
}
return table[S.length()][T.length()];
}
The above DP solution using O(m*n) space, where m is the length of S, and n is the length of T. Below is the Solution that has only O(n) space.
public class Solution {
public int numDistinct(String s, String t) {
if(s == null || t == null || t.length() == 0) return 0;
int[] dp = new int[t.length()];
for(int i = 0; i<s.length(); i++){
char c = s.charAt(i);
for(int j=dp.length-1; j>=0; j--){
if(c == t.charAt(j)){
dp[j] = dp[j] + (j!=0?dp[j-1]: 1);
}
}
}
return dp[t.length()-1];
}
}
From this page.
First of all, note that += can just as well be =, because each combination of [i][j] is visited only once - in fact = would be better because it wouldn't have to use the fact that in Java ints are initialised to 0.
This is a dynamic programming solution. table[i][j] ends up storing the answer when you consider only the first i characters of S and the first i characters of T.
The first loop says that if T is the zero length string the only subsequence of T in S is the zero length subsequence - there is one of these.
The second loop compares the ith character of S with the jth character of T at a time when these are both the last character of the short strings being dealt with. If these don't match the only subsequences of T in S are also sub-sequences of S with the last non-matching character chopped off, and we have already calculated these in table[i-1][j]. If they do match then there are extra subsequences that match this last character. If you take that last character off the subsequence then you find a subsequence from this segment of T with one character lopped off that matches one from S with one character lopped off, and you have already counted them in table[i-1][j-1] - so for a match the answer is table[i-1][j] + table[i-1][j-1].
At the end, of course, you find that you have calculated the answer for the full length of S and T in table[s.length][t.length]

Why does Java give runtime error when depositing data into an array using a "for" loop?

I wanted to write code that reads a word stored as a String variable. The program should loop through each character in the word and update an array that contains the frequency with which each letter occurs.
The letters in the alphabet (A to Z) can be referenced by "freq[1]" to "freq[26]".
However, when I try to run my program, I get an error that says:
java.lang.ArrayIndexOutOfBoundsException: -64
at ReadWords.main(ReadWords.java:17)
Here is the code I used:
public class ReadWords
{
public static void main (String[] args)
{
String line = "This is a line of text. That's not exciting";
line = line.toLowerCase();
int[] freq = new int[27];
for (int i = 0; i < line.length(); i++)
{
int letter = line.charAt(i) - 96;
freq[letter]++;
}
for (int i = 0; i < freq.length - 1; i++)
{
System.out.println(freq[i]); //prints all elements in the array
}
}
}
Because you are reading space characters (ASCII 32) with your letters. Its value is 32, and when you subtract 96, you get -64, obviously not a valid array index.
I don't think you want to count spaces, so skip them; don't process them.
You'll want to skip other punctuation characters as well, with ' being ASCII value 39, and . being ASCII value 46.
Your error
Like rgettman said, you're including the spaces in your analysis of the frequence. Simply add an if-statement.
for (int i = 0; i < line.length(); i++)
{
int letter = line.charAt(i) - 96;
if (letter > 0 && letter < 27) freq[letter]++;
}
if (letter > 0 && letter < 27) makes sure that the char that you're at in your String is in fact a letter from a - z
Helpful points
Also, in your second for-loop, it won't display the frequency of 'z', and it will display the frequency as position 0 in the array, which holds nothing (position 1 is 'a').
You need to change this:
for (int i = 0; i < freq.length - 1; i++)
to this:
for (int i = 1; i < freq.length; i++)
This way it includes element 27, which is freq[26], which is where the 'z' frequency is. It also will ignore element 1, which is freq[0]. Try it. Or you could change the size of your freq array to 26, and subtract 97 from the line.charAt(i) and then change the if-statement I gave you in your first for-loop to
if (letter > -1 && letter < 26). And then use for (int i = 0; i < freq.length; i++).
Display the letter with the frequency
Use this line of code to display the char corresponding to the frequency as well:
System.out.println((char)(i + 96) + ": " + freq[i]);
Or if you did what I said where you changed the size of the freq array and made the frequency of 'a' at position 0, use this line:
System.out.println((char)(i + 97) + ": " + freq[i]);
I guess the easiest way to do this would be to only check for lower case alphabets (97-122 ASCII values).
Below is the modified version of your code.
public static void main(String[] args) {
String line = "This is a line of text. That's not exciting";
line = line.toLowerCase();
int[] freq = new int[27];
for (int i = 0; i < line.length(); i++) {
/*Only use lower case alphabets ranging from 97 to 122.
The below if should omit all other unwanted characters from your string.*/
if (line.charAt(i) > 96
&& line.charAt(i) < 123) {
/* Subtract by 97 to start your array from 0 for a(value 97)*/
int letter = line.charAt(i) - 97;
freq[letter]++;
}
}
for (int i = 0; i < freq.length - 1; i++) {
System.out.println((char)(i+97) + " : " + freq[i]); // prints all elements in the array
}
}

Categories