Can't understand the logic behind this anagram problem's solution [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Given two strings, a and b, that may or may not be of the same length, determine the minimum number of character deletions required to make a and b anagrams. Any characters can be deleted from either of the strings.
This is my first time preparing for competitive programming and understanding the logic behind the two for loops is quite hard for me.
String str1 = s.next();
String str2 = s.next();
char []c1 = str1.toCharArray();
char []c2 = str2.toCharArray();
int []cnt1 = new int[26];
int []cnt2 = new int[26];
int len1 = str1.length();
for (int i = 0; i < len1; i++) {
cnt1[c1[i] - 97]++;
}
int len2 = str2.length();
for (int i = 0; i < len2; i++) {
cnt2[c2[i] - 97]++;
}
int cnt = 0;
for (int i = 0; i < 26; i++) {
cnt += Math.abs(cnt2[i] - cnt1[i]);
}
System.out.println(cnt);

This snippet goes over each string and counts the number of occurrences each letter has in it (and store the counters in an array for better performance).
It then goes over the two arrays of counters, and for each letter subtracts the counters for both strings (in absolute value). The difference is the number of that character that should be removed. These differences are summed, and the result is the answer.

Okay, this is what the program is doing with two for loops.
Imagine 'cnt1' as English alphabet 'A' to 'Z' written up on a paper from left to right, and so is 'cnt2'. First for loop is tick marking a letter on the paper should it be found in 'string1', and so does second for 'string2'.
Now, you have two papers with 'A' to 'Z' written up on them from left to right, and after two 'for loops' have executed, each of the paper has tick marks on those letters that were present in respective string inputs.
Now, if a letter is ticked on both the papers, leave it alone, and should you find any of the letter ticked in one paper (i.e. in the array), and is not ticked in the other array, then count it as a letter to be deleted.
By the time you have scanned both the papers like this from left to right, you'd have number of letters that need to be removed in totality from both the papers.
Lets see how it is implemented in code. Default initial values of primitive array is all zeros, and the act of 'tick marking' a letter on paper is achieved by changing that particular index to '1'.
So, by the time the first two for loops end, each of 'cnt1' and 'cnt2' arrays would have '1' in it randomly. If both the arrays have '1' or '0' in it for a given index, you need not count it, should they be different i.e. difference of that particular index for both the arrays is '1' (that's why you see Math.abs being used), then that is a letter to be deleted from first string, or the second.
edit: For competitive exams, you should be able to visualize the solution first, and then find an optimum one. Computers only add speed to the solution found. They don't think, we make them think :)
Hope you could visualize the solution first and are still getting used to programing. All the best!

Related

NZEC error in Hackerearth problem in java

I'm trying the solve this hacker earth problem https://www.hackerearth.com/practice/basic-programming/input-output/basics-of-input-output/practice-problems/algorithm/anagrams-651/description/
I have tried searching through the internet but couldn't find the ideal solution to solve my problem
This is my code:
String a = new String();
String b = new String();
a = sc.nextLine();
b = sc.nextLine();
int t = sc.nextInt();
int check = 0;
int againCheck =0;
for (int k =0; k<t; k++)
{
for (int i =0; i<a.length(); i++)
{
char ch = a.charAt(i);
for (int j =0; j<b.length(); j++)
{
check =0;
if (ch != b.charAt(j))
{
check=1;
}
}
againCheck += check;
}
}
System.out.println(againCheck*againCheck);
I expect the output to be 4, but it is showing the "NZEC" error
Can anyone help me, please?
The requirements state1 that the input is a number (N) followed by 2 x N lines. Your code is reading two strings followed by a number. It is probably throwing an InputMismatchException when it attempts to parse the 3rd line of input as a number.
Hints:
It pays to read the requirements carefully.
Read this article on CodeChef about how to debug a NZEC: https://discuss.codechef.com/t/tutorial-how-to-debug-an-nzec-error/11221. It explains techniques such as catching exceptions in your code and printing out a Java stacktrace so that you can see what is going wrong.
1 - Admittedly, the requirements are not crystal clear. But in the sample input the first line is a number.
As I've written in other answers as well, it is best to write your code like this when submitting on sites:
def myFunction():
try:
#MY LOGIC HERE
except Exception as E:
print("ERROR Occurred : {}".format(E))
This will clearly show you what error you are facing in each test case. For a site like hacker earth, that has several input problems in various test cases, this is a must.
Coming to your question, NZEC stands for : NON ZERO EXIT CODE
This could mean any and everything from input error to server earthquake.
Regardless of hacker-whatsoever.com I am going to give two useful things:
An easier algorithm, so you can code it yourself, becuase your algorithm will not work as you expect;
A Java 8+ solution with totally a different algorithm, more complex but more efficient.
SIMPLE ALGORITM
In you solution you have a tipical double for that you use to check for if every char in a is also in b. That part is good but the rest is discardable. Try to implement this:
For each character of a find the first occurence of that character in b
If there is a match, remove that character from a and b.
The number of remaining characters in both strings is the number of deletes you have to perform to them to transform them to strings that have the same characters, aka anagrams. So, return the sum of the lenght of a and b.
NOTE: It is important that you keep track of what you already encountered: with your approach you would have counted the same character several times!
As you can see it's just pseudo code, of a naive algorithm. It's just to give you a hint to help you with your studying. In fact this algorithm has a max complexity of O(n^2) (because of the nested loop), which is generally bad. Now, a better solution.
BETTER SOLUTION
My algorithm is just O(n). It works this way:
I build a map. (If you don't know what is it, to put it simple it's a data structure to store couples "key-value".) In this case the keys are characters, and the values are integer counters binded to the respective character.
Everytime a character is found in a its counter increases by 1;
Everytime a character is found in b its counter decreases by 1;
Now every counter represents the diffences between number of times its character is present in a and b. So, the sum of the absolute values of the counters is the solution!
To implement it actually add an entry to map whenever I find a character for the first time, instead of pre-costructing a map with the whole alphabet. I also abused with lambda expressions, so to give you a very different sight.
Here's the code:
import java.util.HashMap;
public class HackerEarthProblemSolver {
private static final String a = //your input string
b = //your input string
static int sum = 0; //the result, must be static because lambda
public static void main (String[] args){
HashMap<Character,Integer> map = new HashMap<>(); //creating the map
for (char c: a.toCharArray()){ //for each character in a
map.computeIfPresent(c, (k,i) -> i+1); //+1 to its counter
map.computeIfAbsent(c , k -> 1); //initialize its counter to 1 (0+1)
}
for (char c: b.toCharArray()){ //for each character in b
map.computeIfPresent(c, (k,i) -> i-1); //-1 to its counter
map.computeIfAbsent(c , k -> -1); //initialize its counter to -1 (0-1)
}
map.forEach((k,i) -> sum += Math.abs(i) ); //summing the absolute values of the counters
System.out.println(sum)
}
}
Basically both solutions just counts how many letters the two strings have in common, but with different approach.
Hope I helped!

Inserting letters into a string at every possible spot [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am looking to insert a single letter one by one into every possible index of a string.
For example the string ry
Would go "ary" "bry" "cry" ... "zry" ... "ray" "rby" .... "rzy" ... "rya" "ryb"
I am not sure how to begin, any help?
Try this
System.out.println("originaltext".replaceAll(".{1}","$0ry"));
The above is using the String replaceAll(String regex, String replacement) method - "Replaces each substring of this string that matches the given regular expression with the given replacement."
".{1}" - The regular expression used to find exactly one occurrence({1}) of any character(.)
"$0ry" - The replacement string with "$0" for the matched value followed by the required characters(ry).
This is repeated for all matches!
Example Code
String originalString = /* your original string */;
char[] characters = /* array of characters you want to insert */;
Vector<String> newStrings = new Vector<>();
String newString;
for (int idx = 0; idx < originalString.length() + 1; ++idx) {
for (char ch : characters) {
newString = originalString.substring(0, idx)
+ ch
+ originalString.substring(idx, originalString.length());
newStrings.add(newString);
}
}
Explanation
Processing all cases:
In order to insert every single letter into an index in a string, you need a loop to iterate through every letter.
In order to insert a letter into every index in a string, you need a loop to iterate through every index in the string.
To do both at once, you should nest one loop inside the other. That way, every combination of an index and a character will be processed. In the problem you presented, it does not matter which loop goes inside the other--it will work either way.
(you actually have to iterate through every index in the string +1... I explain why below)
Forming the new string:
First, it is important to note the following:
What you want to do is not "insert a character into an index" but rather "insert a character between two indices". The distinction is important because you do not want to replace the previous character at that index, but rather move all characters starting at that index to the right by one index in order to make room for a new character "at that index."
This is why you must iterate through every index of the original string plus one. Because once you "insert" the character, the length of the new string is actually equal to originalString.length() + 1, i.e. there are n + 1 possible locations where you can "insert" the character.
Considering this, the way you actually form a new string (in the way you want to) is by getting everything to the left of your target index, getting everything to the right of your target index, and then concatenating them with the new character in between, e.g. leftSubstring + newCharacter + rightSubstring.
Now, it might seem that this would not work for the very first and very last index, because the leftSubstring and/or rightSubstring would be an empty string. However, string concatenation still works even with an empty string.
Notes about Example Code
characters can also be any collection that implements iterable. It does not have to be a primitive array.
characters does not have to contain primitive char elements. It may contain any type that can be concatenated with a String.
Note that the substring(int,int) method of String returns the substring including the character at beginIndex but not including the character at endIndex. One implication of this is that endIndex may be equal to string.length() without any problems.
Well you will need a loop for from i = 0 to your string's length
Then another loop for every character you want to insert - so if you want to keep creating new strings with every possible letter from A to Z make a loop from char A = 'a' to 'z' and keep increasing them ++A(this should work in java).
This should give you some ideas.
Supposing, for instance, you want them all in a list, you could do something like that (iterating all places to insert and iterating over all letters):
List<String> insertLetters(String s) {
List<String> list = new ArrayList<String>();
for (int i = 0; i <= s.length(); i++) {
String prefix = s.substring(0, i);
String postfix = s.substring(i, s.length());
for (char letter = 'a'; letter <= 'z'; letter++) {
String newString = prefix + letter + postfix;
list.add(newString);
}
}
return list;
}
String x = "ry";
char[] alphabets = "abcdefghijklmnopqrstuvwxyz".toCharArray();
String[] alphabets2 = new String[alphabets.length];
for (int i=0;i<alphabets.length;i++){
char z = alphabets[i];
alphabets2[i] = z + x;
}
for (String s: alphabets2
) {
System.out.println(s);
}
First of all you would need a Array of alphabet (Easier for you to continue).
I will not give you exact answer, but something to start, so you would learn.
int length = 0;
Arrays here
while(length <= 2) {
think what would be here: hint you put to index (length 0) the all alphabet and move to index 1 and then 2
}

The output of this loop should be less than 1, but I get very large numbers [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
This program is supposed to count the number of characters "c" and "g" in genes in the DNA string and then take that number and divide it by the length of each gene. The number of cs and gs is always < gene.length(), therefore the output should be something like 0.65555, 0.35657 etc, but I get large numbers like 141, etc. Not sure what is wrong with this loop.
public void testfile(){
String dnaTest = "aaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaacccttaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctcacccttctaact";
int counter = 0;
for(String gene : s1.data()) {
for (char cORg : gene.toCharArray()) {
if ((cORg == 'c') || (cORg == 'g')) {
counter ++;
}
System.out.print(gene +" ");
}
float cgRatioGenes = counter/gene.length();
System.out.println("cgRatio: " + cgRatioGenes);
}
}
}
If you spot the error, let me know. Thanks!
EDIT
Even without the parentesis at the end of the DNA string and with the closing bracket, the loop was not producing the results I expected. Therefore, it is not off topic.
Two problems:
First, you never reinitialize counter when you start the loop again. Move that declaration inside the loop so that each repetition starts with a counter of zero.
If you make that change, all your results will be zero though, because you're diving two integers, which will truncate the results. Cast one to float, so that it keeps the decimal part. See this question for more information on the problem
for(String gene : s1.data()) {
int counter = 0; //Moved inside the for loop, so that it always starts at 0
for (char cORg : gene.toCharArray()) {
if ((cORg == 'c') || (cORg == 'g')) {
counter ++;
}
System.out.print(gene +" ");
}
//Floating point division, instead of integer division
float cgRatioGenes = ((float)counter)/gene.length();
System.out.println("cgRatio: " + cgRatioGenes);
}
One potential problem is here
float cgRatioGenes = counter/gene.length();
As gene.length() is an integer value the ratio is not computed correctly. Instead, you should cast one of them to float like this
float cgRatioGenes = ((float)counter)/gene.length();
In addition, the counter variable should probably be initialized to zero for each gene (unless you want to count the c/g values over all genes).
This probably does not explain the behavior you are observing, but it is not possible to figure it out unless a complete working example is given.
It's a little unclear what the exact intent of this code is, but my guess is that you're using one int counter for every gene in s1.data(). I assume you want to count the number of valid characters per gene, not in the entire pool.
If you do want to count for the entire pool, the problem is that you're peforming gene.length outside of the for, which should honestly throw a compiler error unless you have a gene defined somewhere else as well.
Additionally, you're dividing two ints for your answer, which will yield an int. Case one of your variables to float to get a decimal answer.

Occurrences of a substring in a string without using string functions [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I want to know how to count the occurrences of a particular sub-string in a string without using any of the built in JAVA string functions. For example:
InputString = "knowbutuknow"
subString = "know"
The program should return the result as 2.
EDIT: Re-phrased my question. This is one of those interview questions I came across.
EDIT: Basic string functions like charAt and length can be used here.
Assuming, you already know the keyword you are searching for:
Start at char "0" of Input String
Iterate until "length - keyWordLength" (keyword of length 4 can not match into the last 3 chars)
Inside: Iterate from 0 to keyWord.length -1 and always compare:
Char at Position of outer loop PLUS position of inner loop of the Input string with the char at "inner loops" position of the keyword.
if you find a match, go ahead with the innerloop, if it does not match, advance the outer loop, by simple "breaking" the inner loop.
If you have a match, and completely processed the inner loop, you have a match of that keyword.
Something like this. I'm Assuming String.length to be allowed. Otherwhise you would need to create your own strlen function. (This can be achieved, using a forach loop and simple counting "up")
This is untested and may not work out of the box, but should give you a brief idea.
String inputString = "knowbutuknow";
String subString = "know";
int matches = 0;
for (int outer = 0; outer <= inputString.length() - subString.length(); outer++){
for (int inner = 0; inner < subString.length(); inner++){
if (inputString.charAt(outer + inner) == subString.charAt(inner)){
// letter matched, proceed.
if (inner == subString.length()-1){
//last letter matched, so a word match at position "outer"
matches++;
//proceed with outer. Room for improvement: Skip next n chars beeing
// part of the match already.
break;
}
}else{
//no match for "outer" position, proceed to next char.
break;
}
}
}
edit: Sorry, mixed in some php :) fixed it.

Java function to output every case possible in a string [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am trying to make a function that outputs every case possible of a string. The function must output each variation of a string and keep a counter for that variation. For example in no particular order:
C.d
C>d
C>D
C.D
c.d
c.D
c>D
c>d
So far I have this:
public int allCase(String data)
{
int count=0; // counter for the amount of case changes completed
int size= data.length();// length of incoming string
char c[]= data.toLowerCase().toCharArray();
double maxpos=Math.pow(2,size);
System.out.println("Maximum possibilities= "+maxpos);
for(int i=0;i<size;i++)
{
if (c[i]> 33 && c[i]<64) // if the character is special characters !##$%^&*()_<>?,./
{ // prints characters in front and behind of special character
System.out.println( data.substring(0,i)+((char)(c[i]+16))+data.substring(i+1));
}
else{
// output the string variation
}
count++;
}
return count;
}
You can handle the alphabetic characters as a group, adding or subtracting 32, but the rest of the mappings aren't regular enough to beat a table lookup.
Keep two parallel strings:
shifted = "ABCDEFGHIJKLMNOPQRSTUVWXYZ~!##$%^&*()_+|<>?:\"{}";
unshifted = "abcdefghijklmnopqrstuvwxyz`1234567890-=\,./;'[]";
Then, find each character in one or the other string with .indexOf(). Find the opposite shift at the same index in the other string. If a character isn't in either string, then it's a space or another character that isn't part of a shifted/unshifted pair. The total number of strings to generate is then 2^(number of chars found in one of those strings).
Speaking of powers of 2, using Math.pow() is a lousy way to compute small powers of 2. Use 1L<<n instead of Math.pow(n) for integers 0 <= n <= 62, or even 1<<n for 0<=n<=30 if you're able to live with only being able to print out a billion or so strings.
You can make an iterative version, looping from an index value of 0 to (2^n)-1, where n the length of the input string, and then loop for k=0 to (n-1) testing bit k of the outer loop index value to see whether to print upper or lowercase version of the character. I didn't see it before, but Hot Licks has a comment about using this approach. To perform that test, observe that index&(1<<k) is nonzero if and only if bit k is set in (index).
A recursive version is much simpler, but I suspect you'll learn about that later.

Categories