I have been trying to reduce the length of the way. I represent some integer ID's in my program. For Example
2
3
15
26
63
...
151564852
I would like them to be represented as such (0-9A-Za-z only)
2
3
F
Q
z
...
vDF25a //For example
The approach I thought of is to have 63 if statements which each of the mappings from 0-63 to 0-z respectively and for anything above 64 do a recursion on the value minus 63.
Needless to say, I think my approach is very flawed and impractical. What would be a more appropriate way of doing it?
Update:
Following fge's suggestion I've got the encoder to work correctly, however my decode function only works for up-to length 2 strings, in cases where the string is larger the sum becomes erroneous. For example for 3840 to 3845 this is the output
// Encoded
zw
x
zy
zz
100
// Decoded
3840
3841
3842
3843
124 //Invalid decoding
Here is my code for the decode function
public static int decode(String value)
{
String revStr = new StringBuilder(value).reverse().toString();
int sum = 0;
for (int i=1; i < revStr.length(); i++)
{
for (int j=0; j < ALPHABET.length; j++)
{
if (ALPHABET[j] == revStr.charAt(i))
{
sum += (ALPHABET.length * j) * i;
break;
}
}
}
for (int j=0; j < ALPHABET.length; j++)
{
if (ALPHABET[j] == revStr.charAt(0))
{
sum += j;
break;
}
}
return sum;
}
This is not base64; base64 encodes binary data.
Anyway, you don't need a s*load of if statements; use an array:
public final class AlphabetEncoder
{
private static final char[] ALPHABET = { '0', '1', '2', ...., 'z' };
private static final int ENCODE_LENGTH = ALPHABET.length;
public static String encode(int victim)
{
final List<Character> list = new ArrayList<>();
do {
list.add(ALPHABET[victim % ENCODE_LENGTH]);
victim /= ENCODE_LENGTH;
} while (victim > 0);
Collections.reverse(list);
return new String(list.toArray(new char[list.size()],
StandardCharsets.UTF_8);
}
public int decode(final String encoded)
{
int ret = 0;
char c;
for (int index = 0; index < encoded.length(); index++) {
c = encoded.charAt(index);
ret *= ENCODE_LENGTH;
ret += Arrays.binarySearch(ALPHABET, c);
}
return ret;
}
}
NOTE ABOUT THE DECODE FUNCTION: it is possible to use Arrays.binarySearch() here since the alphabet has the nice property of being naturally sorted (0 < 1 < 2 < ... < z). However, a test should probably be added that its return code not be negative!
Depending on the language you use, there should already be a module which converts a string from/to base64.
Check this other post: Base64 Encoding in Java
You can refer to already existing logic for converting from Decimal [0-9] to Hexadecimal conversion present in Integer class and extend the logic for your Base 64 converison. Refer
Integer.toHexString(int i)
This maybe the efficient implementation for conversion.
My thanks to the #fge answer.
Using it with some changes I've get it to support much larger integers with BigInteger, added support of negative integers and changed Arrays.binarySearch() with HashMap.
BTW, it should be called base62 encoding because [0-9A-Za-z] contains just 62 chars.
public class Base62{
private static final char[] ALPHABET = new char[ 62 ];
private static final Map<Character, Integer> ALPHABET_MAPPING = new HashMap<>();
private static final BigInteger ENCODE_LENGTH = BigInteger.valueOf( ALPHABET.length );
static{
int position = 0;
// numbers
for( int i = 48; i <= 57; i++ ){
ALPHABET[ position++ ] = (char)i;
}
// uppercase letters
for( int i = 65; i <= 90; i++ ){
ALPHABET[ position++ ] = (char)i;
}
// lowercase letters
for( int i = 97; i <= 122; i++ ){
ALPHABET[ position++ ] = (char)i;
}
for( int i = 0; i < ALPHABET.length; i++ ){
ALPHABET_MAPPING.put( ALPHABET[ i ], i );
}
}
public static String encode( final BigInteger in ){
final List<Character> list = new ArrayList<>();
boolean negative = in.signum() == -1;
BigInteger use;
if( negative ){
use = in.negate();
} else {
use = in;
}
do{
BigInteger[] divisionResultAndReminder = use.divideAndRemainder( ENCODE_LENGTH );
list.add( ALPHABET[ divisionResultAndReminder[ 1 ].intValue() ] );
use = divisionResultAndReminder[ 0 ];
} while( use.equals( BigInteger.ZERO ) == false );
Collections.reverse( list );
char[] res = new char[ list.size() ];
for( int i = 0; i < list.size(); i++ ){
res[ i ] = list.get( i );
}
return ( negative ? "-" : "" ) + new String( res );
}
public static BigInteger decode( final String encoded ){
BigInteger res = BigInteger.ZERO;
char c;
boolean negative;
String use;
if( '-' == encoded.charAt( 0 ) ){
negative = true;
use = encoded.substring( 1 );
} else {
negative = false;
use = encoded;
}
for( int index = 0; index < use.length(); index++ ){
c = use.charAt( index );
res = res.multiply( ENCODE_LENGTH );
res = res.add( BigInteger.valueOf( ALPHABET_MAPPING.get( c ) ) );
}
return negative ? res.negate() : res;
}
}
Related
I'm just having a hard time grasping this concept.
each char has a different ASCII value, so how do i grab the lowest value or the highest value?
and if i passed an empty string to my method for all of this min() would just get thrown an error or would it return a 0?
i wrote a test driver that should pass if my min method returns w as the minimum, which is just a stub method right now, character in that string.
final String PASS = "Pass";
final String FAIL = "Fail";
L05A lab5 = new L05A();
int testNum = 1;
String tst = ""; // test empty string
String result = FAIL;
System.out.println("\nTesting min\n");
tst = "";
char ch = lab5.min(tst);
result = (ch == '!') ? PASS : FAIL;
System.out.println(testNum + ": " + result);
++testNum;
tst = "zyxw"; //would return w?
ch = lab5.min(tst);
result = (ch == 'w') ? PASS : FAIL;
System.out.println(testNum + ": " + result);
++testNum;
So how would i scan that string i pass to return the smallest char?
At first i thought i could use str.charAt(0); but silly me, that just returns the first index of the string, so i'm very confused! Any help would be great to develop this min method
I SHOULD SPECIFY THAT WE ARE NOT USING ANY FORM OF ARRAYS[] ON THIS ASSIGNMENT
UNFORTUNATELY.. :(
It's pretty simple:
Convert the string to a char array using String.toCharArray
Convert the array to a Collection<Character>
Pass the collection to Collections.min and max from java.util.Collections
For example:
String test = "test";
List<Character> strArr = new ArrayList<Character>(test.length());
for (char c : test.toCharArray()) strArr.add(c);
System.out.println(Collections.min(strArr)); // prints "e"
EDIT Ok, so now you say you can't use Arrays, so you just do this instead:
String test = "test";
char[] chars = test.toCharArray();
char max = Character.MIN_VALUE;
char min = Character.MAX_VALUE;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
max = max > c ? max : c;
min = min < c ? min : c;
}
System.out.println(min);
And, finally, if you can't use an array (like char[]) then you just drop the toCharArray call, and start the loop like this:
for (int i = 0; i < test.length(); i++) {
char c = test.charAt(i);
get char array out of string
iterate over it
define temp int variable assign to 0
compare ASCII of char to temp var and assign temp var to ascii if temp var is smaller/bigger(based on min max value you need from that function)
once the loop is over, you have what you want in that temp var
You should sort the array first:
Arrays.sort(arr);
Then your minimum value will be its first element:
int minimum = arr[0];
Do note that Arrays.sort does sorting in-place and returns nothing.
I expect there is a utility class which will do this for you, but what you could do is call toCharArray on the string, iterate over the array it returns and look for the smallest char (char is effectively a number so comparisons like < > <= >= etc will work on it)
edit:
String foo = "ksbvs";
final char[] chars = foo.toCharArray();
// create a variable to bung the smallest char in
// iterate over the array chars
// compare the current char to the smallest char you have seen so far, update if it's smaller
public class TestCharASCIIValue {
public static void main(String[] args) {
String slogan = "Programming Java Makes me go nutts"; // The String under test
int maxASCII = 0; // As minimum value for a character in ASCII is 0.
int minACSII = 255; // As maximum value for a character in ASCII is 255
int stringLength = slogan.length();
for(int i =0; i < stringLength; i++) {
int tempASCII = slogan.codePointAt(i);
if(tempASCII > maxASCII)
maxASCII = tempASCII;
else if (tempASCII < minACSII)
minACSII = tempASCII;
}
System.out.println("Max : " + maxASCII + " MIN : " + minACSII);
char maxChar = (char)maxASCII;
char minChar = (char) minACSII;
System.out.println("MaxChar : "+maxChar +"\t MinChar : " + minChar);
}
}
OUTPUT :
Max : 118 MIN : 32
MaxChar : v MinChar : (blank space)
EDIT : As per your Query, If you want to test only for max or min valued char then you can use this.
public class TestCharASCIIValue {
public static void main(String[] args) {
String slogan = "Programming Java Makes me go nutts";
char maxChar = (char)getMaxChar(slogan);
char minChar = (char)getMinChar(slogan);
System.out.println("MaxChar : "+maxChar +"\t MinChar : " + minChar);
}
private static int getMaxChar(String testString) {
int maxASCII = 0;
int stringLength = testString.length();
if(stringLength == 0) {
return -1;
}
for(int i =0; i < stringLength; i++) {
int tempASCII = testString.codePointAt(i);
if(tempASCII > maxASCII)
maxASCII = tempASCII;
}
return maxASCII;
}
private static int getMinChar(String testString) {
int minASCII = 255;
int stringLength = testString.length();
if(stringLength == 0) {
return -1;
}
for(int i =0; i < stringLength; i++) {
int tempASCII = testString.codePointAt(i);
if(tempASCII < minASCII)
minASCII = tempASCII;
}
return minASCII;
}
}
String something = "123e45,j, _122";
int length = something.length();
String result = "";
for (int i = 0; i < length; i++) {
Character character = something.charAt(i);
if (Character.isDigit(character)) {
result += character;
}
}
// out.println("result is:"+result);
Here I'm getting value in resut as:12345122 but I need to calculate sum of all values ,that is 20.
Change type of result to int.
Parse the char to an integer. If you only cast the char to an integer, you add the ascii value of this character to your result.
String something = "123e45,j, _122";
int length = something.length();
int result = 0;
for (int i = 0; i < length; i++) {
Character character = something.charAt(i);
if (Character.isDigit(character)) {
result += Character.getNumericValue(character);
}
}
System.out.println("result is: "+result);
Output: result is: 20
you can use regex like this :
public static void main(String[] args) {
String s = "123e45,j, _122";
int val = 0;
Pattern p = Pattern.compile("\\d"); // match single digit
Matcher m = p.matcher(s);
while (m.find()) { // for all digits
val = val + Integer.parseInt(m.group()); // covert each String (digit) into numeric value and add to count
}
System.out.println(val);
}
O/P :
20
You could stay with your loop and use StringUtils.isNumeric()
String something = "123e45,j, _122";
int length = something.length();
int sum=0;
for (int i = 0; i < length; i++) {
Character character = something.charAt(i);
if (Character.isDigit(character)) {
sum+= Integer.parseInt( Character.toString(character) );
}
}
// out.println("result is:"+sum);
This works. sum is an integer now you can use it to perform calculations or you can parse it to String again with: String result = String.valueOf(sum);
While the solutions of others will get you the desired result with the help of some libraries and wrappers, but I think once you get what happens in this piece of code, your basic understanding of the other code pieces increases as well.
int sumString(String some) {
int sum = 0;
for (int i = 0; i < some.length(); i++)
sum += (some.charAt(i) >= '0' && some.charAt(i) <= '9') ? (some.charAt(i) - '0') : 0;
return sum;
}
In short: for every index of the string, check of the character is numeric by checking if the character value is between 0 and 9. If it is, convert it into its integer value by subtracting the ASCII value of 0 (0 = 48 and 9 = 57, and if we subtract 48 to 48, you get 0, and 57 - 48 = 9)
I have an array of characters:
a b c x y d e f x y a b c t r e a b c
How can I find repetitive patterns of sizes 2 onwards?
The array needs to be traversed from the end. In the example I need to find patterns b c, a b, x y and patterns of sizes 3: a b c and x y z. Along with the indices of matching chars.
So far I have tried to traverse the array backwards and find patterns:
for (int size = 2; size < aLT.size(); size++) {
for (int i = aLT.size() - 1; i >= 0; i--) {
// code here
}
}
This will do the job, you can change the patternSize variable to whatever value you want (well lesser than the size of the input string) :
It takes advantage of the String#contains() method looking for sub sequences of the first String.
public static void main(String[] args) {
int patternSize=4;
String input = "abcxydefxyabctreabcabcx";
Set<String> patterns = new TreeSet<String>();
// test size n patterns
for (int i=0; i<input.length()-patternSize; i++){
String pattern = (String) input.subSequence(i, i+patternSize);
String tester="";
if (i>0 && i<input.length()-patternSize-1)
tester = input.substring(0,i)+input.substring(i+patternSize);
else if (i==0)
tester = input.substring(i+patternSize);
else if (i==input.length()-patternSize-1)
tester = input.substring(0,i);
if (tester.contains(pattern)){
patterns.add(pattern);
}
}
System.out.println("Size "+patternSize+" patterns finder");
for(String aPattern : patterns){
System.out.println("The pattern "+aPattern+" was found several times");
}
}
int n = 2; // in your case 2 and 3
Map<String, List<Integer>> matches = new HashMap<String, List<Integer>>();
String charsString = new String( chars );
String current = null;
String rest = null;
for( int i = chars.length - n; i >= 0; i-- ) {
current = charsString.substring( i, i + n );
rest = charsString.substring( 0, i );
int index = rest.indexOf( current );
if( index > -1 ) {
if( matches.containsKey( current ) ) {
continue;
}
List<Integer> indices = new ArrayList<Integer>();
indices.add( i );
while( index > -1 ) {
indices.add( index );
index = rest.indexOf( current, index + 1 );
}
matches.put( current, indices );
}
}
// print the results
for( Entry<String, List<Integer>> match : matches.entrySet() ) {
System.out.println( match.getKey() + " with indices: " + match.getValue() );
}
And the output is:
ab with indices: [16, 0, 10]
bc with indices: [17, 1, 11]
xy with indices: [8, 3]
Here is a method that does what you want to do. All you have to do if you want tofind patterns of different sizes if change patternSize and the strings that are added to the set. At the moment I have it returning a count of the amount of matches but you can easily modify it to return something else such as indices of where the matches begin or a Boolean of whether there are any matches or not.
public static int findPatterns(char[] charArray) {
int patternSize = 2;
Set<String> patterns = new HashSet<>();
patterns.add("bc");
patterns.add("ab");
patterns.add("xy");
int count = 0;
if (charArray.length < patternSize) {
return 0;
}
for (int i = 0; i < charArray.length - patternSize + 1; i++) {
String pattern = "";
for (int j = i; j < i + patternSize; j++) {
pattern += charArray[j];
}
if (patterns.contains(pattern)) {
count++;
}
}
return count;
}
I am comparing two strings, in Java, to see how many characters from the first string show up in the second string. The following is some expectations:
matchingChars("AC", "BA") → 1
matchingChars("ABBA", "B") → 2
matchingChars("B", "ABBA") → 1
My approach is as follows:
public int matchingChars(String str1, String str2) {
int count = 0;
for (int a = 0; a < str1.length(); a++)
{
for (int b = 0; b < str2.length(); b++)
{ char str1Char = str1.charAt(a);
char str2Char = str2.charAt(b);
if (str1Char == str2Char)
{ count++;
str1 = str1.replace(str1Char, '0');
}
}
}
return count;
}
I know my approach is not the best, but I think it should do it. However, for
matchingChars("ABBA", "B") → 2
My code yields "1" instead of "2". Does anyone have any suggestion or advice? Thank you very much.
Assuming that comparing "AABBB" with "AAAABBBCCC" should return 15 (2*3 + 3*3 + 0*3) then:
For each string make a Map from the character of the string to the count of characters.
Compute the intersection of the keysets for the two maps.
For each element in the keyset accumulate the product of the values. Print the result.
This is linear in the size of the two strings.
Is it ok to supply working code on homework problems?
public long testStringCount() {
String a = "AABBBCCC";
String b = "AAABBBDDDDD";
Map<Character,Integer> aMap = mapIt(a);
Map<Character,Integer> bMap = mapIt(b);
Set<Character> chars = Sets.newHashSet(aMap.keySet());
chars.addAll(bMap.keySet());
long result = 0;
for (Character c : chars) {
Integer ac = aMap.get(c);
Integer bc = bMap.get(c);
if (null != ac && null != bc) {
result += ac*bc;
}
}
return result;
}
private Map<Character, Integer> mapIt(String a) {
Map<Character,Integer> result = Maps.newHashMap();
for (int i = 0; i < a.length(); i++) {
Character c = a.charAt(i);
Integer x = result.get(c);
if (null == x) {
x = 0;
}
x++;
result.put(c, x);
}
return result;
}
Clearly you have to make sure you only count unique characters from string 1. You're double-counting B because you're counting B's twice, once for each occurrence in string 1.
Well your code is only showing 1 because of this line:
str1 = str1.replace(str1Char, '0');
That's turning "ABBA" into "A00A" - so the second B doesn't get seen.
Perhaps you should turn the second string into a HashSet<Character> instead... then you could just use something like:
int count = 0;
for (int i = 0; i < str1.length; i++)
{
if (otherSet.contains(str1.charAt(i))
{
count++;
}
}
It's not clear what result you want to get from "ABBA" / "CBCB" - if it's 2 (because there are 2 Bs) then the above approach will work. If it's 4 (because each of the 2 Bs in the first string matches 2 Bs in the second string) then all you need to do is get rid of your replace call.
EDIT: With the clarifications, it sounds like you could just do this:
for (int a = 0; a < str1.length(); a++)
{
for (int b = 0; b < str2.length(); b++)
{
if (str1.charAt(a) == str2.charAt(b))
{
count++;
// Terminate the inner loop which is iterating over str2,
// and move on to the next character in str1
break;
}
}
}
Your solution works, but is quadratic. If all characters are below 256, then you can do something like this:
int matching(String s1, String s2) {
int[] count1 = frequencies(s1);
int[] count2 = frequencies(s2);
sum = 0;
for(int i = 0; i< 256; i++) {
sum += count1[i]*count2[i] != 0 ? Math.max(count1[i], count2[i]) : 0;
}
return sum;
}
int[] frequencies(String s) {
int[] ret = new int[256];
for(char c : s) {
int[c]+=1;
}
}
Otherwise, you'll need a multiset.
I'm having a bit of trouble, mainly because I do not have much experience with recursive methods and a non-recursive method for my problem seems incredibly complex. However, I might just be looking at this the wrong way.
What I'm trying to accomplish is this:
Given one string, I want to overlap them and display all potential combinations. It's probably easiest if I explain my problem and solution with binary representations.
Given 0000 and 1111,
I want my method to return:
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
This seems incredibly trivial, but I just can't seem to figure out the most efficient way of doing this. I was thinking either recursion or maybe a binary tree. Either way, I'm having trouble setting it up.
Any ideas would be greatly appreciated.
Thank you!
Poor, but passable iterative approach.
import java.util.BitSet;
public class p {
static StringBuilder sb;
// Add one and return true on overflow
static boolean inc( BitSet s, int maxlen ) {
int i = 0;
for( ; i < maxlen; ++i ) {
if( s.get( i )) { s.clear( i ); }
else { break; }
}
if( i == maxlen )
return true;
s.set( i );
return false;
}
static String form( String x, String y, BitSet mask ) {
sb.setLength( 0 );
for( int i = 0; i < x.length(); ++i )
sb.append( (mask.get( x.length() - i - 1) ? y : x).charAt( i ));
return sb.toString();
}
public static void perms( String x, String y ) {
assert( x.length() == y.length() );
BitSet bits = new BitSet( x.length() );
do {
System.out.println( form( x, y, bits ));
} while( ! inc( bits, x.length() ));
}
public static void main( String[] args ) {
sb = new StringBuilder( args[0].length() );
perms( args[0], args[1] );
}
}
Your binary explanation actually gave me a very good idea for doing this. You can simply use a for loop and increment the variable until it is 2 ^ str.Length * 2 - 1. In each iteration, one permutation is the characters from the first string where the corresponding bit in the variable is 0, or from the second string where it is 1. Pseudo-code:
for i = 0 to 2 ^ string1.length * 2 - 1
s = ""
for j = 0 to string1.length - 1
if (i >> j) & 1 == 1 then
s = string1[string1.length - j] + s
else
s = string2[string2.length - j] + s
end if
end for
end for
You want this:
/*************************************************************************
* Compilation: javac Permutations.java
* Execution: java Permutations N
*
* Enumerates all permutations on N elements.
* Two different approaches are included.
*
* % java Permutations 3
* abc
* acb
* bac
* bca
* cab
* cba
*
*************************************************************************/
public class Permutations {
// print N! permutation of the characters of the string s (in order)
public static void perm1(String s) { perm1("", s); }
private static void perm1(String prefix, String s) {
int N = s.length();
if (N == 0) System.out.println(prefix);
else {
for (int i = 0; i < N; i++)
perm1(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
}
}
// print N! permutation of the elements of array a (not in order)
public static void perm2(String s) {
int N = s.length();
char[] a = new char[N];
for (int i = 0; i < N; i++)
a[i] = s.charAt(i);
perm2(a, N);
}
private static void perm2(char[] a, int n) {
if (n == 1) {
System.out.println(a);
return;
}
for (int i = 0; i < n; i++) {
swap(a, i, n-1);
perm2(a, n-1);
swap(a, i, n-1);
}
}
// swap the characters at indices i and j
private static void swap(char[] a, int i, int j) {
char c;
c = a[i]; a[i] = a[j]; a[j] = c;
}
public static void main(String[] args) {
int N = Integer.parseInt(args[0]);
String alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String elements = alphabet.substring(0, N);
perm1(elements);
System.out.println();
perm2(elements);
}
}
Just for laughs, a very inefficient recursive solution:
import java.util.ArrayList;
public class pp {
static ArrayList<String> append(
String x, String y, ArrayList<String> ss ) {
if( x.length() == 0 )
return ss;
ArrayList<String> r = new ArrayList<String>( ss.size() * 2);
for( int i = 0; i < ss.size(); ++i ) {
r.add( ss.get( i ) + x.charAt( 0 ));
r.add( ss.get( i ) + y.charAt( 0 ));
}
return append( x.substring(1), y.substring(1), r );
}
public static void main( String[] args ) {
assert args[0].length() == args[1].length();
ArrayList<String> ss = new ArrayList<String>( 1 );
ss.add( "" );
ArrayList<String> r = append( args[0], args[1], ss );
for( int i = 0; i < r.size(); ++i )
System.out.println( r.get( i ));
}
}