I want to convert binary to decimals and characters like this:
11010 --> 1101 + 0(parity bit) -->decimals= 11 --> char ";"
10101 --> 1010 + 1 -->decimals= 5 --> char "5"
.
.
public class stringek {
String bitek = "1101010101001000001000001";
String[] bits;
String four;
char par;
int parity;
String digits;
int n = 0;
int b;
int kurens;
int decimalis;
int digit;
public stringek() {
this.kurens = 0;
bits = new String[200];
for (int i = 0; i < 25; i += 5) {
bits[n] = bitek.substring(i, i + 5);
n++;
}
for (int i = 0; i < n; ++i) {
int j = 0;
four = bits[i].substring(j, j + 4);
for (int p = 0; p < 4; ++p) {
b = Integer.parseInt(four.substring(p));
kurens += b;
}
par = bits[i].charAt(j+4);
//System.out.print(par);
parity = par-'0';
decimalis = Integer.parseInt(four, 2);
digit = decimalis + 48;
if ((kurens + parity) % 2 == 0) {
System.out.println("Binarys: "+four+"-"+par+" = "+"'"+(char)digit+"'"+" Decimalis:"+decimalis+" Parity <INVALID> ");
}
else{
System.out.println("Binarys: "+four+"-"+par+" = "+"'"+(char)digit+"'"+" Decimalis:"+decimalis+" Parity <VALID> ");
}
}
}
}
but my program results this:
Binarys: 1101-0 = '=' Decimalis:13 Parity <INVALID>
Binarys: 1010-1 = ':' Decimalis:10 Parity <VALID>
Binarys: 0010-0 = '2' Decimalis:2 Parity <INVALID>
Binarys: 0001-0 = '1' Decimalis:1 Parity <INVALID>
Binarys: 0000-1 = '0' Decimalis:0 Parity <VALID>
Can anyone help me to resolve? I have to say cause in my case all Parity is VALID, but I don't know why here some Parity is Invalid (I know cause the results from if give me this results, but I want to know how to resolve to be VALID when is valid and INVALID when is really invalid). thanks
public String[] splitStringEvery(String s, int interval) {
int arrayLength = (int) Math.ceil(((s.length() / (double)interval)));
String[] result = new String[arrayLength];
int j = 0;
int lastIndex = result.length - 1;
for (int i = 0; i < lastIndex; i++) {
result[i] = s.substring(j, j + interval);
j += interval;
} //Add the last bit
result[lastIndex] = s.substring(j);
return result;
}
You wouldn't use String.split() or a StringTokenizer
Use a for loop that increments by 5, checking against length of your string
Use String.substring() to extract the 5 character strings.
To compute the length of the target array you need, you'll need to divide your string length by 5. A Better idea is to use a List<String>.
Use the Guava Libraries Splitter object, specifically the fixedLength(...) method which does exactly what you're trying to do.
Splitter splitter = Splitter.fixedLength(5);
Iterable<String> tokens= splitter.split(myVeryLongString);
Related
My task is to generates all possible combinations of that rows without the hidden # number sign. The input is XOXX#OO#XO and here is the example of what the output should be:
XOXXOOOOXO
XOXXOOOXXO
XOXXXOOOXO
XOXXXOOXXO
I am only allowed to solve this solution iteratively and I am not sure how to fix this and have been working on this code for a week now.
Here is my code:
import java.lang.Math;
public class help {
public static void main(String[] args) {
String str = new String("XOXX#OO#XO");
UnHide(str);
}
public static void UnHide(String str) {
//converting string to char
char[] chArr = str.toCharArray();
//finding all combinations for XO
char[] xo = new char[]{'X', 'O'};
int count = 0;
char perm = 0;
String s = "";
//finding amount of times '#' appears in string
for (int i = 0; i < str.length(); i++) {
if (chArr[i] == '#')
count++;
}
int[] combo = new int[count];
int pMax = xo.length;
while (combo[0] < pMax) {
// print the current permutation
for (int k = 0; k < count; k++) {
//print each character
//System.out.print(xo[combo[i]]);
perm = xo[combo[k]];
s = String.valueOf(perm);
char[] xoArr = s.toCharArray();
String strChar = new String(xoArr);
//substituting '#' to XO combo
for (int i = 0; i < chArr.length; i++) {
for (int j = 0; j < s.length(); j++) {
if (chArr[i] == '#') {
chArr[i] = xoArr[j];
strChar = String.copyValueOf(chArr);
i++;
}
}
i++;
if (i == chArr.length - 1) {
System.out.println(strChar);
i = 0;
}
}
}
System.out.println(); //print end of line
// increment combo
combo[count - 1]++; // increment the last index
//// if increment overflows
for (int i = count - 1; combo[i] == pMax && i > 0; i--) {
combo[i - 1]++; // increment previous index
combo[i] = 0; // set current index to zero
}
}
}
}
Since your input has 2 #'s, there are 2n = 4 permutations.
If you count from 0 to 3, and look at the numbers in binary, you get 00, 01, 10, and 11, so if you use that, inserting O for 0 and X for 1, you can do this using simple loops.
public static void unHide(String str) {
int count = 0;
for (int i = 0; i < str.length(); i++)
if (str.charAt(i) == '#')
count++;
if (count > 30)
throw new IllegalArgumentException("Too many #'s found. " + count + " > 30");
char[] buf = str.toCharArray();
for (int permutation = 0, end = 1 << count; permutation < end; permutation++) {
for (int i = buf.length - 1, bit = 0; i >= 0; i--)
if (str.charAt(i) == '#')
buf[i] = "OX".charAt(permutation >>> bit++ & 1);
System.out.println(buf);
}
}
Test
unHide("XOXX#OO#XO");
Output
XOXXOOOOXO
XOXXOOOXXO
XOXXXOOOXO
XOXXXOOXXO
You can iteratively generate all possible combinations of strings using streams as follows:
public static String[] unHide(String str) {
// an array of substrings around a 'number sign'
String[] arr = str.split("#", -1);
// an array of possible combinations
return IntStream
// iterate over array indices
.range(0, arr.length)
// append each substring with possible
// combinations, except the last one
// return Stream<String[]>
.mapToObj(i -> i < arr.length - 1 ?
new String[]{arr[i] + "O", arr[i] + "X"} :
new String[]{arr[i]})
// reduce stream of arrays to a single array
// by sequentially multiplying array pairs
.reduce((arr1, arr2) -> Arrays.stream(arr1)
.flatMap(str1 -> Arrays.stream(arr2)
.map(str2 -> str1 + str2))
.toArray(String[]::new))
.orElse(null);
}
// output to the markdown table
public static void main(String[] args) {
String[] tests = {"XOXX#OOXO", "XOXX#OO#XO", "#XOXX#OOXO#", "XO#XX#OO#XO"};
String header = String.join("</pre> | <pre>", tests);
String matrices = Arrays.stream(tests)
.map(test -> unHide(test))
.map(arr -> String.join("<br>", arr))
.collect(Collectors.joining("</pre> | <pre>"));
System.out.println("| <pre>" + header + "</pre> |");
System.out.println("|---|---|---|---|");
System.out.println("| <pre>" + matrices + "</pre> |");
}
XOXX#OOXO
XOXX#OO#XO
#XOXX#OOXO#
XO#XX#OO#XO
XOXXOOOXOXOXXXOOXO
XOXXOOOOXOXOXXOOOXXOXOXXXOOOXOXOXXXOOXXO
OXOXXOOOXOOOXOXXOOOXOXOXOXXXOOXOOOXOXXXOOXOXXXOXXOOOXOOXXOXXOOOXOXXXOXXXOOXOOXXOXXXOOXOX
XOOXXOOOOXOXOOXXOOOXXOXOOXXXOOOXOXOOXXXOOXXOXOXXXOOOOXOXOXXXOOOXXOXOXXXXOOOXOXOXXXXOOXXO
The process would probably be best to calculate the number of permutations, then loop through each to define what combination of characters to use.
For that, we'll have to divide the permutation number by some value related to the index of the character we're replacing, which will serve as the index of the character to swap it to.
public static void test(String word) {
// Should be defined in class (outside method)
String[] replaceChars = {"O", "X"};
char replCharacter = '#';
String temp;
int charIndex;
int numReplaceable = 0;
// Count the number of chars to replace
for (char c : word.toCharArray())
if (c == replCharacter)
numReplaceable++;
int totalPermutations = (int) Math.pow(replaceChars.length, numReplaceable);
// For all permutations:
for (int permNum = 0; permNum < totalPermutations; permNum++) {
temp = word;
// For each replacement character in the word:
for (int n = 0; n < numReplaceable; n++) {
// Calculate the character to swap the nth replacement char to
charIndex = permNum / (int) (Math.pow(replaceChars.length, n))
% replaceChars.length;
temp = temp.replaceFirst(
replCharacter + "", replaceChars[charIndex]);
}
System.out.println(temp);
}
}
Which can produces:
java Test "#TEST#"
OTESTO
XTESTO
OTESTX
XTESTX
This can also be used with any number of characters, just add more to replaceChars.
So say I have to shift the word banana 2 characters to the right, so that it becomes nabana - index 0 becomes 2, index 1 becomes 3 ... index 4 becomes 0 and index 5 becomes 1, etc.
So, the formula is:
(i + shiftControl) % length
I coded this in the following way:
public static String shiftString(String s, int n) {
String newWord = "";
for(int i = 0; i < s.length(); i++) {
int index = (s.charAt(i) + n) % (s.length());
newWord += s.charAt(index);
}
return newWord;
}
The issue is, I don't get nabana, I get ananan instead - I don't know where b went!
So I tried with abcdef, then I get defabc. It's only one behind. So I added n+1 instead of n, then it works, but it doesn't for banana.
The logic is the same, but why don't I get the right answer for banana?
When you say the formula is:
(i + shiftControl) % length
This is correct for determining the index of the character at position i in the original string in the shifted string. To use this you have to be able to index into the shifted string, i.e. use a char array:
public static String shiftString(String s, int n) {
char[] newWord = new char[s.length()];
for (int i = 0; i < s.length(); i++) {
int index = (i + n) % s.length();
newWord[index] = s.charAt(i);
}
return String.valueOf(newWord);
}
However, if you want to build the shifted string from left to right you need to use the reverse formula, which is
(i + length - n) % length
Which we can use in your original method:
public static String shiftString(String s, int n) {
String newWord = "";
for (int i = 0; i < s.length(); i++) {
int index = (i + s.length() - n) % s.length();
newWord += s.charAt(index);
}
return newWord;
}
An alternative would be to just join together the right and left substrings in reverse order:
public static String shiftString(String s, int n)
{
return s.substring(s.length()-n) + s.substring(0, s.length()-n);
}
You can shift the word banana by the position
public static String shiftString(String str, int shift) {
int len = str.length();
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
chars[(i + shift) % len] = str.charAt(i);
}
return new String(chars);
}
, main
public static void main(String[] args) {
System.out.println(shiftString("banana", 1));
System.out.println(shiftString("banana", 2));
System.out.println(shiftString("banana", 3));
System.out.println(shiftString("banana", 4));
System.out.println(shiftString("banana", 5));
}
, output
abanan
nabana
anaban
nanaba
ananab
change the fourth line to:
int index = (i + n) % (s.length()-n);
I want to compare every letter on file 2 with file 1.
example :
file 1 : my name
file 2 : mi n#mes
i want to get the number of difference is 3, on file 2 : (i, #,and s).
Can you help me
Here is my code
public float getCER(String originalteks,String extractteks){
int end=0;
int start=0;
int different_char=0;
if(originalteks.length()!=extractteks.length()){
different_char=Math.abs(originalteks.length()-extractteks.length());
}
while(start<end){
if(originalteks.charAt(start)!=originalteks.charAt(start++))
different_char++;//jumlah diferent chart
}
return (float) different_char/originalteks.length();
}
And it's only counting the number of characters, not the different characters.
The following implementation tests for the total difference you need and is able to handle strings with different length, by comparing the shorter string to each substring of the longer up to the maximum offset of their difference. From those differences the smallest is chosen. Of course, if handleOffset is false, then we limit ourselves to only the start of the string and adding the difference to the result;
public int getCER(String originalteks,String extractteks, boolean handleOffset){
String shorter = originalteks;
String longer = extractteks;
if (shorter.length() > longer.length()) {
shorter = extractteks;
longer = originalteks;
}
int[] differences = new int[handleOffset ? (longer.length() - shorter.length + 1) : 1];
for (int i = 0; i < differences.length; i++) differences[i] = 0;
for (int i = 0; i < minLength; i++) {
for (j = 0; j < differences.length; j++) {
if (shorter.charAt(i) !== longer.charAt(i + j)) {
differences[j]++;
}
}
}
int min = shorter.length() + 1;
for (int i = 0; i < differences.length; i++) {
if (differences[i] < min) min = differences[i];
}
if (!handleOffset) min += longer.length() - shorter.length();
return min;
}
This should work for you. I just comment my changes within the example.
public int getCER(String originalteks,String extractteks){
int end;
int different_char=0;
//define the shorter end
if(originalteks.length < extractteks.length)
end = originalteks.length();
else
end = extractteks.length();
//no if needed -> same length, diff will be 0
different_char=Math.abs(originalteks.length()-extractteks.length());
for(int start = 0; start < end; start++){
if(originalteks.charAt(start)!=extractteks.charAt(start))
different_char++;//jumlah diferent chart
}
return different_char;
}
I am to find the last ten digits of 1^1 + 2^2 + 3^3.. + 1000^1000.
Is there any way to find this out with pure logic? I think you can't store a number that big.
This question is from a math competition, but I thought of trying to do this in Java.
You don't need to store number that big, you just need the last ten digits. You can store this in a long.
An efficient way to calculate large powers is to multiply and the squares e.g. 19^19 = 19 * 19^2 * 19 ^ 16 = 19 * 19 ^ 2 * 19^2^2^2^2. When you have value which is greater than 10^10 you can truncate the last 10 digits.
BTW the last ten digits of 1000^1000 is 0000000000 and when your add this to your sum, it's the same as adding zero ;)
Edit: While you don't have to use BigInteger, it is simpler to write.
BigInteger tenDigits = BigInteger.valueOf(10).pow(10);
BigInteger sum = BigInteger.ZERO;
for (int i= 1; i <= 1000; i++) {
BigInteger bi = BigInteger.valueOf(i);
sum = sum.add(bi.modPow(bi, tenDigits));
}
sum = sum.mod(tenDigits);
modPow is more efficient than pow with mod seperately as it doesn't have to calculate very large numbers, only the result of the mod.
You could use BigIntegers...
public static void main(String[] args) {
BigInteger acc = BigInteger.ZERO;
for (int k = 1; k <= 1000; k++) {
BigInteger pow = BigInteger.valueOf(k).pow(k);
acc = acc.add(pow);
}
System.out.println(acc);
}
I believe the problem comes from Project Euler, so it's not just a math problem; it should require some computation as well. I don't know how it could be solved with pencil and paper other than by duplicating the calculations a computer might make. I can't see much in the way of a purely mathematical solution. Mathematics can help us optimize the code, however.
To raise a^n, find the binary expansion of n:
n = n_k x 2^k + n_(k-1) x 2^(k-1) + ... + n_0 x 2^0
where n_i = 0 or 1 are the binary digits of n with the zeroth digit on the right. Then
a^n = a^(n_k x 2^k) x a^(n_(k-1) x 2^(k-1)) x ... x a^(n_0 x 2^0).
We can ignore any factors where n_i = 0, since the factor is then a^0 = 1. The process can be written as an algorithm which is O(log n) time and O(1) space (see below).
Next, as a challenge, in order to avoid the use of BigInteger, we can break the calculation into two parts: finding the answer mod 2^10 and finding the answer mod 5^10. In both cases the numbers in the relevant ranges and products of numbers in the relevant ranges fit into longs. The downside is that we have to use the Chinese Remainder Theorem to recombine the results, but it's not that hard, and it's instructive. The hardest part of using the Chinese Remainder Theorem is finding inverses mod m, but that can be accomplished in a straightforward manner using a modification of the Euclidean algorithm.
Asymptotic running time is O(n log n), space is O(1), and everything fits into a few long variables, no BigInteger or other sophisticated library required.
public class SeriesMod1010 {
public static long pow(long a,long n,long m) { // a^n mod m
long result = 1;
long a2i = a%m; // a^2^i for i = 0, ...
while (n>0) {
if (n%2 == 1) {
result *= a2i;
result %= m;
}
a2i *= a2i;
a2i %= m;
n /= 2;
}
return result;
}
public static long inverse(long a, long m) { // mult. inverse of a mod m
long r = m;
long nr = a;
long t = 0;
long nt = 1;
long tmp;
while (nr != 0) {
long q = r/nr;
tmp = nt; nt = t - q*nt; t = tmp;
tmp = nr; nr = r - q*nr; r = tmp;
}
if (r > 1) return -1; // no inverse
if (t < 0) t += m;
return t;
}
public static void main(String[] args) {
long twoTo10 = 1024;
long sum210 = 0;
for (long i=1; i<=1000; i++) {
sum210 += pow(i,i,twoTo10);
sum210 %= twoTo10;
}
long fiveTo10 = 9_765_625;
long sum510 = 0;
for (long i=1; i<=1000; i++) {
sum510 += pow(i,i,fiveTo10);
sum510 %= fiveTo10;
}
// recombine the numbers with the Chinese remainder theorem
long tenTo10 = 10_000_000_000L;
long answer = sum210 * inverse(fiveTo10,twoTo10) * fiveTo10
+ sum510 * inverse(twoTo10,fiveTo10) * twoTo10;
answer %= tenTo10;
System.out.println(answer);
}
}
use BigIntegers :
import java.math.BigInteger;
public class Program {
public static void main(String[] args) {
BigInteger result = new BigInteger("1");
BigInteger temp = new BigInteger("1");
BigInteger I;
for(int i = 1 ; i < 1001 ; i++){
I = new BigInteger(""+i);
for(int j = 1 ; j < i ; j++){
temp = temp.multiply(I);
}
result = result.multiply(temp);
temp = new BigInteger("1");
}
System.out.println(result);
}
}
It can be solved without BigInteger, because you need to store only 10 last digits on every addition or multiplication operation, using % to avoid overflow:
int n = 1000;
long result = 0;
long tenDigits = 10_000_000_000L;
for (int i = 1; i <= n; i++) {
long r = i;
for (int j = 2; j <= i; j++) {
r = (r * i) % tenDigits;
}
result += r;
}
return result % tenDigits;
Complexity is O(N^2), supposed that multiplication runs in constant time.
Answer: 9110846700.
The decimal base uses 0...9 (10 digits) to represent digits, a number that is in the second position right to left represents Digits * base.length^l2rPosition. Using this logics you can create a class that "pretty much does what your primary school teacher told you to, back when we used paper to calculate stuff, but with a baseN number and base-to-base conversions" I have done this class fully functional in C#, but I don't have time to translate it completely to java, this is about the same logics behind java.math.BigInteger. (with less performance I bet for I used a lot of lists >_>" No time to optimize it now
class IntEx {
ArrayList<Integer> digits = new ArrayList<>();
long baseSize = Integer.MAX_VALUE+1;
boolean negative = false;
public IntEx(int init)
{
set(init);
}
public void set(int number)
{
digits = new ArrayList<>();
int backup = number;
do
{
int index = (int)(backup % baseSize);
digits.add(index);
backup = (int) (backup / baseSize);
} while ((backup) > 0);
}
// ... other operations
private void add(IntEx number)
{
IntEx greater = number.digits.size() > digits.size() ? number : this;
IntEx lesser = number.digits.size() < digits.size() ? number : this;
int leftOvers = 0;
ArrayList<Integer> result = new ArrayList<>();
for (int i = 0; i < greater.digits.size() || leftOvers > 0; i++)
{
int sum;
if (i >= greater.digits.size())
sum = leftOvers;
else if(i >= lesser.digits.size())
sum = leftOvers + greater.digits.get(i);
else
sum = digits.get(i) + number.digits.get(i) + leftOvers;
leftOvers = 0;
if (sum > baseSize-1)
{
while (sum > baseSize-1)
{
sum -= baseSize;
leftOvers += 1;
}
result.add(sum);
}
else
{
result.add(sum);
leftOvers = 0;
}
}
digits = result;
}
private void multiply(IntEx target)
{
ArrayList<IntEx> MultiParts = new ArrayList<>();
for (int i = 0; i < digits.size(); i++)
{
IntEx thisPart = new IntEx(0);
thisPart.digits = new ArrayList<>();
for (int k = 0; k < i; k++)
thisPart.digits.add(0);
int Leftovers = 0;
for (int j = 0; j < target.digits.size(); j++)
{
int multiFragment = digits.get(i) * (int) target.digits.get(j) + Leftovers;
Leftovers = (int) (multiFragment / baseSize);
thisPart.digits.add((int)(multiFragment % baseSize));
}
while (Leftovers > 0)
{
thisPart.digits.add((int)(Leftovers % baseSize));
Leftovers = (int) (Leftovers / baseSize);
}
MultiParts.add(thisPart);
}
IntEx newNumber = new IntEx(0);
for (int i = 0; i < MultiParts.size(); i++)
{
newNumber.add(MultiParts.get(i));
}
digits = newNumber.digits;
}
public long longValue() throws Exception
{
int position = 0;
long multi = 1;
long retValue = 0;
if (digits.isEmpty()) return 0;
if (digits.size() > 16) throw new Exception("The number within IntEx class is too big to fit into a long");
do
{
retValue += digits.get(position) * multi;
multi *= baseSize;
position++;
} while (position < digits.size());
return retValue;
}
public static long BaseConvert(String number, String base)
{
boolean negative = number.startsWith("-");
number = number.replace("-", "");
ArrayList<Character> localDigits = new ArrayList<>();
for(int i = number.toCharArray().length - 1; i >=0; i--) {
localDigits.add(number.charAt(i));
}
// List<>().reverse is missing in this damn java. -_-
long retValue = 0;
long Multi = 1;
char[] CharsBase = base.toCharArray();
for (int i = 0; i < number.length(); i++)
{
int t = base.indexOf(localDigits.get(i));
retValue += base.indexOf(localDigits.get(i)) * Multi;
Multi *= base.length();
}
if (negative)
retValue = -retValue;
return retValue;
}
public static String BaseMult(String a, String b, String Base)
{
ArrayList<String> MultiParts = new ArrayList<>();
// this huge block is a tribute to java not having "Reverse()" method.
char[] x = new char[a.length()];
char[] y = new char[b.length()];
for(int i = 0; i < a.length(); i++) {
x[i] = a.charAt(a.length()-i);
}
for(int i = 0; i < b.length(); i++) {
y[i] = a.charAt(a.length()-i);
}
a = new String(x);
b = new String(y);
// ---------------------------------------------------------------------
for (int i = 0; i < a.length(); i++)
{
ArrayList<Character> thisPart = new ArrayList<>();
for (int k = 0; k < i; k++)
thisPart.add(Base.charAt(0));
int leftOvers = 0;
for (int j = 0; j < b.length(); j++)
{
// Need I say repeated characters in base may cause mayhem?
int MultiFragment = Base.indexOf(a.charAt(i)) * Base.indexOf(b.charAt(j)) + leftOvers;
leftOvers = MultiFragment / Base.length();
thisPart.add(Base.charAt(MultiFragment % Base.length()));
}
while (leftOvers > 0)
{
thisPart.add(Base.charAt(leftOvers % Base.length()));
leftOvers = leftOvers / Base.length();
}
char[] thisPartReverse = new char[thisPart.size()];
for(int z = 0; z < thisPart.size();z++)
thisPartReverse[z] = thisPart.get(thisPart.size()-z);
MultiParts.add(new String(thisPartReverse));
}
String retValue = ""+Base.charAt(0);
for (int i = 0; i < MultiParts.size(); i++)
{
retValue = BaseSum(retValue, MultiParts.get(i), Base);
}
return retValue;
}
public static String BaseSum(String a, String b, String Base)
{
// this huge block is a tribute to java not having "Reverse()" method.
char[] x = new char[a.length()];
char[] y = new char[b.length()];
for(int i = 0; i < a.length(); i++) {
x[i] = a.charAt(a.length()-i);
}
for(int i = 0; i < b.length(); i++) {
y[i] = a.charAt(a.length()-i);
}
a = new String(x);
b = new String(y);
// ---------------------------------------------------------------------
String greater = a.length() > b.length() ? a : b;
String lesser = a.length() < b.length() ? a : b;
int leftOvers = 0;
ArrayList<Character> result = new ArrayList();
for (int i = 0; i < greater.length() || leftOvers > 0; i++)
{
int sum;
if (i >= greater.length())
sum = leftOvers;
else if (i >= lesser.length())
sum = leftOvers + Base.indexOf(greater.charAt(i));
else
sum = Base.indexOf(a.charAt(i)) + Base.indexOf(b.charAt(i)) + leftOvers;
leftOvers = 0;
if (sum > Base.length()-1)
{
while (sum > Base.length()-1)
{
sum -= Base.length();
leftOvers += 1;
}
result.add(Base.charAt(sum));
}
else
{
result.add(Base.charAt(sum));
leftOvers = 0;
}
}
char[] reverseResult = new char[result.size()];
for(int i = 0; i < result.size(); i++)
reverseResult[i] = result.get(result.size() -i);
return new String(reverseResult);
}
public static String BaseConvertItoA(long number, String base)
{
ArrayList<Character> retValue = new ArrayList<>();
boolean negative = false;
long backup = number;
if (negative = (backup < 0))
backup = -backup;
do
{
int index = (int)(backup % base.length());
retValue.add(base.charAt(index));
backup = backup / base.length();
} while ((backup) > 0);
if (negative)
retValue.add('-');
char[] reverseRetVal = new char[retValue.size()];
for(int i = 0; i < retValue.size(); i++)
reverseRetVal[i] = retValue.get(retValue.size()-i);
return new String(reverseRetVal);
}
public String ToString(String base)
{
if(base == null || base.length() < 2)
base = "0123456789";
ArrayList<Character> retVal = new ArrayList<>();
char[] CharsBase = base.toCharArray();
int TamanhoBase = base.length();
String result = ""+base.charAt(0);
String multi = ""+base.charAt(1);
String lbase = IntEx.BaseConvertItoA(baseSize, base);
for (int i = 0; i < digits.size(); i++)
{
String ThisByte = IntEx.BaseConvertItoA(digits.get(i), base);
String Next = IntEx.BaseMult(ThisByte, multi, base);
result = IntEx.BaseSum(result, Next, base);
multi = IntEx.BaseMult(multi, lbase, base);
}
return result;
}
public static void main(String... args) {
int ref = 0;
IntEx result = new IntEx(0);
while(++ref <= 1000)
{
IntEx mul = new IntEx(1000);
for (int i = 0; i < 1000; ++i) {
mul.multiply(new IntEx(i));
}
result.add(mul);
}
System.out.println(result.toString());
}
}
Disclaimer: This is a rough translation/localization from a C# study, there are lots of code omitted. This is "almost" the same logics behind java.math.BigInteger (you can open BigInteger code on your favorite designer and check for yourself. If may I be forgetting a overloaded operator behind not translated to java, have a bit of patience and forgiveness, this example is just for a "maybe" clarification of the theory.
Also, just a sidenote, I know it is "Trying to reinvent the wheel", but considering this question has academic purpose I think its fairly rasonable to share.
One can see the result of this study on gitHub (not localized though), I'm not expanding that C# code here for its very extensive and not the language of this question.
This gives the correct answer without excess calculations. A Long is sufficient.
public String lastTen() {
long answer = 0;
String txtAnswer = "";
int length = 0;
int i = 1;
for(i = 1; i <= 1000; i++) {
answer += Math.pow(i, i);
txtAnswer = Long.toString(answer);
length = txtAnswer.length();
if(length > 9) break;
}
return txtAnswer.substring(length-10);
}
I have a string that consists of characters A,B,C and D and I am trying to calculate the length of the longest substring that has an equal amount of each one of these characters in any order.
For example ABCDB would return 4, ABCC 0 and ADDBCCBA 8.
My code currently:
public int longestSubstring(String word) {
HashMap<Integer, String> map = new HashMap<Integer, String>();
for (int i = 0; i<word.length()-3; i++) {
map.put(i, word.substring(i, i+4));
}
StringBuilder sb;
int longest = 0;
for (int i = 0; i<map.size(); i++) {
sb = new StringBuilder();
sb.append(map.get(i));
int a = 4;
while (i<map.size()-a) {
sb.append(map.get(i+a));
a+= 4;
}
String substring = sb.toString();
if (equalAmountOfCharacters(substring)) {
int length = substring.length();
if (length > longest)
longest = length;
}
}
return longest;
}
This currently works pretty well if the string length is 10^4 but I'm trying to make it 10^5. Any tips or suggestions would be appreciated.
Let's assume that cnt(c, i) is the number of occurrences of the character c in the prefix of length i.
A substring (low, high] has an equal amount of two characters a and b iff cnt(a, high) - cnt(a, low) = cnt(b, high) - cnt(b, low), or, put it another way, cnt(b, high) - cnt(a, high) = cnt(b, low) - cnt(a, low). Thus, each position is described by a value of cnt(b, i) - cnt(a, i). Now we can generalize it for more that two characters: each position is described by a tuple (cnt(a_2, i) - cnt(a_1, i), ..., cnt(a_k, i) - cnt(a_1, i)), where a_1 ... a_k is the alphabet.
We can iterate over the given string and maintain the current tuple. At each step, we should update the answer by checking the value of i - first_occurrence(current_tuple), where first_occurrence is a hash table that stores the first occurrence of each tuple seen so far. Do not forget to put a tuple of zeros to the hash map before iteration(it corresponds to an empty prefix).
If there were only A's and B's, then you could do something like this.
def longest_balanced(word):
length = 0
cumulative_difference = 0
first_index = {0: -1}
for index, letter in enumerate(word):
if letter == 'A':
cumulative_difference += 1
elif letter == 'B':
cumulative_difference -= 1
else:
raise ValueError(letter)
if cumulative_difference in first_index:
length = max(length, index - first_index[cumulative_difference])
else:
first_index[cumulative_difference] = index
return length
Life is more complicated with all four letters, but the idea is much the same. Instead of keeping just one cumulative difference, for A's versus B's, we keep three, for A's versus B's, A's versus C's, and A's versus D's.
Well, first of all abstain from constructing any strings.
If you don't produce any (or nearly no) garbage, there's no need to collect it, which is a major plus.
Next, use a different data-structure:
I suggest 4 byte-arrays, storing the count of their respective symbol in the 4-span starting at the corresponding string-index.
That should speed it up considerably.
You can count the occurrences of the characters in word. Then, a possible solution could be:
If min is the minimum number of occurrences of any character in word, then min is also the maximum possible number of occurrences of each character in the substring we are looking for. In the code below, min is maxCount.
We iterate over decreasing values of maxCount. At every step, the string we are searching for will have length maxCount * alphabetSize. We can view this as the size of a sliding window we can slide over word.
We slide the window over word, counting the occurrences of the characters in the window. If the window is the substring we are searching for, we return the result. Otherwise, we keep searching.
[FIXED] The code:
private static final int ALPHABET_SIZE = 4;
public int longestSubstring(String word) {
// count
int[] count = new int[ALPHABET_SIZE];
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
count[c - 'A']++;
}
int maxCount = word.length();
for (int i = 0; i < count.length; i++) {
int cnt = count[i];
if (cnt < maxCount) {
maxCount = cnt;
}
}
// iterate over maxCount until found
boolean found = false;
while (maxCount > 0 && !found) {
int substringLength = maxCount * ALPHABET_SIZE;
found = findSubstring(substringLength, word, maxCount);
if (!found) {
maxCount--;
}
}
return found ? maxCount * ALPHABET_SIZE : 0;
}
private boolean findSubstring(int length, String word, int maxCount) {
int startIndex = 0;
boolean found = false;
while (startIndex + length <= word.length()) {
int[] count = new int[ALPHABET_SIZE];
for (int i = startIndex; i < startIndex + length; i++) {
char c = word.charAt(i);
int cnt = ++count[c - 'A'];
if (cnt > maxCount) {
break;
}
}
if (equalValues(count, maxCount)) {
found = true;
break;
} else {
startIndex++;
}
}
return found;
}
// Returns true if all values in c are equal to value
private boolean equalValues(int[] count, int value) {
boolean result = true;
for (int i : count) {
if (i != value) {
result = false;
break;
}
}
return result;
}
[MERGED] This is Hollis Waite's solution using cumulative counts, but taking my observations at points 1. and 2. into consideration. This may improve performance for some inputs:
private static final int ALPHABET_SIZE = 4;
public int longestSubstring(String word) {
// count
int[][] cumulativeCount = new int[ALPHABET_SIZE][];
for (int i = 0; i < ALPHABET_SIZE; i++) {
cumulativeCount[i] = new int[word.length() + 1];
}
int[] count = new int[ALPHABET_SIZE];
for (int i = 0; i < word.length(); i++) {
char c = word.charAt(i);
count[c - 'A']++;
for (int j = 0; j < ALPHABET_SIZE; j++) {
cumulativeCount[j][i + 1] = count[j];
}
}
int maxCount = word.length();
for (int i = 0; i < count.length; i++) {
int cnt = count[i];
if (cnt < maxCount) {
maxCount = cnt;
}
}
// iterate over maxCount until found
boolean found = false;
while (maxCount > 0 && !found) {
int substringLength = maxCount * ALPHABET_SIZE;
found = findSubstring(substringLength, word, maxCount, cumulativeCount);
if (!found) {
maxCount--;
}
}
return found ? maxCount * ALPHABET_SIZE : 0;
}
private boolean findSubstring(int length, String word, int maxCount, int[][] cumulativeCount) {
int startIndex = 0;
int endIndex = (startIndex + length) - 1;
boolean found = true;
while (endIndex < word.length()) {
for (int i = 0; i < ALPHABET_SIZE; i++) {
if (cumulativeCount[i][endIndex] - cumulativeCount[i][startIndex] != maxCount) {
found = false;
break;
}
}
if (found) {
break;
} else {
startIndex++;
endIndex++;
}
}
return found;
}
You'll probably want to cache cumulative counts of characters for each index of String -- that's where the real bottleneck is. Haven't thoroughly tested but something like the below should work.
public class Test {
static final int LEN = 4;
static class RandomCharSequence implements CharSequence {
private final Random mRandom = new Random();
private final int mAlphabetLen;
private final int mLen;
private final int mOffset;
RandomCharSequence(int pLen, int pOffset, int pAlphabetLen) {
mAlphabetLen = pAlphabetLen;
mLen = pLen;
mOffset = pOffset;
}
public int length() {return mLen;}
public char charAt(int pIdx) {
mRandom.setSeed(mOffset + pIdx);
return (char) (
'A' +
(mRandom.nextInt() % mAlphabetLen + mAlphabetLen) % mAlphabetLen
);
}
public CharSequence subSequence(int pStart, int pEnd) {
return new RandomCharSequence(pEnd - pStart, pStart, mAlphabetLen);
}
#Override public String toString() {
return (new StringBuilder(this)).toString();
}
}
public static void main(String[] pArgs) {
Stream.of("ABCDB", "ABCC", "ADDBCCBA", "DADDBCCBA").forEach(
pWord -> System.out.println(longestSubstring(pWord))
);
for (int i = 0; ; i++) {
final double len = Math.pow(10, i);
if (len >= Integer.MAX_VALUE) break;
System.out.println("Str len 10^" + i);
for (int alphabetLen = 1; alphabetLen <= LEN; alphabetLen++) {
final Instant start = Instant.now();
final int val = longestSubstring(
new RandomCharSequence((int) len, 0, alphabetLen)
);
System.out.println(
String.format(
" alphabet len %d; result %08d; time %s",
alphabetLen,
val,
formatMillis(ChronoUnit.MILLIS.between(start, Instant.now()))
)
);
}
}
}
static String formatMillis(long millis) {
return String.format(
"%d:%02d:%02d.%03d",
TimeUnit.MILLISECONDS.toHours(millis),
TimeUnit.MILLISECONDS.toMinutes(millis) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
TimeUnit.MILLISECONDS.toSeconds(millis) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)),
TimeUnit.MILLISECONDS.toMillis(millis) -
TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(millis))
);
}
static int longestSubstring(CharSequence pWord) {
// create array that stores cumulative char counts at each index of string
// idx 0 = char (A-D); idx 1 = offset
final int[][] cumulativeCnts = new int[LEN][];
for (int i = 0; i < LEN; i++) {
cumulativeCnts[i] = new int[pWord.length() + 1];
}
final int[] cumulativeCnt = new int[LEN];
for (int i = 0; i < pWord.length(); i++) {
cumulativeCnt[pWord.charAt(i) - 'A']++;
for (int j = 0; j < LEN; j++) {
cumulativeCnts[j][i + 1] = cumulativeCnt[j];
}
}
final int maxResult = Arrays.stream(cumulativeCnt).min().orElse(0) * LEN;
if (maxResult == 0) return 0;
int result = 0;
for (int initialOffset = 0; initialOffset < LEN; initialOffset++) {
for (
int start = initialOffset;
start < pWord.length() - result;
start += LEN
) {
endLoop:
for (
int end = start + result + LEN;
end <= pWord.length() && end - start <= maxResult;
end += LEN
) {
final int substrLen = end - start;
final int expectedCharCnt = substrLen / LEN;
for (int i = 0; i < LEN; i++) {
if (
cumulativeCnts[i][end] - cumulativeCnts[i][start] !=
expectedCharCnt
) {
continue endLoop;
}
}
if (substrLen > result) result = substrLen;
}
}
}
return result;
}
}
Suppose there are K possible letters in a string of length N. We could track the balance of letters seen with a vector pos of length K that is updated as follows:
If letter 1 is seen, add (K-1, -1, -1, ...)
If letter 2 is seen, add (-1, K-1, -1, ...)
If letter 3 is seen, add (-1, -1, K-1, ...)
Maintain a hash that maps pos to the first string position where pos is reached. Balanced substrings occur whenever hash[pos] already exists and the substring value is s[hash[pos]:pos].
The cost of maintaining the hash is O(log N) so processing the string takes O(N log N). How does this compare with solutions so far? These types of problems tend to have linear solutions but I haven't come across one yet.
Here's some code demonstrating the idea for 3 letters and a run using biased random strings. (Uniform random strings allow for solutions that are around half the string length, which is unwieldy to print).
#!/usr/bin/python
import random
from time import time
alphabet = "abc"
DIM = len(alphabet)
def random_string(n):
# return a random string over choices[] of length n
# distribution of letters is non-uniform to make matches harder to find
choices = "aabbc"
s = ''
for i in range(n):
r = random.randint(0, len(choices) - 1)
s += choices[r]
return s
def validate(s):
# verify frequencies of each letter are the same
f = [0, 0, 0]
a2f = {alphabet[i] : i for i in range(DIM)}
for c in s:
f[a2f[c]] += 1
assert f[0] == f[1] and f[1] == f[2]
def longest_balanced(s):
"""return length of longest substring of s containing equal
populations of each letter in alphabet"""
slen = len(s)
p = [0 for i in range(DIM)]
vec = {alphabet[0] : [2, -1, -1],
alphabet[1] : [-1, 2, -1],
alphabet[2] : [-1, -1, 2]}
x = -1
best = -1
hist = {str([0, 0, 0]) : -1}
for c in s:
x += 1
p = [p[i] + vec[c][i] for i in range(DIM)]
pkey = str(p)
if pkey not in hist:
hist[pkey] = x
else:
span = x - hist[pkey]
assert span % DIM == 0
if span > best:
best = span
cand = s[hist[pkey] + 1: x + 1]
print("best so far %d = [%d,%d]: %s" % (best,
hist[pkey] + 1,
x + 1,
cand))
validate(cand)
return best if best > -1 else 0
def main():
#print longest_balanced( "aaabcabcbbcc" )
t0 = time()
s = random_string(1000000)
print "generate time:", time() - t0
t1 = time()
best = longest_balanced( s )
print "best:", best
print "elapsed:", time() - t1
main()
Sample run on an input of 10^6 letters with an alphabet of 3 letters:
$ ./bal.py
...
best so far 189 = [847894,848083]: aacacbcbabbbcabaabbbaabbbaaaacbcaaaccccbcbcbababaabbccccbbabbacabbbbbcaacacccbbaacbabcbccaabaccabbbbbababbacbaaaacabcbabcbccbabbccaccaabbcabaabccccaacccccbaacaaaccbbcbcabcbcacaabccbacccacca
best: 189
elapsed: 1.43609690666