Why will this java string routine not print the answer? - java

I have been working on the Project Euler problem 4. I am new to java, and believe I have found the answer (906609 = 993 * 913, by using Excel!).
When I print the line commented out, I can that my string manipulations have worked. I've researched a few ways to compare strings in case I had not understoof something, but this routine doesn't give me a result.
Please help me identify why it is not printing the answer?
James
public class pall{
public static void main(String[] args){
int i;
int j;
long k;
String stringProd;
for(i=994;i>992; i--){
for (j=914;j>912; j--){
k=(i*j);
stringProd=String.valueOf(k);
int len=stringProd.length();
char[] forwards=new char[len];
char[] back = new char[len];
for(int l=0; l<len; l++){
forwards[l]=stringProd.charAt(l);
}
for(int m=0; m<len;m++){
back[m]=forwards[len-1-m];
}
//System.out.println(forwards);
//System.out.println(back);
if(forwards.toString().equals(back.toString())){
System.out.println(k);}
}
}
}
}

You are comparing the string representation of your array. toString() doesn't give you what you think. For example, the below code makes it clear:
char[] arr1 = {'a', 'b'};
char[] arr2 = {'a', 'b'};
System.out.println(arr1.toString() + " : " + arr2.toString());
this code prints:
[C#16f0472 : [C#18d107f
So, the string representation of both the arrays are different, even though the contents are equal. This is because arrays don't override toString() method. It inherits the Object#toString() method.
The toString method for class Object returns a string consisting of
the name of the class of which the object is an instance, the at-sign
character #, and the unsigned hexadecimal representation of the hash
code of the object. In other words, this method returns a string equal
to the value of:
getClass().getName() + '#' + Integer.toHexString(hashCode())
So, in the above output, [C is the output of char[].class.getName(), and 18d107f is the hashcode.
You can't also compare the arrays using forward.equals(back), as arrays in Java don't override equals() or hashCode() either. Any options? Yes, for comparing arrays you can use Arrays#equals(char[], char[]) method:
if (Arrays.equals(forward, back)) {
System.out.println(k);
}
Also, to get your char arrays, you don't need those loops. You can use String#toCharArray() method. And also to get the reverse of the String, you can wrap the string in a StringBuilder instance, and use it's reverse() method:
char[] forwards = stringProd.toCharArray();
char[] back = new StringBuilder(stringPod).reverse().toString().toCharArray();
And now that you have found out an easy way to reverse a string, then how about using String#equals() method directly, and resist creating those character arrays?
String stringPod = String.valueOf(k);
String reverseStringPod = new StringBuilder(stringPod).reverse().toString()
if (stringPod.equals(reverseStringPod)) {
System.out.println(k);
}
Finally, since it is about project euler, which is about speed and mostly mathematics. You should consider avoiding String utilities, and do it with general division and modulus arithmetic, to get each individual digits, from beginning and end, and compare them.

To convert a string to char[] use
char[] forward = stringProd.toCharArray();
To convert a char[] to String, use String(char[]) constructor:
String backStr = new String(back); // Not the same as back.toString()
However, this is not the most performant solution, for several reasons:
You do not need to construct a back array to check if a string is a palindrome - you can walk the string from both ends, comparing the characters as you go, until you either find a difference or your indexes meet in the middle.
Rather than constructing a new array in a loop, you could reuse the same array - in case you do want to continue with an array, you could allocate it once for the maximum length of the product k, and use it in all iterations of your loop.
You do not need to convert a number to string in order to check if it is a palindrome - you can get its digits by repeatedly taking the remainder of division by ten, and then dividing by ten to go to the next digit.
Here is an illustration of the last point:
boolean isPalindrome(int n) {
int[] digits = new int[10];
if (n < 0) n = -n;
int len = 0;
while (n != 0) {
digits[len++] = n % 10;
n /= 10;
}
// Start two indexes from the opposite sides
int left = 0, right = len-1;
// Loop until they meet in the middle
while (left < right) {
if (digits[left++] != digits[right--]) {
return false;
}
}
return true;
}

Related

How to handle the time complexity for permutation of strings during anagrams search?

I have a program that computes that whether two strings are anagrams or not.
It works fine for inputs of strings below length of 10.
When I input two strings whose lengths are equal and have lengths of more than 10 program runs and doesn't produce an answer .
My concept is that if two strings are anagrams one string must be a permutation of other string.
This program generates the all permutations from one string, and after that it checks is there any matching permutation for the other string. In this case I wanted to ignore cases.
It returns false when there is no matching string found or the comparing strings are not equal in length, otherwise returns true.
public class Anagrams {
static ArrayList<String> str = new ArrayList<>();
static boolean isAnagram(String a, String b) {
// there is no need for checking these two
// strings because their length doesn't match
if (a.length() != b.length())
return false;
Anagrams.permute(a, 0, a.length() - 1);
for (String string : Anagrams.str)
if (string.equalsIgnoreCase(b))
// returns true if there is a matching string
// for b in the permuted string list of a
return true;
// returns false if there is no matching string
// for b in the permuted string list of a
return false;
}
private static void permute(String str, int l, int r) {
if (l == r)
// adds the permuted strings to the ArrayList
Anagrams.str.add(str);
else {
for (int i = l; i <= r; i++) {
str = Anagrams.swap(str, l, i);
Anagrams.permute(str, l + 1, r);
str = Anagrams.swap(str, l, i);
}
}
}
public static String swap(String a, int i, int j) {
char temp;
char[] charArray = a.toCharArray();
temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
return String.valueOf(charArray);
}
}
1. I want to know why can't this program process larger strings
2. I want to know how to fix this problem
Can you figure it out?
To solve this problem and check whether two strings are anagrams you don't actually need to generate every single permutation of the source string and then match it against the second one. What you can do instead, is count the frequency of each character in the first string, and then verify whether the same frequency applies for the second string.
The solution above requires one pass for each string, hence Θ(n) time complexity. In addition, you need auxiliary storage for counting characters which is Θ(1) space complexity. These are asymptotically tight bounds.
you're doing it in very expensive way and the time complexity here is exponential because your'e using permutations which requires factorials and factorials grow very fast , as you're doing permutations it will take time to get the output when the input is greater than 10.
11 factorial = 39916800
12 factorial = 479001600
13 factorial = 6227020800
and so on...
So don't think you're not getting an output for big numbers you will eventually get it
If you go something like 20-30 factorial i think i will take years to produce any output , if you use loops , with recursion you will overflow the stack.
fact : 50 factorial is a number that big it is more than the number of sand grains on earth , and computer surrender when they have to deal with numbers that big.
That is why they make you include special character in passwords to make the number of permutations too big that computers will not able to crack it for years if they try every permutations , and encryption also depends on that weakness of the computers.
So you don't have to and should not do that to solve it (because computer are not good very at it), it is an overkill
why don't you take each character from one string and match it with every character of other string, it will be quadratic at in worst case.
And if you sort both the strings then you can just say
string1.equals(string2)
true means anagram
false means not anagram
and it will take linear time,except the time taken in sorting.
You can first get arrays of characters from these strings, then sort them, and then compare the two sorted arrays. This method works with both regular characters and surrogate pairs.
public static void main(String[] args) {
System.out.println(isAnagram("ABCD", "DCBA")); // true
System.out.println(isAnagram("𝗔𝗕𝗖𝗗", "𝗗𝗖𝗕𝗔")); // true
}
static boolean isAnagram(String a, String b) {
// invalid incoming data
if (a == null || b == null
|| a.length() != b.length())
return false;
char[] aArr = a.toCharArray();
char[] bArr = b.toCharArray();
Arrays.sort(aArr);
Arrays.sort(bArr);
return Arrays.equals(aArr, bArr);
}
See also: Check if one array is a subset of the other array - special case

Replacing a character in a string from another string with the same char index

I'm trying to search and reveal unknown characters in a string. Both strings are of length 12.
Example:
String s1 = "1x11222xx333";
String s2 = "111122223333"
The program should check for all unknowns in s1 represented by x|X and get the relevant chars in s2 and replace the x|X by the relevant char.
So far my code has replaced only the first x|X with the relevant char from s2 but printed duplicates for the rest of the unknowns with the char for the first x|X.
Here is my code:
String VoucherNumber = "1111x22xx333";
String VoucherRecord = "111122223333";
String testVoucher = null;
char x = 'x'|'X';
System.out.println(VoucherNumber); // including unknowns
//find x|X in the string VoucherNumber
for(int i = 0; i < VoucherNumber.length(); i++){
if (VoucherNumber.charAt(i) == x){
testVoucher = VoucherNumber.replace(VoucherNumber.charAt(i), VoucherRecord.charAt(i));
}
}
System.out.println(testVoucher); //after replacing unknowns
}
}
I am always a fan of using StringBuilders, so here's a solution using that:
private static String replaceUnknownChars(String strWithUnknownChars, String fullStr) {
StringBuilder sb = new StringBuilder(strWithUnknownChars);
while ((int index = Math.max(sb.toString().indexOf('x'), sb.toString().indexOf('X'))) != -1) {
sb.setCharAt(index, fullStr.charAt(index));
}
return sb.toString();
}
It's quite straightforward. You create a new string builder. While a x or X can still be found in the string builder (indexOf('X') != -1), get the index and setCharAt.
Your are using String.replace(char, char) the wrong way, the doc says
Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar.
So you if you have more than one character, this will replace every one with the same value.
You need to "change" only the character at a specific spot, for this, the easiest is to use the char array that you can get with String.toCharArray, from this, this is you can use the same logic.
Of course, you can use String.indexOf to find the index of a specific character
Note : char c = 'x'|'X'; will not give you the expected result. This will do a binary operation giving a value that is not the one you want.
The OR will return 1 if one of the bit is 1.
0111 1000 (x)
0101 1000 (X)
OR
0111 1000 (x)
But the result will be an integer (every numeric operation return at minimum an integer, you can find more information about that)
You have two solution here, you either use two variable (or an array) or if you can, you use String.toLowerCase an use only char c = 'x'

Converting index of string to integers

I'm attempting to convert the characters at a specific String index to an integer.
This is the function I have:
public int[] digitsOfPi(int n) {
{
String piDigits = Double.toString(Math.PI);
int[] piArray = new int[n];
for (int i = 0; i < n; i++)
{
piArray[i] = Character.digit(piDigits.charAt(i), n);;
}
return piArray;
}
}
Unfortunately, when I test this function with digitsOfPi(3), I got
[I#15db9742
Any help would be much appreciated.
Use Arrays.toString(arg)
System.out.println(Arrays.toString(digitsOfPi(3)));
... to get pretty result output like
[1, 2, 3]
What you have printed is a reference to the array, not its content. That is why I asked first about the way youre outputting the result.
Thi signature of Character.digit() is (char ch, int RADIX). So you use ternary number system or how to call it. Moreover, it returns -1 when the char ch does not contain valid number, it is your case 3.1415... is [invalid, invalid, 1]. You need to use 10 as an argument and skip 2nd position.
Or you can simply do
piArray[i] = piDigits.charAt(i) - '0';
You are using System.out.pritln(digitsOfPi(3) for getting the element at 3rd position, but actually its returning an array of int
So try to use the following code snippet, instead -
public static int digitsOfPi(int n) {
String piDigits = Double.toString(Math.PI);
char[] array = piDigits.toCharArray();
return Character.getNumericValue(array[3]);
}

Alternating string of char and int [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
when given a input string i am suppose to break it up into two groups
char
int.
with these two groups i want to create a new alternating string.
for example
abc1234defgh567jk89
will transform into
a1b2c3d5e6f7j8k9
notice that the digit 4,g,h has been discarded.
i figured that a queue can be implemented in this case.
queue1> abc
queue2> 123
index 0 to 2 is a char
index three is a int, so for queue 2 we only take in 3 values.
my question is there a more efficient data structure to perform this operation?
and during implementation, how to i compare to see if a particular value is a int or a char?
please advise.
Treating the string as an array of char integers would make this easier to compare, as you can do a simple comparision on the entry. If array[x]>64 it is a character else it is a number. You can use two pointers to do the interleaving. One for character and the other for integer. Find a character and then advance the integer pointer until it finds a match, then advance them as long as they are both true, then fast forward both of them. For example:
char array[]=(char *)string;
int letter=array[0];
int number=array[0];
// Initialize
while(number >= 64)
number++;
while (letter<64)
letter++;
//Now that the pointers are initialized, interleave them.
while(letter>=64 && number<64)
{
output[i++]=letter;
output[i++]=number;
number++;
letter++;
}
// Now you need to advance to the next batch, so you need to see the comparison false and then true again.
....
You are right, a queue is a good data structure for this problem. If, however, you want fancier methods at hand, a Linked List would be another very similar alternative.
To check if a particular value is a letter or a number, you can use the Character class. For example,
String sample = "hello1";
Character.isLetter( sample.charAt(0) ); // returns true
Character.isLetter( sample.charAt(5) ); // returns false
how to i compare to see if a particular value is a int or a char?
You can do something like this:
String string = "abc1234defgh567jk89";
for(int i=0; i<string.length;i++){
int c = (int)string.charAt(i);
boolean isChar = 97<=c&&c<=122 || 65<=c&&c<=90;
boolean isNum = 48<=c&&c<=57;
if(!isChar && !isNum){
throw new IllegalArgumentException("I don't know what you are")
}
}
About the datastructutures, personally I will use two single linked list, one for chars and one for numbers and every character will be stored in a different node. Why?, well if you store the characters (in general, I mean chars and ints) in groups of threes later you will have to add more code to split those groups and put chars and ints together, putting them in a linked list makes sense because
you can put as much nodes as you want (or memory lets you but let's assume is infinite)
data will be stored in order (which looks like some kind of requirement you have in order to display the output, also this discards trees and stacks(FILO))
since you only need to go forward when generating the output a double linked list will be over engineering.
To generate the output:
Having two datastructures let's you add another check like:
if(listChars.size() != listNums.size()){
throw new IllegalArgumentException("Wrong input!!!")
}
Additionally,
Reviewing the list will take you O(n) time, memory used will be O(n), reviewing both list will take you O(n/m) where m is the size of the initial group of chars.
You can do that like this:
Iterator<Character> iterChar = listChar.iterator();
Iterator<Integer> iterNum = listChar.iterator();
String result = "";
while(iterChar.hasNext() && iterNum.hasNext() ){
result+=iterChar.next()+iterNum.next();
}
Finally, you can use queues or linked list here both give you the same in this scenario
To check if the next char is a letter or number you can use this:
public static boolean isNumber(char c) { return c >= '0' && c <= '9'; }
public static boolean isLetter(char c) { return c >= 'a' && c <= 'z'; }
These functions find the index of the next number or letter, starting at pos i:
public static int nextNumber(String s, int i) {
while(i < s.length() && !isNumber(s.charAt(i))) i++;
return i;
}
public static int nextLetter(String s, int i) {
while(i < s.length() && !isLetter(s.charAt(i))) i++;
return i;
}
You don't really need a data structure, all you need is 3 pointers:
public static String alternate(String s){
// pointers
int start = 0, mid = 0, end = 0;
StringBuilder sb = new StringBuilder(s.length());
while(end < s.length()){
// E.g. for 'abc1234' {start, mid, end} = {0, 3, 7}
start = Math.min(nextLetter(s, end), nextNumber(s, end));
mid = Math.max(nextLetter(s, end), nextNumber(s, end));
end = Math.max(nextLetter(s, mid), nextNumber(s, mid));
for(int i = 0; i < Math.min(mid - start, end - mid); i++)
sb.append(s.charAt(start + i)).append(s.charAt(mid + i));
}
return sb.toString();
}
Running the example below outputs the desired result: a1b2c3d5e6f7j8k9
public static void main(String... args){
System.out.println(alternate("abc1234defgh567jk89"));
}

Generate all words using Java

I want to know how to generate all words using java from specified characters and length
String first[]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
String second[]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
String ch ="";
String total[];
for(int i = 0;i<26;i++) {
for(int j = 0;j<26;j++) {
ch+=first[i]+first[j];
System.out.println(ch);
}
}
I get only 576 words only by this program, but the 26! words is 4.03291461 × 10^26
How to write the program in java?
public class Words {
static char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray();
static void generate(StringBuilder sb, int n) {
if (n == sb.length()) {
System.out.println(sb.toString());
return;
}
for (char letter : alphabet) {
sb.setCharAt(n, letter);
generate(sb, n + 1);
}
}
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
for (int length = 2; length <= 5; length++) {
sb.setLength(length);
generate(sb, 0);
}
}
}
This generates all 2-letters, 3-letters, 4-letters, and 5-letters "words". It uses a standard recursive algorithm.
See also
Given an array of integers [x0 x1 x2], how do you calculate all possible permutations from [0 0 0] to [x0 x1 x2]?
On a more mathematical note, people often confuse what the term "permutation" means. Yes, there are 26! permutations of the 26 letters a-z -- that's A LOT of strings, but this does not include aa, ab, etc. It includes all strings where the 26 letters each appear exactly once.
Consider what you're doing:
you're looping through the first array once, and looping through the second once for each iteration through that loop.
That's going to yield you a total of 26^2 results, or 676 (not 576).
And the way you're constructing the output is very specific, check what you get and you'll notice a highly explicit pattern in there.
The second array of course is never used at all, so completely superfluous.
The solution is to write out on paper how you'd go about it were you to attempt it by hand, then attempt to translate that into code.
For one you're not going to want to have only words of a specific length (which you get) or specific patterns of letters (which you also get).
but the 26! words is 4.03291461 × 1026
how to write the program in java
You don't write that program in Java or any other language. It would be pointless because it would literally take billions of years to finish.
But the number is also completely wrong for your intended result in the comments. 26! is the number of permutations, i.e. the different ways to order 26 elements without repetition. The number of words would be 26^n, where n is the length.
Here's my solution. It's kind of quick, so don't be too hard on the optimization.
public static void printWords(int length) {
if (length < 1)
throw new IllegalArgumentException();
printWordsRec("", length);
}
private static void printWordsRec(String base, int length) {
for (char c = 'a'; c <= 'z'; c++) {
if (length == 1) {
System.out.println(base + c);
}
else {
printWordsRec(base + c, length - 1);
}
}
}

Categories