I am trying to solve the following question:
https://www.hackerrank.com/challenges/sherlock-and-anagrams
This is my code
import java.util.*;
public class Solution {
public static boolean check(String s1,String s2)
{
int [] count1 = new int[26];
for( int i = 0; i < s1.length(); i++ )
{
char ch1 = s1.charAt(i);
count1[ch1-'a']++;
}
int [] count2 = new int[26];
for( int i = 0; i < s2.length(); i++ )
{
char ch2 = s2.charAt(i);
count2[ch2-'a']++;
}
int count =0;
for(int j=0;j<26;j++)
{
count = count + Math.abs(count1[j]-count2[j]);
}
if(count ==0)
return true;
else return false;
}
public static void main(String[] args) {
String s,sub;
int i,c,len;
List<String> all = new ArrayList<>();
Scanner in = new Scanner(System.in);
int t = Integer.parseInt(in.nextLine());
while((t--)>0)
{
s = in.nextLine();
len = s.length();
for( c = 0 ; c < len ; c++ )
{
for( i = 1 ; i <= len - c ; i++ )
{
sub = s.substring(c, c+i);
all.add(sub);
}
}
String[] arr = new String[all.size()];
for( i = 0; i < all.size(); i++)
arr[i] = all.get(i);
int l=0;
for (int m=0;m<arr.length;m++)
{
for(int n=m+1;n<arr.length;n++)
{
if(check(arr[m],arr[n]))
l++;
}
}
System.out.println(l);all.clear();
}
}
}
My code worked for few test cases which have small strings but failed to work if string size is too big
Sample input
5
ifailugtyovhdfuhdouarjsnrbfpvmupwjjjfiwneogwnoegnoegneognoewhrlkpekxxnebfrwibylcvkfealgonjkzw
gffryqktmwocejbrexfidpjfgrrkpowoxwggxaknmltjcpazgtnakcfbveieivoenwvpnoevvneocogzatyskqjyorcftw
uqlzvuzgkwhkkrrfpwarkckansgabfclzgnumdrojexnofeqjnqnxwidhbvbenevun9evnnv9euxxhfwargwkikjq
sygjxynvofnvirarcoacwnhxyqlrviikfuiuotifznqmzpjrxycnqkeibvibvewioebvitkryutpqvbgbgthfges
mkenscyiamnwlpxytkndjsygifmqlqibxxqlauxamfviftquntvkwppxrzuncyenavebiobeviobeiobeibvcfivtigv
My Output
4s : Terminated due to timeout
is there any better way to solve it or to change the existing code so that executed time is within 4mins
You can check out this link. It is explained very well here.
I think that you are storing all substrings and then searching for the anagram pair because of that space complexity of your code is very much. So you can improve that. You can also reduce the number of operations in your check function by returning false at the very first point where they mismatch.
I have implemented the above problem in c++. Here is my code:
#define MAX 26
bool isAnagram(int *count1, int *count2) {
for(int i = 0; i < MAX; i++) {
if(count1[i] != count2[i])
return false;
}
return true;
}
int findPair(string str, int start, char *tmp, int n) {
int len = str.length();
if(strlen(tmp) > len-start) {
return 0;
}
int *count1 = new int[MAX];
int *count2 = new int[MAX];
int cnt = 0;
int i;
for(i = 0; i < MAX; i++) {
count1[i] = 0;
count2[i] = 0;
}
for(i = 0; i < n && (start+i) < len; i++) {
count1[tmp[i]-'a']++;
count2[str[start+i]-'a']++;
}
int j;
for(j = start + i; j < len; j++) {
if(isAnagram(count1, count2)) {
cnt++;
}
count2[str[start]-'a']--;
count2[str[j]-'a']++;
start++;
}
if(j == len) {
if(isAnagram(count1, count2)) {
cnt++;
}
}
delete []count1;
delete []count2;
return cnt;
}
int countPairs(string str) {
int n = str.length();
if(n < 2) {
return 0;
}
int cnt = 0;
char *tmp = new char[n];
for(int i = 0; i < n; i++) {
int k = 0;
for(int j = i; j < n; j++) {
tmp[k] = str[j];
tmp[k+1] = '\0';
cnt += findPair(str, i+1, tmp, k+1);
k++;
}
}
delete []tmp;
return cnt;
}
int main() {
int t;
cin>>t;
while(t--) {
string str;
cin>>str;
cout<<countPairs(str)<<endl;
}
return 0;
}
Apart from early termination. You can use a HashMap, the key being the length and the value being a list of substrings of the same length. Store the substrings and check only with elements inside the 'value'.
Although you might think it works the same as early termination if the lengths are different, it makes a difference and doesn't give early termination problems.
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int x=sc.nextInt();
for(int k=0; k<x; k++){
String str1=sc.next();
HashMap<Integer,ArrayList<String>> sub= getSub(str1);
int counter=0;
for(int t=1; t<=str1.length(); t++){
ArrayList<String> subsl= sub.get(t);
for(int i=0; i<subsl.size()-1; i++){
for(int j=i+1; j<subsl.size(); j++){
if(isAnagram(subsl.get(j),subsl.get(i))){
counter++;
}
}
}
}
System.out.println(counter);
}
}
public static HashMap<Integer,ArrayList<String>> getSub(String str1){
HashMap<Integer,ArrayList<String>> ret= new HashMap<Integer,ArrayList<String>>();
for(int i=0; i<str1.length(); i++){
for(int j=i; j<str1.length(); j++){
if(!ret.containsKey(str1.substring(i, j+1).length())){
ArrayList<String> x= new ArrayList<String>();
x.add(str1.substring(i, j+1));
ret.put(str1.substring(i, j+1).length(), x);
}
else
ret.get(str1.substring(i, j+1).length()).add(str1.substring(i, j+1));
}
}
return ret;
}
public static boolean isAnagram(String a1, String a2){
int count1[]= new int[26];
int count2[]= new int[26];
if(a1.length()!=a2.length())
return false;
for(int i=0; i<a1.length(); i++){
count1[(int)a1.charAt(i)-97]++;
count2[(int)a2.charAt(i)-97]++;
}
for(int i=0; i<26; i++){
if(count1[i]!=count2[i])
return false;
}
return true;
}
}
If you want to make it even faster, then change the HashMap to include an object with has the counts of all 26 alphabets. That'll obviously take more memory so you can have something intermediate with the length and say counts of letters a,b,c (or 3 such letters).
To make the checking efficient, use bit manipulation to encode all these (length, count of a, count of b and count of c). Though take care to not exceed the number of bits for Integer.
Try this.
What I have done here is broken the string into two substrings and checked all the anagramic pairs of 1st string in the second.
for ex:abba
1st substring=a;
2nd substring=bba
now check all anagramic pairs of a in bba
import java.util.*;
public class SherlockAndAnagrams{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int t=Integer.parseInt(sc.nextLine());
while(t-->0){
String s=sc.nextLine();
int count=0;
for(int i=0;i < s.length();i++){
for(int k=i+1;k < s.length();k++){
int num=anagram(s.substring(i,k),s.substring(i+1),s.substring(i,k).length());
count=count+num;
}
}
System.out.println(count);
}
}
static int anagram(String s1,String s2,int len){
int count = 0;
char[] c1=s1.toCharArray();
Arrays.sort(c1);
String ss1=new String(c1);
int length=s2.length();
for(int i=0;i<length;i++){
if(i+len<=length){
String sub=s2.substring(i,i+len);
char[] c2=sub.toCharArray();
Arrays.sort(c2);
String ss2=new String(c2);
if(ss1.compareTo(ss2)==0)
count++;
}
}
return count;
}
}
Related
For school, i have to build myself a method in java that compresses an array using RLE(run-length encoding). I can't find a solution online because my teacher wants me to solve the problem myself. I, unfortunately, cannot do this for i am a busy man with some busy plans.
RLE turns this: {1,1,1,1,2,2,3,3,6,6,6,7,8,8,8}
into this: {4,1,2,2,2,3,3,6,1,7,3,8}
it basically makes a new array that follows this formula {# of this value, this value, # of this value, this value, cont...} there are 4 1's so {4,1} you get my drift.
Here is what i tried to do(forgive me for my crappy code, i am merely a high school student):
public class tester{
public static void main(String[] args){
int[] potato = {1,1,1,2,2,4,4,4,6,6,6,6};
printArray(compress(potato));
}
public static void printArray(int[] arr){
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
}
public static int[] compress(int[] a) {
//figure out how many different numbers there are.
int diffNums = 1;
for(int i = 0; i < a.length; i++){
if(i != a.length-1 && a[i] != a[i+1]){
diffNums++;
}
}
//make compressed array at the correct length.
int[] compressed = new int[diffNums * 2];
//figure out what each number is.
int[] nums = new int[diffNums];
nums[0] = a[0];
int spot = 0;
for(int i = 0; i < a.length; i++){
if(i != a.length-1 && a[i] != a[i+1]){
nums[spot] = a[i+1];
}
}
//figure out quantity of each number.
int[] quantities = new int[diffNums];
int spot2 = 0;
int spotcur = 0;
for(int i = 0; i < diffNums; i++){
int quant = 0;
while(a[spotcur] == a[spot2]){
quant++;
spotcur++;
}
spot2 = spotcur;
quantities[i] = quant;
}
//add them together and return compressed array
int spotter = 0;
for(int i = 0; i < diffNums; i++){
compressed[spotter] = quantities[i];
spotter++;
compressed[spotter] = nums[i];
spotter++;
}
return compressed;
}
}
Does anyone know how i can fix this crappy code? i am stuck on it
I think this problem could be solved with a lot less code. You could use an outer/inner loop construct something like the following:
public static int[] compress(int[] a) {
List<Integer> encoded = new ArrayList<>();
for (int i=0; i<a.length; i++) {
int num = a[i];
int count = 1;
for (int j=i+1; j<a.length; j++) {
int nextNum = a[j];
if (nextNum != num)
break;
count++;
i++;
}
encoded.add(count);
encoded.add(num);
}
return encoded.stream().mapToInt(i->i).toArray();
}
Also, the Arrays class contains a useful toString method already defined.
System.out.println(Arrays.toString(compress(potato)));
Here is my code ,
Find me the way to finish this off .
I had this question in paper this is the code at that time I could do.
In following example it should return 3.(starting point of "d")
public class HelloWorld {
public static void main(String []args){
int result = getMax("haaddddddddccf");
System.out.println(result);
}
public static int getMax(String input){
int length = input.length();
int count = 0;
int max = 0;
int tempCount = 0;
for(int i=0;i<length-1;i++) {
if(input.charAt(i) == input.charAt(i+1)) {
count ++ ;
}
tempCount = count;
count = 0;
if(max > tempCount) {
max = tempCount;
return i;
}
tempCount = 0;
}
return 0;
}
}
How about something like this:
public class HelloWorld {
public static void main(String []args){
int result = getMax("haaddddddddccf");
System.out.println(result);
}
public static int getMax(String input){
int length = input.length();
int maxIndex = 0;
int max = 0;
int count = 1;
char current = input.charAt(0);
int index = 0;
for(int i=1; i<length-1; i++) {
if(input.charAt(i) == current) {
count ++ ;
if(count > max) {
max = count;
maxIndex = index;
}
}
else {
count = 1;
current = input.charAt(i);
index = i;
}
}
return maxIndex;
}
}
This goes over the entire string and counting consecutive occurrences of characters. If the count goes over the observed maximum, the start index of that series of consecutive characters is saved as well as the number of characters. If the character changes, the current values reset and counting starts over. After going over the entire list, the index of the longest series of consecutive characters is in maxIndex.
so when I go to compile this Eclipse says, that the numbers for Insertionct and Shakerct are 0 and prints out a tie. I know for a fact that both methods are sorting correctly, but for some reason it doesn't return the amount of comparisons that they are making to main in order to decide which one sorted the array faster. Thanks for any help in advance.
import java.io.*;
import java.util.*;
public class Sorts {
private static Scanner in;
public static void main(String[] args) throws Exception {
in = new Scanner(System.in);
System.out.print("How many strings will you be entering? ");
int sz = Integer.parseInt (in.nextLine());
String[] A = new String[sz];
String[] B = new String[sz];
for (int i = 0; i < sz; i++){
System.out.print ("Enter String #"+(i+1)+": ");
A[i] = in.nextLine();// sets the array at i equal to a string
B[i] = A[i]; // sets array B to the same as array A so I can use it in the shaker sort method
}
int Insertionct = 0;
int Shakerct = 0;
System.out.println(Insertionct);
System.out.println(Shakerct);
if (Shakerct > Insertionct) {
System.out.println("Insertion Sort was faster!");
} else if (Shakerct < Insertionct) {
System.out.println("Shaker Sort was faster!");
} else {
System.out.println("It was a tie");
}
}
public static int InsertionSort (int Insertionct, String[] A) throws Exception { //sorts the array of strings with the insertion sort.
// initializes the count variable
int sz = A.length; // sets size equal toe array A
for (int i = 0; i < sz-1; i++)
for (int j = i; j >= 0 && A[j].compareTo (A[j+1]) > 0; j--) {
Insertionct++;
String t = A[j]; //switch A[j], A[j+1]
A[j] = A[j+1];
A[j+1] = t;
}
return Insertionct;
}
public static int ShakerSort (int Shakerct, String[] B) throws Exception {//Uses the ShakerSort in order to order the array.
int sz = B.length;
for (int i = 0; i < sz; i++){
int nsct = 0;
for(int j = nsct+sz-1; j > i; j--){//runs through the array backwards and then swaps if it needs to
Shakerct++;
if (B[j].compareTo(B[j-1]) < 0) {
nsct = 0;
String t = B[j];
B[j] = B[j-1];
B[j-1] = t;
} else {
nsct++; // if no swap happens it increases no swap to increment the starting points.
}
}
for (int j = nsct; j > sz-i-1; j++){
if (B[j].compareTo(B[j+1]) > 0){//runs through the array going forward swaps if needed
Shakerct++;
nsct = 0;
String t = B[j];
B[j] = B[j+1];
B[j+1] = t;
} else {
nsct++;// increases no-swap count if no swap happens and changes the starting point.
}
}
}
return Shakerct;
}
}
You don't call InsertionSort and ShakerSort in main.
I have to make a 3 way merge sort of an array. the array length is a in a power of 3, i.e. 3,9,27 etc. So I can use only one split function and not "left","mid","right".
Would like to get an answer how to repair it and why does not it work.
I have written the code, however don't know how to get it to work.
Here it is:
EDITED THE CODE, STILL DOES NOT WORK
public class Ex3 {
public static void main(String[] args) { //main function
Scanner in = new Scanner(System.in); //scanner
int size = in.nextInt();
int[] arr = new int[size];
for (int i = 0; i<arr.length; i++){
arr[i] = in.nextInt();
}
in.close();
arr = merge3sort (arr); //send to the function to merge
for (int i = 0; i<arr.length; i++){ //printer
System.out.print(arr[i]+ " ");
}
}
static int[] split(int[] m, int thirdNum) { //split function that splits to 3 arrays
int third[] = new int[m.length/3];
int third1[]=new int[m.length/3];
int third2[]=new int[m.length/3];
for(int i = 0; i<=m.length/3; i++)
third[i]=m[i];
for(int i=0; i<=m.length/3;i++)
third1[i]=m[i+thirdNum];
for(int i=0; i<=m.length/3;i++)
third2[i]=m[i+2*thirdNum];
return merge(third,third1,third2);
//return null;
}
static int minOf3(int[] a3) { //function that finds out how what is the index of the smallest number
int num0 = a3[0];
int num1 = a3[1];
int num2 = a3[2];
int idx = 0;
if(num0<num1 && num1<num2)
idx=0;
if(num1<num0 && num0<num2)
idx=1;
else
idx=2;
return idx;
}
static int[] merge(int[] th0, int[] th1, int[] th2) { //function that sorts the numbers between 3 arrays
int len0=th0.length;
int len1=th1.length;
int len2=th2.length;
int[] united = new int[len0+len1+len2];
int ind = 0; int i0=0; int i1=0; int i2=0;
while(i0<len0 && i1<len1 && i2<len2){
if(th0[i0]<th1[i1]){
if(th0[i0]<th2[i2]){
united[ind]=th0[i0];
i0=i0+1;
}//end inner if
else{
united[ind]=th2[i2];
i2=i2+1;
}//end inner else
}//end outer if
else{
united[ind]=th1[i1];
i1=i1+1;
}//end outer else
ind=ind+1;
}//end while
for (int i = i0; i < len0; i = i + 1) {
united[ind] = th0[i];
ind = ind + 1;
}
for (int i = i1; i < len1; i = i + 1) {
united[ind] = th1[i];
ind = ind + 1;
}for (int i = i2; i < len2; i = i + 1) {
united[ind] = th2[i];
ind = ind + 1;
}
return united;
}
static int[] merge3sort(int[] m) { //function that glues all together
if (m.length == 1) {
return m;
}
else{
return merge(merge3sort(split(m,m.length/3)),merge3sort(split(m,m.length/3)),merge3sort(split(m,m.length/3))); }
}
I get the following exception:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at ololosh1.Ex3.split(Ex3.java:27)
at ololosh1.Ex3.merge3sort(Ex3.java:98)
at ololosh1.Ex3.main(Ex3.java:15)
Look at this part of your code:
for(int i = 0; i<=m.length/3; i++)
third[i]=m[i];
for(int i=0; i<=m.length/3;i++)
third1[i]=m[i+thirdNum];
for(int i=0; i<=m.length/3;i++)
third2[i]=m[i+2*thirdNum];
Arrays are indexed from 0 to length-1. Each third* array has length m.length/3. Therefore their index can only go up to m.length/3 - 1. Yet you are indexing up to and including m.length/3.
Once you get your application working correctly, you really should clean it up. There is a lot of redundancy. For example, you are using the expression m.length/3 multiple times in method split() but you are also passing that same value to it as an argument.
Basically I need to call my "sum" and "sumOfEvens" methods into the main method. The "sum" method is for when the array contains the lucky numbers as seen in the "isLucky" method. The "sumOfEvens" method adds of the even numbers if the array doesn't contain a lucky number.
So "sum" = true
and "sumOfEvens" = false
So here is my code...
import java.util.Scanner;
public class FunArrays {
public static void main(String[] args) {
luckyNumber1 = 7;
luckyNumber2 = 13;
luckyNumber3 = 18;
int[] a=new int[10];
Scanner sc=new Scanner(System.in);
System.out.println("Please enter numbers...");
for(int j = 0; j < a.length; j++)
a[j] = sc.nextInt();
}
public static int sum(int [ ] value)
{
int i, total = 0;
for(i=0; i<10; i++)
{
total = total + value[ i ];
}
return (total);
}
static int sumOfEvens(int array[])
{
int sum = 0;
for(int i = 0; i < array.length; i++>) {
if(array[i] % 2 == 0)
sum += array[i];
}
return sum;
}
public static boolean isLucky (int[] array)
{
if ( array[i] == 7 || array[i] == 13 || array[i] == 18 )
return true;
else
return false
}
// write the static methods isLucky, sum, and sumOfEvens
}
boolean b = isLucky(a);
int result;
if(b)
result = sum(a);
else
result = sumOfEvens(a);
You can do it in one line:
int result = isLucky(a) ? sum(a) : sumOfEvens(a);