Given an integer N, i am trying to find the nth binary palindrome.I have written the following code but it is not efficient.is there a more efficient way in terms of time complexity.
I was trying it out as a problem online and i was supposed to output in 1 sec or less but for every input it takes 2 seconds.
public static Boolean Palind(String n){
String reverse = "";
int length = n.length();
for(int i = length - 1; i >=0;i--){
reverse = reverse + n.charAt(i);
}
if(n.equals(reverse)){
return true;
}
else{
return false;
}
}
public static int Magical(int n){
ArrayList<Integer> res = new ArrayList<Integer>();
for(int i = 1; i < Math.pow(2, n);i++){
if(Palind(Integer.toBinaryString(i))){
res.add(i);
}
}
return res.get(n-1);
}
The relevant OEIS entry (A006995) has a lot of nice tips if you read through it. For example, a(2^n-1)=2^(2n-2)-1 lets you skip right to the (2n - 1)th palindrome really quickly.
It also gives several implementations. For example, the Smalltalk implementation works like this (note that the input value, n, starts with 1 for the first palindrome, 0):
public static final int nthBooleanPalindrome(int n) {
if (n == 1) return 0;
if (n == 2) return 1;
int m = 31 - Integer.numberOfLeadingZeros(n);
int c = 1 << (m - 1);
int b;
if (n >= 3*c) {
int a = n - 3*c;
int d = 2*c*c;
b = d + 1;
int k2 = 1;
for (int i = 1; i < m; i++) {
k2 <<= 1;
b += a*k2/c%2*(k2 + d/k2);
}
}
else {
int a = n - 2*c;
int d = c*c;
b = d + 1 + (n%2*c);
int k2 = 1;
for (int i = 1; i < m - 1; i++) {
k2 <<= 1;
b += a*k2/c%2*(k2 + d/k2);
}
}
return b;
}
Try something like this maybe?
public static void main(String[] args) {
for (int i = 1; i < 65535; i++) {
System.out.println(
i + ": " + getBinaryPalindrom(i) + " = " + Integer.toBinaryString(getBinaryPalindrom(i)));
}
}
public static int getBinaryPalindrom(int N) {
if (N < 4) {
switch (N) {
case 1:
return 0;
case 2:
return 1;
case 3:
return 3;
}
throw new IndexOutOfBoundsException("You need to supply N >= 1");
}
// second highest to keep the right length (highest is always 1)
final int bitAfterHighest = (N >>> (Integer.SIZE - Integer.numberOfLeadingZeros(N) - 2)) & 1;
// now remove the second highest bit to get the left half of our palindrom
final int leftHalf = (((N >>> (Integer.SIZE - Integer.numberOfLeadingZeros(N) - 1)) & 1) << (Integer.SIZE -
Integer.numberOfLeadingZeros(N) - 2)) | ((N << (Integer.numberOfLeadingZeros(N) + 2)) >>> (Integer.numberOfLeadingZeros(N) + 2));
// right half is just the left reversed
final int rightHalf = Integer.reverse(leftHalf);
if (Integer.numberOfLeadingZeros(leftHalf) < Integer.SIZE / 2) {
throw new IndexOutOfBoundsException("To big to fit N=" + N + " into an int");
}
if (bitAfterHighest == 0) {
// First uneven-length palindromes
return (leftHalf << (Integer.SIZE - Integer.numberOfLeadingZeros(leftHalf)) - 1) | (rightHalf
>>> Integer.numberOfTrailingZeros(rightHalf));
} else {
// Then even-length palindromes
return (leftHalf << (Integer.SIZE - Integer.numberOfLeadingZeros(leftHalf))) | (rightHalf
>>> Integer.numberOfTrailingZeros(rightHalf));
}
}
The idea is that each number will become a palindrome once it reverse is added. To have the halves correctly aligned the halves just need to be shifted in place.
The problem why this has gotten a bit complex is that all uneven-length palindromes of a given leftHalf length come before all even-length palindromes of a given leftHalf length. Feel free to provide a better solution.
As int has 32 bit in Java there is a limit on N.
int-Version on ideone.com
And a BigInteger-version to support big values. It is not as fast as the int-version as the byte[]-arrays which store the value of the BigInteger create some overhead.
public static void main(String[] args) {
for (BigInteger i = BigInteger.valueOf(12345678); i.compareTo(BigInteger.valueOf(12345778)) < 0; i = i
.add(BigInteger
.ONE)) {
final BigInteger curr = getBinaryPalindrom(i);
System.out.println(i + ": " + curr + " = " + curr.toString(2));
}
}
public static BigInteger getBinaryPalindrom(BigInteger n) {
if (n.compareTo(BigInteger.ZERO) <= 0) {
throw new IndexOutOfBoundsException("You need to supply N >= 1");
} else if (n.equals(BigInteger.valueOf(1))) {
return BigInteger.valueOf(0);
} else if (n.equals(BigInteger.valueOf(2))) {
return BigInteger.valueOf(1);
} else if (n.equals(BigInteger.valueOf(3))) {
return BigInteger.valueOf(3);
}
final int bitLength = n.bitLength() - 1;
// second highest to keep the right length (highest is always 1)
final boolean bitAfterHighest = n.testBit(bitLength - 1);
// now remove the second highest bit to get the left half of our palindrom
final BigInteger leftHalf = n.clearBit(bitLength).setBit(bitLength - 1);
// right half is just the left reversed
final BigInteger rightHalf;
{
byte[] inArray = leftHalf.toByteArray();
byte[] outArray = new byte[inArray.length];
final int shiftOffset = Integer.SIZE - Byte.SIZE;
for (int i = 0; i < inArray.length; i++) {
outArray[inArray.length - 1 - i] = (byte) (Integer.reverse(inArray[i]) >>> shiftOffset);
}
rightHalf = new BigInteger(1, outArray).shiftRight(outArray.length * Byte.SIZE - bitLength);
}
if (!bitAfterHighest) {
// First uneven-length palindromes
return leftHalf.shiftLeft(bitLength - 1).or(rightHalf);
} else {
// Then even-length palindromes
return leftHalf.shiftLeft(bitLength).or(rightHalf);
}
}
I have the same idea with #Kiran Kumar: you should not count number one by one to find if it is a binary palindrome which is too slow, but rather find the internal pattern that number has.
List the number in binary string one by one, you can find the pattern:
0
1
11
101
1001
1111
...
1......1
And the following is some math problem:
We have 2^round_up((L-2)/2) palindrome of number with length L in binary format.
Sum up every shorter length number, we get following len to sum mapping:
for (int i = 1; i < mapping.length; i++) {
mapping[i] = (long) (mapping[i - 1] + Math.pow(2, Math.ceil((i - 1) * 1.0 / 2)));
}
If we find N range in [count(L), count(L+1)), we can concat it with remaining number:
public static long magical(long n) {
if (n == 0 || n == 1) {
return n;
}
long N = n - 2;
return Long.parseLong(concat(N), 2);
}
private static String concat(long N) {
int midLen = Arrays.binarySearch(indexRange, N);
if (midLen < 0) {
midLen = -midLen - 1;
}
long remaining = N - indexRange[midLen];
String mid = mirror(remaining, midLen);
return '1' + mid + '1';
}
private static String mirror(long n, int midLen) {
int halfLen = (int) Math.ceil(midLen * 1.0 / 2);
// produce fixed length binary string
final String half = Long.toBinaryString(n | (1 << halfLen)).substring(1);
if (midLen % 2 == 0) {
return half + new StringBuilder(half).reverse().toString();
} else {
return half + new StringBuilder(half).reverse().toString().substring(1);
}
}
Full code with test for produce large possible long can be found in my git repo.
Idea to optimize,
Let's look at the palindrome sequence 0, 1, 11, 101, 111, 1001 etc...
All numbers must begin and end with 1, So the middle bits only changes and midle substring should be palindrome for full string to become palindrome,
So let's take a 2 digit binary number - one palindrome is possible.
The binary of the decimal 3 is a palindrome. 11
For a 3 digit binary number 2 palindromes are possible, 2*(no of 1 digit palindrome)
The binary of the decimal 5 is a palindrome. 101
The binary of the decimal 7 is a palindrome. 111
For 5 digit binary number 4 palindromes are possible 2*(no of 3 digit palindrome)
10001,10101, 11011, 11111
and so on,
So it will be 2 + 20 + 21 + 22 +...... +2i-N ,
we solve for i and find out the palindrome number.
So by analysing this sequence we get an equation like 2(i/2)+1 -1 = N
where N is the No of palindrome,
and i is the number of bits in the nth palindrome string,
using this we can find the length of the String, from this we can find the string early.
This might be complex, but helps in solving higher values of N quickly....
Related
Given an input string of digits, split that into groups of prime numbers by maintaining the order given in the input string and each group should hold all the characters of the input string. Find the count of such groups.
Example:
11375
Ans:
3
Explanation:
The 3 combinations are [11,37,5], [11,3,7,5] and [113,7,5]
Code that I tried
public int countPossibilities(String s) {
int n = s.length();
int[] ar = new int[n + 1];
ar[0] = 1;
for (int i = 1; i < n; i++) {
int j = i - 1;
while (j >= 0 && j >= i - 3) {
if (prime(s.substring(j, i)))
ar[i] += ar[j];
j--;
}
}
return ar[n];
}
public boolean prime(String s) {
int n = Integer.parseInt(s);
if (n < 2) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
This works fine if the input string length is small.
But the length of the input string can be from 1 to 10^5. So my program fails for large strings.
Example:
1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659
Expected result is : 4386816
What is the right approach to solve this problem.
Here's working Python code that answers your long example.
Let dp[i] represent the number of valid combinations ending at the ith index of the input. Then for each prime suffix of length x ending at input[i], we add to dp[i] the count of valid combinations ending at dp[i-x], provided there is also a count of valid combinations recorded for dp[i-x].
# https://rosettacode.org/wiki/Sieve_of_Eratosthenes
def primes2(limit):
if limit < 2: return []
if limit < 3: return [2]
lmtbf = (limit - 3) // 2
buf = [True] * (lmtbf + 1)
for i in range((int(limit ** 0.5) - 3) // 2 + 1):
if buf[i]:
p = i + i + 3
s = p * (i + 1) + i
buf[s::p] = [False] * ((lmtbf - s) // p + 1)
return set(["2"] + [str(i + i + 3) for i, v in enumerate(buf) if v])
def f(n):
# The constant, k, limits the number
# of digits in the suffix we're
# checking for primality.
k = 6
primes = primes2(10**k)
dp = [0] * len(n) + [1]
for i in range(len(n)):
suffix = ""
for j in range(min(i + 1, k)):
suffix = n[i-j] + suffix
if suffix in primes and dp[i-j-1] > 0:
dp[i] += dp[i-j-1]
return dp[len(n) - 1]
Output:
n = "1350297079989171477791892123929141605573631151125933376097791877830238462471373933362476484818693477173990672289892448124097556197582379957168911392680312103962394732707409889862447273901522659"
print(f(n)) # 4386816
Proof of concept from my comments, but in C# (I'm an AP Comp Sci teacher that doesn't like to code in Java; go figure!):
Take the length of the input string minus 1 and call this "padLength".
Now raise 2 to the power of padLength to get the total number of
possibilities for string combinations; call this number
"numberOfCombinations". Next, count from 0 to numberOfCombinations and
convert that decimal number to a BINARY number, left padded with
zeroes out to padLength, called "binaryNumber". The binary number
represents whether or not a space should be added in-between the
digits of the original number. For instance, binary "1100" and dec
"11375" would result in "1 1 375" because 1 means put a space
in-between. This process will give you all combinations of the
original string in the different groups. Then you can extract the
numbers from the groups and see if they are primes...
Code:
private async void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text.Trim().Length == 0) { return; }
textBox1.Enabled = false;
button1.Enabled = false;
textBox2.Clear();
String binary;
StringBuilder sb = new StringBuilder();
String input = textBox1.Text.Trim();
char[] digits = input.ToCharArray();
int padLength = input.Length - 1;
long combinations = (long)Math.Pow(2, padLength);
List<String> combos = new List<string>();
await Task.Run(() => {
for (long i = 0; i < combinations; i++)
{
binary = Convert.ToString(i, 2).ToString().PadLeft(padLength, '0');
char[] binaryDigits = binary.ToCharArray();
sb.Clear();
for (int s = 0; s < digits.Length; s++)
{
sb.Append(digits[s]);
if (s < (digits.Length - 1))
{
if (binaryDigits[s] == '1')
{
sb.Append(' ');
}
}
}
combos.Add(sb.ToString());
}
});
textBox2.Lines = combos.ToArray();
textBox1.Enabled = true;
button1.Enabled = true;
}
Output:
For very large inputs, you won't be able to compute the number of combinations using Math.Pow(), or any built-in methods for converting a decimal to a binary number. In those cases, you can "count manually" in binary by using a String directly and following the counting algorithm. You'd build the binary numbers using only String manipulation directly by inspecting each char to see if it is 1 or 0 and acting accordingly. You'll know you're done when you have a string of ones that has a length one less than the length of your input. It will run a lot slower than working with numbers directly.
Consider a hexadecimal integer value such as n = 0x12345, how to get 0x1235 as result by doing remove(n, 3) (big endian)?
For the inputs above I think this can be achieved by performing some bitwising steps:
partA = extract the part from index 0 to targetIndex - 1 (should return 0x123);
partB = extract the part from targetIndex + 1 to length(value) - 1 (0x5);
result, then, can be expressed by ((partA << length(partB) | partB), giving the 0x1235 result.
However I'm still confused in how to implement it, once each hex digit occupies 4 spaces. Also, I don't know a good way to retrieve the length of the numbers.
This can be easily done with strings however I need to use this in a context of thousands of iterations and don't think Strings is a good idea to choose.
So, what is a good way to this removing without Strings?
Similar to the idea you describe, this can be done by creating a mask for both the upper and the lower part, shifting the upper part, and then reassembling.
int remove(int x, int i) {
// create a mask covering the highest 1-bit and all lower bits
int m = x;
m |= (m >>> 1);
m |= (m >>> 2);
m |= (m >>> 4);
m |= (m >>> 8);
m |= (m >>> 16);
// clamp to 4-bit boundary
int l = m & 0x11111110;
m = l - (l >>> 4);
// shift to select relevant position
m >>>= 4 * i;
// assemble result
return ((x & ~(m << 4)) >>> 4) | (x & m);
}
where ">>>" is an unsigned shift.
As a note, if 0 indicates the highest hex digit in a 32-bit word independent of the input, this is much simpler:
int remove(int x, int i) {
int m = 0xffffffff >>> (4*i);
return ((x & ~m) >>> 4) | (x & (m >>> 4));
}
Solution:
Replace operations using 10 with operations using 16.
Demo
Using Bitwise Operator:
public class Main {
public static void main(String[] args) {
int n = 0x12345;
int temp = n;
int length = 0;
// Find length
while (temp != 0) {
length++;
temp /= 16;
}
System.out.println("Length of the number: " + length);
// Remove digit at index 3
int m = n;
int index = 3;
for (int i = index + 1; i <= length; i++) {
m /= 16;
}
m *= 1 << ((length - index - 1) << 2);
m += n % (1 << ((length - index - 1) << 2));
System.out.println("The number after removing digit at index " + index + ": 0x" + Integer.toHexString(m));
}
}
Output:
Length of the number: 5
The number after removing digit at index 3: 0x1235
Using Math::pow:
public class Main {
public static void main(String[] args) {
int n = 0x12345;
int temp = n;
int length = 0;
// Find length
while (temp != 0) {
length++;
temp /= 16;
}
System.out.println("Length of the number: " + length);
// Remove digit at index 3
int m = n;
int index = 3;
for (int i = index + 1; i <= length; i++) {
m /= 16;
}
m *= ((int) (Math.pow(16, length - index - 1)));
m += n % ((int) (Math.pow(16, length - index - 1)));
System.out.println("The number after removing digit at index " + index + ": 0x" + Integer.toHexString(m));
}
}
Output:
Length of the number: 5
The number after removing digit at index 3: 0x1235
JavaScript version:
n = parseInt(12345, 16);
temp = n;
length = 0;
// Find length
while (temp != 0) {
length++;
temp = Math.floor(temp / 16);
}
console.log("Length of the number: " + length);
// Remove digit at index 3
m = n;
index = 3;
for (i = index + 1; i <= length; i++) {
m = Math.floor(m / 16);
}
m *= 1 << ((length - index - 1) << 2);
m += n % (1 << ((length - index - 1) << 2));
console.log("The number after removing digit at index " + index + ": 0x" + m.toString(16));
This works by writing a method to remove from the right but adjusting the parameter to remove from the left. The bonus is that a remove from the right is also available for use. This method uses longs to maximize the length of the hex value.
long n = 0x12DFABCA12L;
int r = 3;
System.out.println("Supplied value: " + Long.toHexString(n).toUpperCase());
n = removeNthFromTheRight(n, r);
System.out.printf("Counting %d from the right: %X%n", r, n);
n = 0x12DFABCA12L;
n = removeNthFromTheLeft(n, r);
System.out.printf("Counting %d from the left: %X%n", r, n);
Prints
Supplied value: 12DFABCA12
Counting 3 from the right: 12DFABA12
Counting 3 from the left: 12DABCA12
This works by recursively removing a digit from the end until just before the one you want to remove. Then remove that and return thru the call stack, rebuilding the number with the original values.
This method counts from the right.
public static long removeNthFromTheRight(long v, int n) {
if (v <= 0) {
throw new IllegalArgumentException("Not enough digits");
}
// save hex digit
long k = v % 16;
while (n > 0) {
// continue removing digit until one
// before the one you want to remove
return removeNthFromTheRight(v / 16, n - 1) * 16 + k;
}
if (n == 0) {
// and ignore that digit.
v /= 16;
}
return v;
}
This method counts from the left. It simply adjusts the value of n and then calls removeFromTheRight.
public static long removeNthFromTheLeft(long v, int n) {
ndigits = (67-Long.numberOfLeadingZeros(v))>>2;
// Now just call removeNthFromTheRight with modified paramaters.
return removeNthFromTheRight(v, ndigits - n - 1);
}
Here is my version using bit manipulation with explanation.
the highest set bit helps find the offset for the mask. For a long that bit is 64-the number of leading zeroes. To get the number of hex digits, one must divide by 4. To account for numbers evenly divisible by 4, it is necessary to add 3 before dividing. So that makes the number of digits:
digits = (67-Long.numberOfLeadingZeros(i))>>2;
which then requires it to be adjusted to mask the appropriate parts of the number.
offset = digits-i - 1
m is the mask to mask off the digit to be removed. So start with a -1L (all hex 'F') and right shift 4*(16-offset) bits. This will result in a mask that masks everything to the right of the digit to be removed.
Note: If offset is 0 the shift operator will be 64 and no bits will be shifted. To accommodate this, the shift operation is broken up into two operations.
Now simply mask off the low order bits
v & m
And the high order bits right shifted 4 bits to eliminate the desired digit.
(v>>>4)^ ~m
and then the two parts are simply OR'd together.
static long remove(long v, int i) {
int offset = ((67 - Long.numberOfLeadingZeros(v))>>2) - i - 1;
long m = (-1L >>> (4*(16 - offset) - 1)) >> 1;
return ((v >>> 4) & ~m) | (v & m);
}
I'm working on a problem where I'm required to manipulate large lists of palindromes up to a certain number of digits. This should work with numbers up 15 digits. The most common method I've seen for this is iterating through each number and checking whether each is a palindrome and then adding that to a list. This is my implementation in java and it works fine.
public class Palindrome {
public ArrayList<Long> List = new ArrayList<Long>();
public double d;
public Palindrome(double digits) {
this.d = digits;
long dig = (int)(Math.pow(10,digits));
for (long i = 1; i <= dig; i++) {
long a = i;
long b = inverse(a);
if (a == b) {
List.add(a);
}
}
public long inverse(long x){
long inv = 0;
while (x > 0) {
inv = inv * 10 + x % 10;
x = x / 10;
}
return inv;
}
}
Only problem is it's pretty slow when I get to 10+ digit palindromes. I've been considering alternative ways to create this list and one consideration I've had is generating the list of palindromes rather than iterating through each number and checking if it's a palindrome.
I'm still working on paper but the pattern isn't as obvious as I thought I would find it to turn into pseudocode. I'm working it out that for n number of digits, going from i to n, if the number of digits is even, generate numbers from 1 up to [10^(i/2 + 1) - 1]. Then append the reverse of each number to itself. A little stuck on how to do it for the odd digits. That's where I am right now.
I will come back with my own response if I figure this out and implement the code but in the meantime, I would just like to know if anyone has done this before or has an alternative method I've overlooked that would be more efficient.
UPDATE
So I did manage to work out something thanks to all your suggestions. I decided to work with the numbers as strings but contrary to what I intended this has actually increased the runtime :/
public class Palindrome2 {
public ArrayList<Long> List = new ArrayList<Long>();
public double d;
public Palindrome2(double digits) {
this.d = digits;
for (long n = 1; n <= d; n++) {
if (n == 1) {
for (long i = 1; i < 10; i++) {
List.add(i);
}
}
if (n % 2 != 0 && n != 1) {
long max = (long) Math.pow(10, (n + 1) / 2);
long min = (long) Math.pow(10, Math.floor(n / 2));
for (long i = min; i < max; i++) {
String str = Long.toString(i);
str = str + removeFirst(reverse(str));
Long x = Long.parseLong(str);
List.add(x);
}
} else if (n % 2 == 0) {
long max = (long) (Math.pow(10, Math.floor((n + 1) / 2)) - 1);
long min = (long) Math.pow(10, (n / 2) - 1);
for (long i = min; i <= max; i++) {
String str = Long.toString(i);
str = str + reverse(str);
Long x = Long.parseLong(str);
List.add(x);
}
}
}
}
public String reverse(String x) {
String rev = new StringBuffer(x).reverse().toString();
return rev;
}
public String removeFirst(String x) {
return x.substring(1);
}
}
Once again, accurate but still slow :(
Introduction
You need to analyzing the regular pattern for an algorithm roughly before jump into developing, that will saving lot of time, for example:
each 1 digit is 1 palindrome, e.g: 1
each 2 digits has 1 palindrome, e.g: 11.
each 3 digits has 10 palindromes, e.g: 101,111,...,191.
each 4 digits has 10 palindromes, e.g: 1001, 1111, ..., 1991.
each 5 digits has 100 palindromes, e.g: 10001, 11011, ..., 19091, ..., 19991.
each 6 digits has 100 palindromes, e.g: 100001, 110011, ..., 190091, ..., 199991.
each 7 digits has 1000 palindromes, e.g: 1000001, ...,1900091,...,1090901, ..., 1999991.
each 8 digits has 1000 palindromes, e.g: 10000001, ...,19000091,...,10900901, ..., 19999991.
....
then you can write some arrangement algorithm to implement this .
Implementation
But I can tell you this implementation can optimizing as further, if you using a cache to saving palindromes generated from low digits palindromes(2), then any high digits palindromes(n>2) can reusing it.
Maybe it's not robust but it pass all my tests on github. I left the rest working & optimization to you, and I wish you can done by yourself.
private static List<Integer> palindromes(int digits) {
return palindromes(digits, 0);
}
private static List<Integer> palindromes(int digits, int shifts) {
List<Integer> result = new ArrayList<>();
int radix = (int) Math.pow(10, digits - 1);
int renaming = digits - 2;
boolean hasRenaming = renaming > 0;
for (int i = start(digits, shifts); i <= 9; i++) {
int high = i * radix;
int low = low(digits, i);
if (hasRenaming) {
for (Integer m : palindromes(renaming, shifts + 1)) {
int ret = high + m * 10 + low;
if (ret < 0) {
return result;
}
result.add(ret);
}
} else {
result.add(high + low);
}
}
return result;
}
private static int low(int digits, int high) {
return digits > 1 ? high : 0;
}
private static int start(int digits, int shifts) {
return digits > 1 && shifts == 0 ? 1 : 0;
}
Usage
then you can collect all palindrome numbers as below:
// v--- min:0, max: 2147447412, count: 121474
List<Integer> all = IntStream.rangeClosed(1, 10)
.mapToObj(PalindromeTest::palindromes)
.flatMap(List::stream)
.collect(Collectors.toList());
Time Cost:
191ms
Enable Caching
public class Palindromes {
private static final int[] startingNonZerosTable = {
0,// 0
0, 1,// 1 2
10, 10,//3 4
100, 100, //5 6
1000, 1000,//7 8
10000, 10000,// 9 10
100000, 100000,//11 12
1000000, 1000000,//13 14
10000000, 10000000,//15 16
100000000, 100000000,//17 18
1000000000, 1000000000//19 20
};
private static final int MAX_DIGIT = 9;
private static final int MIN_DIGIT = 0;
private static final int RADIX = MAX_DIGIT - MIN_DIGIT + 1;
private static final int LONG_MAX_DIGITS = 19;
private static volatile long[][] cache = new long[LONG_MAX_DIGITS + 1][];
// includes palindromes(0) ---^
static {
cache[0] = new long[0];
cache[1] = new long[]{0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L};
cache[2] = new long[]{0L, 11L, 22L, 33L, 44L, 55L, 66L, 77L, 88L, 99L};
}
public static LongStream since1(int end) {
return between(1, end);
}
public static LongStream between(int start, int end) {
return IntStream.rangeClosed(start, end)
.mapToObj(Palindromes::of)
.flatMapToLong(identity());
}
public static LongStream of(int digits) {
return Arrays.stream(palindromes0(digits))
.skip(startingNonZerosTable[digits]);
}
private final static long[] palindromes0(int digits) {
if (cache[digits] != null) {
return cache[digits];
}
long[] result = new long[sizeOf(digits)];
int size = 0;
long high = (long) Math.pow(RADIX, digits - 1);
for (int i = MIN_DIGIT; i <= MAX_DIGIT; i++) {
for (long mid : palindromes0(digits - 2)) {
long value = i * high + mid * RADIX + i;
if (value < 0) {//overflow
return cache[digits] = Arrays.copyOf(result, size);
}
result[size++] = value;
}
}
return cache[digits] = result;
}
private static int sizeOf(int digits) {
return MAX_DIGIT * (int) Math.pow(RADIX, (digits - 1) >>> 1)
+ startingNonZerosTable[digits];
}
// v--- java -Xms1024m -Xmx2048m test.algorithm.Palindromes
public static void main(String[] args) {
Duration duration = timing(() -> {
// palindromes[1..15] ---v
LongSummaryStatistics result = since1(15).summaryStatistics();
long max = result.getMax();
long count = result.getCount();
System.out.printf("Max: %d, Count: %d%n", max, count);
});
System.out.printf("Time Elapsed:%s%n", duration);
// ^--- time elapsed: 4s
}
private static Duration timing(Runnable task) {
long starts = System.currentTimeMillis();
task.run();
return Duration.ofMillis(System.currentTimeMillis() - starts);
}
}
Time Cost:
palindromes[1..15] time elapsed: 4s
Have you tried working with characters rather than numbers? You could generate the palindrome as a string of digits and then convert to a number at the end. Something like this pseudocode:
generatePalindrome(size)
half <- size DIV 2 // Integer division
result <- ""
result.append(randomDigitIn(1..9)) // No leading zeros.
while (result.length <= half)
result.append(randomDigitIn(0..9))
endwhile
if (size is odd)
result <- result + randomDigitIn(0..9) + result.reverse()
else
result <- result + result.reverse()
endif
return number.parse(result)
end generatePalindrome()
Basically you randomly generate half the palindrome, avoiding leading zeros, insert an extra digit in the middle for odd lengths, append the reversed first half and then parse the digit string into the number format you want.
For odd digit you can simply reuse the palindromes generated at the previous even step , split them in half and insert in the middle all the possible number from 0 to 9.
Let's say you need to generate the palindrom of 3 digit, simply get all the palindromes of 2 digit and add insert all the number from 0 to 9.
We have 22 than we can generate:
202
212
222
232
and so on
Hope my idea is clear:)
Try something like this:
public class Palindrome
{
public static ArrayList<Long> calculatePalindromes(int maxLength) {
ArrayList<Long> result = new ArrayList<>();
if (maxLength <= 0) {
return result;
}
long maxPart = (long)Math.pow(10, maxLength / 2);
for (long i = 0; i < 10; ++i) {
result.add(i);
}
for (long i = 1; i < maxPart; ++i) {
long curHalf = i;
long curNum = i;
int curLen = 0;
while (curHalf != 0) {
curNum *= 10;
curNum += curHalf % 10;
curHalf /= 10;
++curLen;
}
result.add(curNum);
// insert numbers from 0 to 9
if (curLen * 2 + 1 > maxLength) {
continue;
}
for (int j = 0; j < 10; ++j) {
curHalf = i;
curNum = i;
curNum *= 10;
curNum += j;
while (curHalf != 0) {
curNum *= 10;
curNum += curHalf % 10;
curHalf /= 10;
}
result.add(curNum);
}
}
return result;
}
}
The idea is to insert numbers from 0 to 9 after each X and add reversed(X) after it so we get X (1..9) reversed(X).
You can generate all palindromes in the needed range without check, but you will probably face with the memory insufficiency, as storing all these numbesr for 15-length upper number in the list - is a bad idea.
More specifically your code will looks like:
long dig = (long) Math.pow(10, digits / 2);
int pow = 10;
int npow = 100;
for (long i = 1; i <= dig; i++) {
System.out.println(i * pow + inverse(i));
System.out.println(i * pow / 10 + inverse(i / 10));
// list.add(i * pow + inverse(i));
// list.add(i * pow/10 + inverse(i / 10));
if (i % pow == 0) {
pow = npow;
npow *= 10;
}
}
I have deliberately commented list adding lines.
The idea is to push into list/output all numbers composed with given half as:
XXXY+YXXX
and
XXX+Y+XXX
i.e. generating both cases: odd and even palindromes.
I am writing code for counting the number of ways an integer can be represented as a sum of the consecutive integers. For Example
15=(7+8),(1+2+3+4+5),(4+5+6). So the number of ways equals 3 for 15.
Now the input size can be <=10^12. My program is working fine till 10^7(i think so, but not sure as i didnt check it on any online judge. Feel free to check the code for that)
but as soon as the i give it 10^8 or higher integer as input. it throws many runtime exceptions(it doesnt show what runtime error). Thanks in advance.
import java.io.*;
//sum needs to contain atleast 2 elements
public class IntegerRepresentedAsSumOfConsecutivePositiveIntegers
{
public static long count = 0;
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
long num = Long.parseLong(br.readLine()); //Enter a number( <=10^12)
driver(num);
System.out.println("count = " + count);
}
public static void driver(long num)
{
long limit = num / 2;
for(long i = 1 ; i <= limit ; i++)
{
func(i,num);
}
}
public static void func(long i,long num)
{
if(i < num)
{
func(i + 1,num - i);
}
else if(i > num)
{
return;
}
else
{
count++;
}
}
}
Use some math: if arithmetic progression with difference 1 starts with a0 and contains n items, then its sum is
S = (2 * a0 + (n-1))/2 * n = a0 * n + n * (n-1) / 2
note that the second summand rises as quadratic function. So instead of checking all a0 in range S/2, we can check all n is smaller range
nmax = Ceil((-1 + Sqrt(1 + 8 * S)) / 2)
(I used some higher approximation).
Just test whether next expression gives integer positive result
a0 = (S - n * (n - 1) / 2) / n
Recursive function isn't suitable when you have big input size like your case.
The maximum depth of the java call stack is about 8900 calls and sometimes only after 7700 calls stack overflow occurs so it really depends on your program input size.
Try this algorithm I think it worked for your problem:
it will work fine until 10^9 after that it will take much more time to finish running the program.
long sum = 0;
int count = 0;
long size;
Scanner in = new Scanner(System.in);
System.out.print("Enter a number <=10^12: ");
long n = in.nextLong();
if(n % 2 != 0){
size = n / 2 + 1;
}
else{
size = n / 2;
}
for(int i = 1; i <= size; i++){
for(int j = i; j <= size; j++){
sum = sum + j;
if(sum == n){
sum = 0;
count++;
break;
}
else if(sum > n){
sum = 0;
break;
}
}
}
System.out.println(count);
Output:
Enter a number <=10^12: 15
3
Enter a number <=10^12: 1000000000
9
BUILD SUCCESSFUL (total time: 10 seconds)
There's a really excellent proof that the answer can be determined by solving for the unique odd factors (Reference). Essentially, for every odd factor of a target value, there exists either an odd series of numbers of that factor multiplied by its average to produce the target value, or an odd average equal to that factor that can be multiplied by double an even-sized series to reach the target value.
public static int countUniqueOddFactors(long n) {
if (n==1) return 1;
Map<Long, Integer> countFactors=new HashMap<>();
while ((n&1)==0) n>>>=1; // Eliminate even factors
long divisor=3;
long max=(long) Math.sqrt(n);
while (divisor <= max) {
if (n % divisor==0) {
if (countFactors.containsKey(divisor)) {
countFactors.put(divisor, countFactors.get(divisor)+1);
} else {
countFactors.put(divisor, 1);
}
n /= divisor;
} else {
divisor+=2;
}
}
int factors=1;
for (Integer factorCt : countFactors.values()) {
factors*=(factorCt+1);
}
return factors;
}
As #MBo noted, if a number S can be partitioned into n consecutive parts, then S - T(n) must be divisible by n, where T(n) is the n'th triangular number, and so you can count the number of partitions in O(sqrt(S)) time.
// number of integer partitions into (at least 2) consecutive parts
static int numberOfTrapezoidalPartitions(final long sum) {
assert sum > 0: sum;
int n = 2;
int numberOfPartitions = 0;
long triangularNumber = n * (n + 1) / 2;
while (sum - triangularNumber >= 0) {
long difference = sum - triangularNumber;
if (difference == 0 || difference % n == 0)
numberOfPartitions++;
n++;
triangularNumber += n;
}
return numberOfPartitions;
}
A bit more math yields an even simpler way. Wikipedia says:
The politeness of a positive number is defined as the number of ways it can be expressed as the sum of consecutive integers. For every x, the politeness of x equals the number of odd divisors of x that are greater than one.
Also see: OEIS A069283
So a simple solution with lots of room for optimization is:
// number of odd divisors greater than one
static int politeness(long x) {
assert x > 0: x;
int p = 0;
for (int d = 3; d <= x; d += 2)
if (x % d == 0)
p++;
return p;
}
CUSIPs are a 9-digit alphanumeric code for uniquely identifying a financial security.
https://en.wikipedia.org/wiki/CUSIP
They were invented in the 1964, and given the reliability of data transmission in the 60's, the 9th digit is actually a check digit used to confirm the validity of the first 8 characters. Sometimes, even today, you might find reason to want to validate a CUSIP, or perhaps a company or service obnoxiously decides to only transmit the 8-character CUSIP, even though this defeats the purpose of a check digit.
The procedure to generate the check digit is:
Convert non-numeric digits to values according to their ordinal position in the alphabet plus 9 (A=10, B=11,...Z=35) and converting the characters *=36, #=37, #=38.
Multiply every even digit by 2
If the result of the multiplication is a two-digit number, add the digits together. (12 = 1 + 2 = 3)
Get the sum of all values.
Get the floored value of this operation: (10 - (sum modulo 10)) modulo 10.
What is the best/simplest way to get this value in C#?
public string GenerateCheckDigit(string cusip)
{
int sum = 0;
char[] digits = cusip.ToUpper().ToCharArray();
string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ*##";
for (int i = 0; i < digits.Length; i++)
{
int val;
if (!int.TryParse(digits[i].ToString(), out val))
val = alphabet.IndexOf(digits[i]) + 10;
if ((i % 2) != 0)
val *= 2;
val = (val % 10) + (val / 10);
sum += val;
}
int check = (10 - (sum % 10)) % 10;
return check.ToString();
}
Edit:
.NET Fiddle demonstrating this: https://dotnetfiddle.net/kspQWl
If you pre-compute the values of check digits, and store them in a lookup table, your computation of check digit would become much simpler:
private static readonly int[,] Check = new int[128, 2];
static CusipCheckSum() {
var cusipChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ*##";
for (var i = 0 ; i != cusipChars.Length ; i++) {
Check[cusipChars[i], 0] = i%10 + i/10;
Check[cusipChars[i], 1] = 2*i%10 + 2*i/10;
}
}
With the 2D lookup array in place you can compute check digit in a single line of code:
var checkDigit = (10-(cusip.Select((ch, pos) => Check[ch, pos%2]).Sum()%10))%10;
I see that there is no algo for java so adding it as well:
String generateCusipCheckDigit(String cusip) {
final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ*##";
int sum = 0;
int value = 0;
char[] cusipChars = cusip.toUpperCase().toCharArray();
for (int i = 0; i < cusipChars.length; i++) {
char actualChar = cusipChars[i];
if (Character.isDigit(actualChar)) {
value = Integer.parseInt(String.valueOf(actualChar));
} else if (Character.isAlphabetic(actualChar)){
value = alphabet.indexOf(actualChar) + 10;
} else if (cusipChars[i] == '*'){
value = 36;
} else if (cusipChars[i] == '#'){
value = 37;
} else if (cusipChars[i] == '#'){
value = 38;
}
if ((i % 2) != 0){
value *= 2;
}
value = (value % 10) + (value / 10);
sum += value;
}
int check = (10 - (sum % 10)) % 10;
return String.valueOf(check);
}
and some tests:
#Test
void checkDigitTest1(){
String actual = generator.generateCusipCheckDigit("925524BF");
Assertions.assertEquals("6", actual);
}
#Test
void checkDigitTest2(){
String actual = generator.generateCusipCheckDigit("90284B96");
Assertions.assertEquals("2", actual);
}
#Test
void checkDigitTest3(){
String actual = generator.generateCusipCheckDigit("90284B97");
Assertions.assertEquals("0", actual);
}