Problem description: https://www.hackerrank.com/challenges/sherlock-and-anagrams
Can somebody please tell me what am I doing wrong? My algorithm is:
Input the string ; str
Generate a pattern string from length i=1 to str.length-2
Check whether anagram of pattern string exist in str.substring(i+1)
Below are the test cases which are NOT passing :
input-string My OP Expected OP
ifailuhkqq 2 3
My code:
public class SherlockandAnagrams
{
static int count = 0;
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
generatePairs(sc.next());
int len = 1;
}
public static void generatePairs(String str)
{
int len = 1;
//int i=0;
while (len < str.length())
{
for (int i = 0; i + len <= str.length(); i++)
findAnagramPairs(str, len, str.substring(i, i + len), i + 1);
len++;
}
System.out.println(count);
}
private static void findAnagramPairs(String str, int len, String pattern, int p)
{
int i = p;
while (i + len <= str.length())
{
if (checkAnagram(pattern, str.substring(i, i + len)))
{
count++;
}
i++;
}
}
private static boolean checkAnagram(String pattern, String text)
{
if (pattern.length() == 1)
{
if (pattern.equals(text))
return true;
else
return false;
}
else
{
int i = 0;
int j = pattern.length() - 1;
while (i < pattern.length())
{
if (pattern.charAt(i) == text.charAt(j))
{
i++;
j--;
}
else
return false;
}
return true;
}
}
}
A simpler solution to the problem would be the following:
An anagramic pair with starting-indices at (n , m) and length l can only exist, if another pair with length l - 1 at (n or n - 1 or n + 1 , m or m - 1 or m - 1) exists. Thus we can easily reduce efficiency from bruteforce to a more efficient solution.
An example:
A B C B A A B C A
len 1 A A A A //all pairs containing A
len 2 A B B A //all pairs that match A B or its reverse
len 3 A B C B A //all pairs that match A B C or its reverse
OR
A B C B A A B C A
len 1 B B B //all pairs containing B
len 2 B C B B C //all pairs that match B C or its reverse
len 3 A B C B A A B C //all pairs that match A B C or its reverse
The same applies to any other pair of length l and it's matching pairs with length l + 1. In general, a pair of length l + 1 only exists, if two pairs (a , b) and (c , d) of length l exists, such that either a = c - l and b = d + l or a = c + l and b = d - l exist.
In pseudocode this would look like this:
set pairs = listAnagrams(input , 1)
int len = 1
while NOT pairs.isEmpty()
set next_len
//generate pairs with length len + 1
for pair p in pairs
pair left = pair(p.a - len , p.b + len)
pair right = pair(p.a + len , p.b - len)
if pairs.contains(left)
next_len.add(pair(p.a , left.b)
if pairs.contains(right)
next_len.add(pair(left.a , p.b)
pairs = next_len
++len
Related
import java.util.Random;
public class MergeSortEx {
public static void mergeSort(char[] array) {
sortArray(array, 0, array.length);
}
private static void sortArray(char[] array, int start, int end) {
if (end-start <2)
return;
int mid = (start + end) / 2;
sortArray(array, 0, mid);
sortArray(array, mid, end);
mergeArray(array, start, mid, end);
}
private static void mergeArray(char[] array, int start, int mid, int end) {
char[] temp = new char[end - start];
int t = 0, s = start, m = mid;
while (s < mid && m < end) {
if (array[s] < array[m])
temp[t++] = array[s++];
else
temp[t++] = array[m++];
}
while (s < mid) {
temp[t++] = array[s++];
}
while (m < end) {
temp[t++] = array[m++];
}
for(int i=start;i<end;i++) {
array[i]=temp[i-start];
}
}
public static void main(String[] args) {
char[] randomString = new char[20];
Random rnd = new Random();
for (int i = 0; i < 20; i++) {
if (i < 10)
randomString[i] = (char) (rnd.nextInt(6) + 'A');
else
randomString[i] = (char) (rnd.nextInt(6) + 'a');
}
System.out.println(randomString.length);
for (int i = 0; i < 20; i++)
System.out.print(randomString[i] + " ");
mergeSort(randomString);
System.out.println();
for (int i = 0; i < 20; i++)
System.out.print(randomString[i] + " ");
}
}
I used the translator.
It's a university algorithm assignment, Merge sort implemented successfully.
Now, capital letters come out first, and lowercase letters come out.
Can make the code case-insensitive?
I want the results to be like this.
ex) a A A B b C c c D d ...
plz help.
Instead of comparing using if (array[s] < array[m]) directly, convert the characters to uppercase before comparing, similar to what String.compareToIgnoreCase(...) does:
if (Character.toUpperCase(array[s]) < Character.toUpperCase(array[m]))
That is for sorting individual characters. For sorting String values, there are two ways to make a case-insensitive sort:
Use the predefined String.CASE_INSENSITIVE_ORDER Comparator.
stringList.sort(String.CASE_INSENSITIVE_ORDER);
Use a Collator:
Collator collator = Collator.getInstance(Locale.US);
stringList.sort(collator);
That will sort localized alphabets correctly, e.g. if you specified Locale.GERMANY, it would sort upper- and lower-case letters together, but will e.g. also sort Ð between D and E, and sort ß same as S.
Just replace:
while (s < mid && m < end) {
if (arr[s] < arr[m])
temp[t++] = arr[s++];
else
temp[t++] = arr[m++];
}
with
while (s < mid && m < end) {
if (Character.toLowerCase(arr[s]) < Character.toLowerCase(arr[m]))
temp[t++] = arr[s++];
else
temp[t++] = arr[m++];
}
If you want small letters come first like aAbbbBBBcCCCD then try following.
Instead of:
array[s] < array[m]
Use:
private static boolean charCompare(char a, char b) {
char ua = Character.toUpperCase(a);
char ub = Character.toUpperCase(b);
if(ua == ub) {
return a > b;
} else {
return ua < ub;
}
}
Output:
20
F E E A D A B C A E a e c f d f c a f e
a a A A A B c c C d D e e E E E f f f F
I have a problem with this exercise.
In this exercise I enter a word and a number. I have to use the ASCII table to encrypt the word.
If I enter the letter "a" and the number 3, the letter becomes "d".
If I enter the letter "z" and the number 2, the letter should become "b", but a symbol comes out.
Another problem is if I use an uppercase letter. If I enter the uppercase letter "Z" I'll still get a symbol.
Another problem is if I use the letters "aB" and the number -2 should come out "yZ", but symbols come out.
This is the exercise:
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
String s, n="";
int N;
System.out.println("Insert a word");
s=in.next();
System.out.println("Insert a number");
N=in.nextInt();
n=uno(s, N);
System.out.println("That's the encrypted word: " + n);
}
public static String uno (String s, int N) {
String f, n="";
int c;
int length = s.length();
for (int i=0; i<length; i++) {
c = s.charAt(i);
c=c+N;
f = Character.toString((char)c);
n=n+f;
}
return n;
}
ASCII for z is 122. You add 2 to that. The ASCII for 124 is | symbol.
You need to check if your addition is going out of range (i.e. above 122).
Note: this won't work is N is greater than 26. Check the solution just below that implements modulo to handle that.
public static String uno (String s, int N) {
String f, n = "";
int c;
int length = s.length();
for (int i = 0; i < length; i++) {
c = s.charAt(i);
c = c + N;
if (c >= 122) {
c -= 26;
}
f = Character.toString((char) c);
n = n + f;
}
return n;
}
Side note: Never concatenate a string in a loop using +. It is very inefficient. Using StringBuilder.
Handle case sensitive letters concisely:
public static String uno (String s, int N) {
StringBuilder n = new StringBuilder();
int bound = s.length();
IntStream.range(0, bound).forEach(i -> {
char c = s.charAt(i);
n.append(Character.isUpperCase(c) ?
(char) ((c + N - 'A') % 26 + 'A') :
(char) ((c + N - 'a') % 26 + 'a'));
});
return n.toString();
}
Handling negative numbers:
public static String uno (String s, int N) {
StringBuilder n = new StringBuilder();
int bound = s.length();
IntStream.range(0, bound).forEach(i -> {
char c = s.charAt(i);
if (N > 0) {
n.append(Character.isUpperCase(c) ?
(char) ((c + N - 'A') % 26 + 'A') :
(char) ((c + N - 'a') % 26 + 'a'));
} else {
n.append((char) (c + N % 26 + 26));
}
});
return n.toString();
}
Check this comment for a good point on your naming conventions.
I am writing a program to find the number of 'a' in a given string that is repeated. For example, the call findAmountA("aba", 7) means that it finds the number of 'a' in the string "aba" repeated for 7 characters. So "abaabaa" is the final string, so that call would return 5.
Without actually making the string 7 characters (so calls for 1,000,000 characters would not take so long), how would I use mathematics to accomplish this task? I cannot get further than this, as I have been trying to troubleshoot this for a while.
Keep in mind I am a beginner Java programmer (Student) and do not want to use any advanced/fancy syntax that I would not learn in high school. Thank you!
public class AInString {
public static void main(String[] args) {
boolean a = findAmountA("aba", 10) == 7;
boolean b = findAmountA("a", 100) == 100;
boolean c = findAmountA("abca", 10) == 5;
boolean d = findAmountA("", 10) == 0;
boolean e = findAmountA("abcaa", 1000000) == 600000;
boolean f = findAmountA("abc", 0) == 0;
boolean g = findAmountA("bcd", 10) == 0;
System.out.println(a && b && c && d && e && f && g);
}
public static int findAmountA(String word, int n) {
String s = word;
if(s.length() == 0 || aInWord(word) == 0) {
return 0;
}else {
int a = (aInWord(s));
return a;
}
}
public static int aInWord(String word) {
String s = word;
int aInWord = 0;
for(int i = 0; i < word.length(); i++) {
if(s.charAt(i) == 'a') {
aInWord++;
}
}
return aInWord;
}
}
Let's say your short string w has N copies of 'a' in it. Then the result string will consist of K copies of w followed by a possibility empty “tail” string.
The value of K can be determined by integer-dividing the number of 'a's in the target string by N. Then the number t of 'a's in the “tail” would be equal to the remainder of the division. Now you can print K copies of w followed by the shortest prefix of 'w' containing t 'a's.
Divide the target length by the input length: for the example:
7 / 3 = 2 remainder 1
2 the number of "full copies" of the entire input string you will use. So, find the number of "a"s in the entire string, multiply by 2.
You will take the first 1 character of the input to make up the remainder of the 7 characters. Count the number of "a"s in that substring.
Simply add these two numbers together.
int total = count(input, "a") * targetLength / input.length()
+ count(input.substring(0, targetLength % input.length()), "a");
where count(input, c) is some method to count the number of occurrences of c in input.
Now that you've counted the occurrences of a char a in a string word, you can count the occurrences of the char in the string extended n characters with:
return n / word.length() * aInWord(word) + aInWord(word.substring(0, n % word.length()));
n / word.length() gives the number of full repeats of the string that fit into n. Multiplying this by the count of aInWord(word) gives the count of a in repeats of word that fit cleanly into n.
The rest is a matter of finding the number of repeats in the substring of word that doesn't fit cleanly into n using the % modulus operator to find the size of the partial substring (if any). Adding the two counts together produces the total number of occurrences in the extended string.
Here is a clean version which avoids duplicate variables, extra conditionals and generalizes methods to maximize reusability:
class Main {
public static void main(String[] args) {
assert findAmount("aba", 10, "a") == 7;
assert findAmount("a", 100, "a") == 100;
assert findAmount("abca", 10, "a") == 5;
assert findAmount("", 10, "a") == 0;
assert findAmount("abcaa", 1000000, "a") == 600000;
assert findAmount("abc", 0, "a") == 0;
assert findAmount("bcd", 10, "a") == 0;
System.out.println("tests passed");
}
public static int findAmount(String word, int n, String target) {
if (word.length() == 0) {
return 0;
}
return n / word.length() * count(target, word) +
count(target, word.substring(0, n % word.length()));
}
public static int count(String target, String s) {
return s.length() - s.replace(target, "").length();
}
}
Try it!
I made some changes in your code, take a look:
public static void main(String[] args) {
int a = findAmountA("aba", 10); // 7
int b = findAmountA("a", 100); // 100;
int c = findAmountA("abca", 10); //5;
int d = findAmountA("", 10); //0;
int f = findAmountA("abc", 0); //0;
int g = findAmountA("bcd", 10); //0;
System.out.println(a + " " + b + " " + c + " " + d + " " + f + " " + g);
}
public static int findAmountA(String word, int n) {
if (word.length() < n) {
for (int i=0; i<word.length(); i++) {
while (word.length() < n) {
word = word + word.charAt(i);
break;
}
}
} else if (word.length() > n) {
for (int i=0; i<word.length(); i++) {
word = word.substring(0, n);
}
} else {
return aInWord(word);
}
return aInWord(word);
}
public static int aInWord(String word) {
String s = word;
int aInWord = 0;
for(int i = 0; i < word.length(); i++) {
if(s.charAt(i) == 'a') {
aInWord++;
}
}
Thank you all for your help, using substrings I found an answer:
public class AInString {
public static void main(String[] args) {
boolean a = findAmountA("aba", 10) == 7;
boolean b = findAmountA("a", 100) == 100;
boolean c = findAmountA("abca", 10) == 5;
boolean d = findAmountA("", 10) == 0;
boolean e = findAmountA("abcaa", 1000000) == 600000;
boolean f = findAmountA("abc", 0) == 0;
boolean g = findAmountA("bcd", 10) == 0;
System.out.println(a && b && c && d && e && f && g);
}
public static int findAmountA(String word, int n) {
String s = word;
if(s.length() == 0 || aInWord(s) == 0) {
return 0;
}else {
int a = aInWord(s)*(n/s.length());
int b = n % s.length();
return a + aInWord(s.substring(0, b));
}
}
public static int aInWord(String word) {
String s = word;
int aInWord = 0;
for(int i = 0; i < word.length(); i++) {
if(s.charAt(i) == 'a') {
aInWord++;
}
}
return aInWord;
}
}
This question already has answers here:
Sort 4 numbers without array
(2 answers)
Closed 5 years ago.
I have a homework where I'm supposed to prompt the user to enter five numbers and arrange them from min to max and since we didn't take arrays
I'm only left with Math.min & Math.max or if statement.
I wrote a code where the first, second and last number are always correct But I can't seem to figure out how to do the 3rd and 4th number
Here's an example:
if (a <= b && a <= c && a <= d && a <= e) {
System.out.println("Numbers in Ascending order "
+ a + " " +Math.min(Math.min(b, c), Math.min(d, e)) +
" " + "?" +
" " + "?" +
" " +Math.max(Math.max(b, c), Math.max(d, e)));
}
If you know any idea that might help me solve this task?
Here is one possible solution
public static void main(String... args) {
int a = 32;
int b = 42;
int c = 2;
int d = 88;
int e = 92901;
int counter = 0;
while (counter < 5) {
int currentMin = findMin(a, b, c, d, e);
// Printing smallest number yeat
System.out.print(currentMin + " ");
if (a == currentMin){
a = Integer.MAX_VALUE;
}
if (b == currentMin){
b = Integer.MAX_VALUE;
}
if (c == currentMin){
c = Integer.MAX_VALUE;
}
if (d == currentMin){
d = Integer.MAX_VALUE;
}
if (e == currentMin){
e = Integer.MAX_VALUE;
}
counter++;
}
}
private static int findMin(int a, int b, int c, int d, int e) {
int smallest = Math.min(a, Math.min(b, Math.min(c, Math.min(d, e))));
return smallest;
}
Notice how I am using the Integer.MAX_VALUE to remove the smallest number yeat for example in the first iteration 2 will be returned which is equals to c now I have to make the code somehow to ignore c in the next iteration because it was already used if I was using the Integer object i could have set c to be null but int cannot be setted to null so what i can do is to set it to number so large that findMin function would never choose it again that's why I use MAX_VALUE
If you have to do it using if,else if statements then you will have to write one if statement and 119 else if statements i.e. number of ways in which 5 numbers can be arranged. 5!=120.
if you are allowed to use for loop check this link
int aux;
if (b < a){
aux = b; b = a; a = aux;
}
if (c < a){
aux = c; c = b; b = a; a = aux;
}
else{
if (c < b){
aux = c; c = b; b = aux;
}
}
...
I guess you get the idea, in the end a will be the smallest and e will be the biggest
For more information, since it looks like you're getting started to programming and sorting algorithms, this is called Insertion Sort (I believe). More information here https://en.wikipedia.org/wiki/Insertion_sort
This is a possible answer. Since loop and arrays cannot be used, much of the code is repetition. In the end a,b,c,d,e contain the values arranged from min to max. Hope this helps.
import java.io.*;
class SortFiveElements {
//utility function
//returns index as a:1, b:2, c:3, d:4, e:4
public static int find_min_index(int a,int b, int c,int d, int e, int min)
{
return a==min?1:(b==min?2:(c==min)?3:(d==min?4:5));
}
public static void main (String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int a = Integer.parseInt(br.readLine());
int b = Integer.parseInt(br.readLine());
int c = Integer.parseInt(br.readLine());
int d = Integer.parseInt(br.readLine());
int e = Integer.parseInt(br.readLine());
//temp is a temporary var to store the i-th value which may get replaced
//smallest stores the min value among i-th to 5th element
//idx stores the minimum value's index
int temp,smallest,idx;
//i=1, i.e element 'a'
//temp has value of 1st element that is a
//find minimum among 5 elements in 'smallest', its index in 'idx'
//then swap
temp = a;
smallest = Math.min(a,Math.min(b,Math.min(c,Math.min(d,e))));
idx = find_min_index(a,b,c,d,e,smallest);
a = smallest;
if(idx==1)
a=temp;
else if(idx==2)
b = temp;
else if(idx==3)
c = temp;
else if(idx==4)
d = temp;
else
e = temp;
//i=2, i.e element 'b'
//temp has value of 2nd element that is b
//find minimum among 4 elements in 'smallest', its index in 'idx'
//NB: a already has the smallest value, so replace a with MAX_VALUE while finding index
//then swap
temp = b;
smallest = Math.min(b,Math.min(c,Math.min(d,e)));
idx = find_min_index(Integer.MAX_VALUE,b,c,d,e,smallest);
b = smallest;
if(idx==1)
a=temp;
else if(idx==2)
b = temp;
else if(idx==3)
c = temp;
else if(idx==4)
d = temp;
else
e = temp;
//repeat above process for 'c' and 'd'.
//'e' will automatically fall in place
temp = c;
smallest = Math.min(c,Math.min(d,e));
idx = find_min_index(Integer.MAX_VALUE,Integer.MAX_VALUE,c,d,e,smallest);
c = smallest;
if(idx==1)
a=temp;
else if(idx==2)
b = temp;
else if(idx==3)
c = temp;
else if(idx==4)
d = temp;
else
e = temp;
temp = d;
smallest = Math.min(d,e);
idx = find_min_index(Integer.MAX_VALUE,Integer.MAX_VALUE,
Integer.MAX_VALUE,d,e,smallest);
d = smallest;
if(idx==1)
a=temp;
else if(idx==2)
b = temp;
else if(idx==3)
c = temp;
else if(idx==4)
d = temp;
else
e = temp;
//we have the values in sorted order in a,b,c,d,e
System.out.println(a+" "+b+" "+c+" "+d+" "+e);
}
}
I need to first encrypt and then decrypt a message using the Vigenere cypher. This is how it should work
example message: "c a t s _ d o g s"
keyword "rats": r a t s r a t s r
order of the letter in the message (start at a=0):2 0 19 18 () 3 14 6 18
order of the letter in the keyword: 17 0 19 18 17 0 19 18 17
sum of the two orders: 19 0 38 36 17 3 39 24 35
new letter for the message* t a m k d h y j
encrypted message = "tamk uoyk"
Note: if the sum > 26 then we subtract 26 from the sum to get a cyclical alphabet. Example:
z + b = 25 + 1 = 26; 26 - 26 = 0 --> a
I have written the methods to obtain the numerical value of the keyword, and also two methods that "add" or "subtract" individual letters and two methods that perform the caesar encoding/decoding (simply shifting the entire message by an int to the right in the alphabet, or to the left to decrypt).
The piece that I really need help for is to how to create a for loop that's going to repeat the keyword the appropriate amount of times (to have the same length as the message) and proceed to the obtainKeys method to get the numerical values of the repeated key.
Here is my entire program; the part I am struggling with is at the end (Q2f)
import java.util.Arrays;
public class Cypher {
public static void main(String[] args) {
System.out.println(charRightShift('z', 3));
System.out.println(charLeftShift('z', 3));
String test = caesarEncode("cats and dogs", 5);
System.out.println(test);
System.out.println(caesarDecode(test, 5));
obtainKeys("abcxyz");
System.out.println(vigenereEncode("elephants", "rats"));
}
//Q2a-b
//Generalized method for char shifts
public static char charShift(char c, int n) {
//value of n should be between 0 and 25
if (Math.abs(n) < 0 || 25 < Math.abs(n)) {
//returning the ascii value of '0' which
//is nul & adding error message
int zero = 0;
c = (char) zero;
throw new IllegalArgumentException("n has to be 0<=|n|<=25");
}
//character c should be a lower case latin letter
//if not, we simply return c, the original character,
//skipping this else if
else if (c >= 'a' && c <= 'z') {
c = (char) (c + n);
if (c > 'z') {
c = (char) (c - 26);
} else if (c < 'a') {
c = (char) (c + 26);
}
}
return c;
}
//method that shifts the value of the character to the right
public static char charRightShift(char c, int n) {
c = charShift(c, n);
return c;
}
//method that shifts the value of the character to the left
public static char charLeftShift(char c, int n) {
n = -n;
c = charShift(c, n);
return c;
}
//Q2c
//method that shifts the message to the right by int 'key' characters
public static String caesarEncode(String message, int key) {
//transform string into char array
char[] messageEncrypt = message.toCharArray();
//for each char, we shift it by 'key' ints,
//using charRightShift method
for (int i = 0; i < messageEncrypt.length; i++) {
char c = messageEncrypt[i];
c = charRightShift(c, key);
messageEncrypt[i] = c;
}
return new String(messageEncrypt);
}
//Q2d
//method that shifts the message to the left by int 'key' characters
public static String caesarDecode(String message, int key) {
//transform string into char array
char[] messageDecrypt = message.toCharArray();
//for each char, we shift it by 'key' ints using charLeftShift
for (int i = 0; i < messageDecrypt.length; i++) {
char c = messageDecrypt[i];
c = charLeftShift(c, key);
messageDecrypt[i] = c;
}
return new String(messageDecrypt);
}
//Q2e
//method to obtain the int array storing the numerical value of the String
public static int[] obtainKeys(String s) {
//creating int array where we're going to
//store the numerical value of the String
int[] keys = new int[s.length()];
int j;
//for each ascii value of the char in string s, we substract 97 to
//get the lower case english alphabet character corresponding to it
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
j = c - 97;
//now store every int in the int array
keys[i] = j;
}
String keysString = Arrays.toString(keys);
return keys;
}
//Q2f
public static String vigenereEncode(String message, String keyword) {
//for loop check if there are any 'illegal' characters in the keyword
char[] kword = keyword.toCharArray();
for (int i = 0; i < kword.length; i++) {
char c = kword[i];
if (c < 'a' || c > 'z') {
throw new IllegalArgumentException(
"The keyword must only contain characters " +
"from the lower case English alphabet.");
}
}
int[] numMessage = obtainKeys(message);
int[] numKeyword = obtainKeys(keyword);
for (int i = 0; i < message.length(); i++) {
for (int j = 0; j < keyword.length(); i++) {
//NOT SURE IF I NEED A NESTED LOOP HERE
//WHAT TO DO HERE?
}
}
return messageVigenere;
}
}
You can do this by using the mod operation %.
char[] messageArray = message.toCharArray();
char[] encryptedMessage = new char[messageArray.length];
int[] numKeyword = obtainKeys(keyword);
int keywordLength = numKeyword.length;
for(int i=0; i<message.length(); i++){
int shiftAmount = numKeyword[i % keywordLength];
char c = messageArray[i];
c = charRightShift(c,shiftAmount);
encryptedMessage[i] = c;
}
Instead of repeating the keyword til it is the length of the message, you can find which letter is needed using modulus logic. For any location n in the message, the keyword letter is keyword[n % keyword.length()].