Hash only LETTERS using Horner's method in java - 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;
}
}

Related

Not able to understand the code to Count Duplicates in a string?

This program finds the count of duplicates in a string.
Example 1:
Input:
"abbdde"
Output:
2
Explanation:
"b" and "d" are the two duplicates.
Example 2:
Input:
"eefggghii22"
Output:
3
Explanation:
duplicates are "e", "g", and "2".
Help me with this code.
public class CountingDuplicates {
public static int duplicateCount(String str1) {
// Write your code here
int c = 0;
str1 = str1.toLowerCase();
final int MAX_CHARS = 256;
int ctr[] = new int[MAX_CHARS];
countCharacters(str1, ctr);
for (int i = 0; i < MAX_CHARS; i++) {
if(ctr[i] > 1) {
// System.out.printf("%c appears %d times\n", i, ctr[i]);
c = ctr[i];
}
}
return c;
}
static void countCharacters(String str1, int[] ctr)
{
for (int i = 0; i < str1.length(); i++)
ctr[str1.charAt(i)]++;
}
}
You need to maintain a count and if the value of that character exceeds 1, you need to increment the count.
Return that count to know the count of duplicates.
Added comments to understand the code better.
public class CountingDuplicates {
public static int duplicateCount(String str1) {
// Initialised integer to count the duplicates
int count = 0;
// Converting a string to lowercase to count lowerCase and Uppercase as duplicates
str1 = str1.toLowerCase();
// According to ASCII, the Maximum number of characters is 256,
// So, initialized an array of size 256 to maintain the count of those characters.
final int MAX_CHARS = 256;
int ctr[] = new int[MAX_CHARS];
countCharacters(str1, ctr);
for (int i = 0; i < MAX_CHARS; i++) {
if(ctr[i] > 1) {
// System.out.printf("%c appears %d times\n", i, ctr[i]);
count = count + 1;
}
}
return count;
}
static void countCharacters(String str1, int[] ctr)
{
for (int i = 0; i < str1.length(); i++)
ctr[str1.charAt(i)]++;
}
}
In short it is counting the number of characters appearing in the String str and saving it in ctr array.
How? ctr is the array that has a length of 256. So it can have 256 values (0-255 indexed). str1 is the string that contains the String. charAt(i) method returns the character at index i. Because String acts like an array where you can access each char a index values of an array.
Now assuming your input will always ASCII characters, each ASCII chars contain a value of 0-255 (i.e. ASCII value 'a' is 97). ++ after any variable means adding 1 to that. i.e.c++ means c = c+1
Now coming to the loop, ctr[str1.charAt(i)]++;, you can see the loops starts from 0 and ends at the length of the String str where 0 is the first value str. So if value of 0 indexed value (first value) of the String str is a, str.charAt(0) would return 97(well actually it will return 'a' but java takes the ASCII value). so the line actually is (for 0 th index) ctr[97]++; so it's incrementing the value of the 97th index (which is initially 0) by 1. So now the value is 1.
Like this way it will only increment the index values that matches with the ASCII values of the character in the String, thus counting the amount of time the characters occur.

License Key Formatting code Challenge Leetcode

This is the challenge:
You are given a license key represented as a string S which consists only alphanumeric character and dashes. The string is separated into N+1 groups by N dashes. Given a number K, we would want to reformat the strings such that each group contains exactly K characters, except for the first group which could be shorter than K, but still must contain at least one character. Furthermore, there must be a dash inserted between two groups and all lowercase letters should be converted to uppercase. Given a non-empty string S and a number K, format the string according to the rules described above.
Example 1:
Input: S = "5F3Z-2e-9-w", K = 4 Output: "5F3Z-2E9W" Explanation: The string S has been split into two parts, each part has 4 characters.
Note that the two extra dashes are not needed and can be removed.
Example 2:
Input: S = "2-5g-3-J", K = 2 Output: "2-5G-3J" Explanation: The string S has been split into three parts, each part has 2 characters except the first part as it could be shorter as mentioned above.
Note:
1) The length of string S will not exceed 12,000, and K is a positive integer.2) String S consists only of alphanumerical characters (a-z and/or A-Z and/or 0-9) and dashes(-).
3) String S is non-empty.
Here is my Code:
public static String licenseKeyFormatting(String S, int Key) {
String cleaned = S.replaceAll("[\\-]", "").toUpperCase();
String result = "";
int currentPos = 0;
//IF EVENLY SPLIT
if ( (cleaned.length() % Key) == 0 ) {
int numGroups = cleaned.length()/Key;
for(int i = 0; i < numGroups; i++) {
for (int k =0; k < Key; k++) {
char currentLetter = cleaned.charAt(currentPos++);
result = result + currentLetter;
}
if (i != (numGroups - 1)) {
result = result + "-";
}
}
}
else {
int remainder = cleaned.length() % Key;
for (int i = 0; i < remainder; i++) {
char currentLetter = cleaned.charAt(currentPos++);
result = result + currentLetter;
}
if(remainder == cleaned.length()) {
return result;
}
else {
result = result + "-";
}
int numGroups =( (cleaned.length() - remainder)/Key);
for (int i = 0; i < numGroups; i++) {
for (int k =0; k < Key; k++) {
char currentLetter = cleaned.charAt(currentPos++);
result = result + currentLetter;
}
if (i != (numGroups - 1)) {
result = result + "-";
}
}
}
//IF NOT EVENLY SPLIT
return result;
}
When I run it on my Computer, it works perfectly. When I run it on leetcode, it gives me a "Time Limit Exceeded" Error on the an input of a string of 44151 characters and "1" as the key. When I run the same input on my IDE, it works fine, but not on LeetCode. What might be the error? How could I make this more efficient?
I believe there is nothing wrong in program, but it is not the fast enough to meet time complexity expected by leetcode. I would suggest you can try, remove dashes and convert to upper cases. then add dashes at every (kth+remainder) places after the remainder position.
Do these operations in a stringbuilder instead of string.

How count of characters getting stored in char array. Basically wanted to the working of increment operator on the array

public static void getCharCountArray(String str)
{
for (int i = 0; i < str.length(); i++)
{
count[str.charAt(i)]++;
}
}
How is count array getting the count of the character. Working of the increment operator?
count is an indexed array of integers.
Each index of this array is a char.
The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).
In your loop, str.charAt(i) return the char of your String str for the current iteration.
You get the previous count for the current char of your String with the expression :
count[str.charAt(i)]
and you increment this value with the ++ operator.
we could rewrite your code like this :
for (int i = 0; i < str.length(); i++)
{
char currentChar = str.charAt(i);
int previousCharCount = count[currentChar];
int currentCharCount = previousCharCount + 1;
count[currentChar] = currentCharCount;
}
Your line : count[str.charAt(i)]++; does the same things, but in a simpler and more readable way.
The ++ operator, doesn't operate an increment on the array (non sense) but operates an increment on the integer value at the position char.

Java replacing character in string from the back

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

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]

Categories