Java Fibonacci for loop variable - java

This is a program which takes a command line variable, parses it into an int and the output is the fibonacci number equal to that cmd line argument. So if i enter 7, the output will be 13. since: 1 1 2 3 5 8 13
Can someone explain the b = a; inside the for loop? Since they're both already equal to 1, why do they need to be set equal to eachother?
int a,b,c;
int n = Integer.parseInt(args[0]);
a = 1;
b = 1;
c = 0;
if (n == 1 || n == 2)
System.out.println(1);
else
{
for (int i = 3; i<=n; i++)
{
c = a + b;
b = a;
a = c;
}
System.out.println(c);
}
}

a and b are equal to 1 initially, so on the first iteration of the loop, this statement does nothing. But let's look at what happens on later iterations:
Initial state:
a = 1
b = 1
c = 0
Iteration 1:
c = 1 + 1 = 2
b = a = 1
a = c = 2
Iteration 2:
c = 1 + 2 = 3
b = a = 2
a = c = 3
Iteration 3:
c = 2 + 3 = 5
b = a = 3
a = c = 5
Essentially, a stores the previous number in the sequence, while b stores the second to last. Since the first 2 numbers of the sequence are 1, 1, b will stay as 1 for two iterations, but then change later on.

Fn = Fn-1 + Fn-2, i.e. for starting from a = 1 and b = 1, you have to calculate next fibonacci number and move a and b to the one position right.
public static long fibonacci(int n) {
n = Math.abs(n);
if (n == 0)
return 0;
if (n < 3)
return 1;
long a = 1;
long b = 1;
long c = 0;
for (int i = 3; i <= n; i++) {
c = a + b;
b = a;
a = c;
}
return c;
}

Related

Make a sequence an increasing sequence by adding a number multiple times

I have an array of numbers, now I want to make this as increasing sequence by adding a fixed number b. I want to find how many times the fixed number b is added to make my array as increasing sequence.
Here is the program which is working:
int process(int[] a, int b) {
int count = 0;
for (int i = 0; i + 1 < a.length; i++) {
int current = a[i];
int next = a[i + 1];
// add b to next element if it is less than current
while (next <= current) {
next += b;
count++;
}
a[i + 1] = next;
}
return count;
}
Example:
int[] a = { 1, 3, 3, 2 };
int B = 2;
Output is 3
Explanation:
a[1] = 3 & a[2] = 3, so increment a[2] by B so a[2] = 3+2 = 5
Now a[2] = 5 & a[3]=2, so incremease a[3] by multiple of B so it is more than a[2], so a[3] = 2 + 2*2 = 6
So we have incremented 3 times, so the output is 3.
The time complexity of this program is O(N^2), but I was asked to reduce the time complexity of this program further. What is the better approach?
This should solve the problem in O(n):
int process(int[] a, int b) {
int count = 0, dif = 0, add = 0;
for (int i = 1; i < a.length; i++) {
dif = a[i] - a[i - 1];
if(dif < 0){
dif = Math.abs(dif);
add = (dif / b);
if(a[i - 1] + (add * b) >= a[i]) add++;
a[i] += add * b;
count += add;
}
else if(dif == 0){
a[i] += b;
count ++;
}
}
return count;
}
The idea is to take the difference between adjacent numbers and evaluate how many Bs you need to add, which is the difference divided by B.
If adjacent numbers are equal, just add a single B.

Java for loop is hard to understand

May someone explain to me why the following blocks of code generate such different outputs?
public class hello
{
public static void main(String args[])
{
int a,b,c;
for (a = 0; a < 5; a++)
{
for (b = 4; b >= a; b--)
{
System.out.print(" ");
}
for (c = 0; c <= a - b; c++)
{
System.out.print("*");
}
System.out.println();
}
}
}
Output:
public class hello
{
public static void main(String args[])
{
int a,b,c;
for (a = 0; a < 5; a++)
{
for (b = 4; b >= 0; b--)
{
System.out.print(" ");
}
for (c = 0; c <= a - b; c++)
{
System.out.print("*");
}
System.out.println();
}
}
}
Output:
Shouldnt the outputs be the same since b >= a is equivalent to b >= 0 as b's value will be deducted by 1 for every loop?
No, the outputs cannot be the same, since every time you are executing
for (a = 0; a < 5; a++)
this gets executed as well (5 times)
for (b = 4; b >= a; b--)
{
System.out.print(" ");
}
But the value of a is changing with every iteration: a will be initially 0, then 1, 2, 3 and finally 4.
Hence, the number of spaces that you are printing in the first scenario will decrease with every iteration of a.
For a = 0 we have:
b = 4,
b = 3,
b = 2,
b = 1,
b = 0 (for loop stops since b=-1 is not >= a=0)
For a = 1 we have:
b = 4,
b = 3,
b = 2,
b = 1 (for loop stops since b=0 is not >= a=1)
For a = 2 we have:
b = 4,
b = 3,
b = 2 (for loop stops since b=1 is not >= a=2)
For a = 3 we have:
b = 4,
b = 3 (for loop stops since b=2 is not >= a=3)
For a = 4 we have:
b = 4 (for loop stops since b=3 is not >= a=4)
variable a will go from 0 to 4, so for each iteration you will have:
for (b = 4; b >= 0; b--)
{ [...]
for (b = 4; b >= 1; b--)
{ [...]
for (b = 4; b >= 2; b--)
{ [...]
Please read the comments in the code and you will se the difference!
int a, b, c;
for (a = 0; a < 5; a++)
{
for (b = 4; b >= a; b--) // Print every time b-a + 1 underscores... since you start every time with b=4 you have for each a one space fewer
{
System.out.print(" ");
}
for (c = 0; c <= a - b; c++) // and then print (a-b)-c +1 stars (b is every time a-1)...
// (first a=0 -b=-1)+1=2 and any time it will prit 2 stars scince
{
System.out.print("*");
}
System.out.println();
}
for (a = 0; a < 5; a++)
{
for (b = 4; b >= 0; b--) // Print every time b-a + 1=4 underscores
{
System.out.print(" ");
}
for (c = 0; c <= a - b; c++) // and then print (a-b)-c +1 stars (b is every time -1)...
// first time ( a=0 -b=-1)+1 =2 , second time (a=1 - b=-1)+1=3
{
System.out.print("*");
}
System.out.println();
}

the next palindrome in Java [duplicate]

Firstly here is the problem:
A positive integer is called a palindrome if its representation in the decimal system is the same when read from left to right and from right to left. For a given positive integer K of not more than 1000000 digits, write the value of the smallest palindrome larger than K to output. Numbers are always displayed without leading zeros.
Input: The first line contains integer t, the number of test cases. Integers K are given in the next t lines.
Output: For each K, output the smallest palindrome larger than K.
Example
Input:
2
808
2133
Output:
818
2222
Secondly here is my code:
// I know it is bad practice to not cater for erroneous input,
// however for the purpose of the execise it is omitted
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.lang.Exception;
import java.math.BigInteger;
public class Main
{
public static void main(String [] args){
try{
Main instance = new Main(); // create an instance to access non-static
// variables
// Use java.util.Scanner to scan the get the input and initialise the
// variable
Scanner sc=null;
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
String input = "";
int numberOfTests = 0;
String k; // declare any other variables here
if((input = r.readLine()) != null){
sc = new Scanner(input);
numberOfTests = sc.nextInt();
}
for (int i = 0; i < numberOfTests; i++){
if((input = r.readLine()) != null){
sc = new Scanner(input);
k=sc.next(); // initialise the remainder of the variables sc.next()
instance.palindrome(k);
} //if
}// for
}// try
catch (Exception e)
{
e.printStackTrace();
}
}// main
public void palindrome(String number){
StringBuffer theNumber = new StringBuffer(number);
int length = theNumber.length();
int left, right, leftPos, rightPos;
// if incresing a value to more than 9 the value to left (offset) need incrementing
int offset, offsetPos;
boolean offsetUpdated;
// To update the string with new values
String insert;
boolean hasAltered = false;
for(int i = 0; i < length/2; i++){
leftPos = i;
rightPos = (length-1) - i;
offsetPos = rightPos -1; offsetUpdated = false;
// set values at opposite indices and offset
left = Integer.parseInt(String.valueOf(theNumber.charAt(leftPos)));
right = Integer.parseInt(String.valueOf(theNumber.charAt(rightPos)));
offset = Integer.parseInt(String.valueOf(theNumber.charAt(offsetPos)));
if(left != right){
// if r > l then offest needs updating
if(right > left){
// update and replace
right = left;
insert = Integer.toString(right);
theNumber.replace(rightPos, rightPos + 1, insert);
offset++; if (offset == 10) offset = 0;
insert = Integer.toString(offset);
theNumber.replace(offsetPos, offsetPos + 1, insert);
offsetUpdated = true;
// then we need to update the value to left again
while (offset == 0 && offsetUpdated){
offsetPos--;
offset =
Integer.parseInt(String.valueOf(theNumber.charAt(offsetPos)));
offset++; if (offset == 10) offset = 0;
// replace
insert = Integer.toString(offset);
theNumber.replace(offsetPos, offsetPos + 1, insert);
}
// finally incase right and offset are the two middle values
left = Integer.parseInt(String.valueOf(theNumber.charAt(leftPos)));
if (right != left){
right = left;
insert = Integer.toString(right);
theNumber.replace(rightPos, rightPos + 1, insert);
}
}// if r > l
else
// update and replace
right = left;
insert = Integer.toString(right);
theNumber.replace(rightPos, rightPos + 1, insert);
}// if l != r
}// for i
System.out.println(theNumber.toString());
}// palindrome
}
Finally my explaination and question.
My code compares either end and then moves in
if left and right are not equal
if right is greater than left
(increasing right past 9 should increase the digit
to its left i.e 09 ---- > 10) and continue to do
so if require as for 89999, increasing the right
most 9 makes the value 90000
before updating my string we check that the right
and left are equal, because in the middle e.g 78849887
we set the 9 --> 4 and increase 4 --> 5, so we must cater for this.
The problem is from spoj.pl an online judge system. My code works for all the test can provide but when I submit it, I get a time limit exceeded error and my answer is not accepted.
Does anyone have any suggestions as to how I can improve my algorithm. While writing this question i thought that instead of my while (offset == 0 && offsetUpdated) loop i could use a boolean to to make sure i increment the offset on my next [i] iteration. Confirmation of my chang or any suggestion would be appreciated, also let me know if i need to make my question clearer.
This seems like a lot of code. Have you tried a very naive approach yet? Checking whether something is a palindrome is actually very simple.
private boolean isPalindrome(int possiblePalindrome) {
String stringRepresentation = String.valueOf(possiblePalindrome);
if ( stringRepresentation.equals(stringRepresentation.reverse()) ) {
return true;
}
}
Now that might not be the most performant code, but it gives you a really simple starting point:
private int nextLargestPalindrome(int fromNumber) {
for ( int i = fromNumber + 1; ; i++ ) {
if ( isPalindrome( i ) ) {
return i;
}
}
}
Now if that isn't fast enough you can use it as a reference implementation and work on decreasing the algorithmic complexity.
There should actually be a constant-time (well it is linear on the number of digits of the input) way to find the next largest palindrome. I will give an algorithm that assumes the number is an even number of digits long (but can be extended to an odd number of digits).
Find the decimal representation of the input number ("2133").
Split it into the left half and right half ("21", "33");
Compare the last digit in the left half and the first digit in the right half.
a. If the right is greater than the left, increment the left and stop. ("22")
b. If the right is less than the left, stop.
c. If the right is equal to the left, repeat step 3 with the second-last digit in the left and the second digit in the right (and so on).
Take the left half and append the left half reversed. That's your next largest palindrome. ("2222")
Applied to a more complicated number:
1. 1234567887654322
2. 12345678 87654322
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ equal
3. 12345678 87654322
^ ^ greater than, so increment the left
3. 12345679
4. 1234567997654321 answer
This seems a bit similar to the algorithm you described, but it starts at the inner digits and moves to the outer.
There is no reason to fiddle with individual digits when the only needed operation is one simple addition. The following code is based on Raks' answer.
The code stresses simplicity over execution speed, intentionally.
import static org.junit.Assert.assertEquals;
import java.math.BigInteger;
import org.junit.Test;
public class NextPalindromeTest {
public static String nextPalindrome(String num) {
int len = num.length();
String left = num.substring(0, len / 2);
String middle = num.substring(len / 2, len - len / 2);
String right = num.substring(len - len / 2);
if (right.compareTo(reverse(left)) < 0)
return left + middle + reverse(left);
String next = new BigInteger(left + middle).add(BigInteger.ONE).toString();
return next.substring(0, left.length() + middle.length())
+ reverse(next).substring(middle.length());
}
private static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}
#Test
public void testNextPalindrome() {
assertEquals("5", nextPalindrome("4"));
assertEquals("11", nextPalindrome("9"));
assertEquals("22", nextPalindrome("15"));
assertEquals("101", nextPalindrome("99"));
assertEquals("151", nextPalindrome("149"));
assertEquals("123454321", nextPalindrome("123450000"));
assertEquals("123464321", nextPalindrome("123454322"));
}
}
Well I have constant order solution(atleast of order k, where k is number of digits in the number)
Lets take some examples
suppose n=17208
divide the number into two parts from middle
and reversibly write the most significant part onto the less significant one.
ie, 17271
if the so generated number is greater than your n it is your palindrome, if not just increase the center number(pivot) ie, you get 17371
other examples
n=17286
palidrome-attempt=17271(since it is less than n increment the pivot, 2 in this case)
so palidrome=17371
n=5684
palidrome1=5665
palidrome=5775
n=458322
palindrome=458854
now suppose n = 1219901
palidrome1=1219121
incrementing the pivot makes my number smaller here
so increment the number adjacent pivot too
1220221
and this logic could be extended
public class NextPalindrome
{
int rev, temp;
int printNextPalindrome(int n)
{
int num = n;
for (int i = num+1; i >= num; i++)
{
temp = i;
rev = 0;
while (temp != 0)
{
int remainder = temp % 10;
rev = rev * 10 + remainder;
temp = temp / 10;
}
if (rev == i)
{
break;
}
}
return rev;
}
public static void main(String args[])
{
NextPalindrome np = new NextPalindrome();
int nxtpalin = np.printNextPalindrome(11);
System.out.println(nxtpalin);
}
}
Here is my code in java. Whole idea is from here.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter number of tests: ");
int t = sc.nextInt();
for (int i = 0; i < t; i++) {
System.out.println("Enter number: ");
String numberToProcess = sc.next(); // ne proveravam dal su brojevi
nextSmallestPalindrom(numberToProcess);
}
}
private static void nextSmallestPalindrom(String numberToProcess) {
int i, j;
int length = numberToProcess.length();
int[] numberAsIntArray = new int[length];
for (int k = 0; k < length; k++)
numberAsIntArray[k] = Integer.parseInt(String
.valueOf(numberToProcess.charAt(k)));
numberToProcess = null;
boolean all9 = true;
for (int k = 0; k < length; k++) {
if (numberAsIntArray[k] != 9) {
all9 = false;
break;
}
}
// case 1, sve 9ke
if (all9) {
whenAll9(length);
return;
}
int mid = length / 2;
if (length % 2 == 0) {
i = mid - 1;
j = mid;
} else {
i = mid - 1;
j = mid + 1;
}
while (i >= 0 && numberAsIntArray[i] == numberAsIntArray[j]) {
i--;
j++;
}
// case 2 already polindrom
if (i == -1) {
if (length % 2 == 0) {
i = mid - 1;
j = mid;
} else {
i = mid;
j = i;
}
addOneToMiddleWithCarry(numberAsIntArray, i, j, true);
} else {
// case 3 not polindrom
if (numberAsIntArray[i] > numberAsIntArray[j]) { // 3.1)
while (i >= 0) {
numberAsIntArray[j] = numberAsIntArray[i];
i--;
j++;
}
for (int k = 0; k < numberAsIntArray.length; k++)
System.out.print(numberAsIntArray[k]);
System.out.println();
} else { // 3.2 like case 2
if (length % 2 == 0) {
i = mid - 1;
j = mid;
} else {
i = mid;
j = i;
}
addOneToMiddleWithCarry(numberAsIntArray, i, j, false);
}
}
}
private static void whenAll9(int length) {
for (int i = 0; i <= length; i++) {
if (i == 0 || i == length)
System.out.print('1');
else
System.out.print('0');
}
}
private static void addOneToMiddleWithCarry(int[] numberAsIntArray, int i,
int j, boolean palindrom) {
numberAsIntArray[i]++;
numberAsIntArray[j] = numberAsIntArray[i];
while (numberAsIntArray[i] == 10) {
numberAsIntArray[i] = 0;
numberAsIntArray[j] = numberAsIntArray[i];
i--;
j++;
numberAsIntArray[i]++;
numberAsIntArray[j] = numberAsIntArray[i];
}
if (!palindrom)
while (i >= 0) {
numberAsIntArray[j] = numberAsIntArray[i];
i--;
j++;
}
for (int k = 0; k < numberAsIntArray.length; k++)
System.out.print(numberAsIntArray[k]);
System.out.println();
}
}
Try this
public static String genNextPalin(String base){
//check if it is 1 digit
if(base.length()==1){
if(Integer.parseInt(base)==9)
return "11";
else
return (Integer.parseInt(base)+1)+"";
}
boolean check = true;
//check if it is all 9s
for(char a: base.toCharArray()){
if(a!='9')
check = false;
}
if(check){
String num = "1";
for(int i=0; i<base.length()-1; i++)
num+="0";
num+="1";
return num;
}
boolean isBasePalin = isPalindrome(base);
int mid = base.length()/2;
if(isBasePalin){
//if base is palin and it is odd increase mid and return
if(base.length()%2==1){
BigInteger leftHalf = new BigInteger(base.substring(0,mid+1));
String newLeftHalf = leftHalf.add(BigInteger.ONE).toString();
String newPalin = genPalin2(newLeftHalf.substring(0,mid),newLeftHalf.charAt(mid));
return newPalin;
}
else{
BigInteger leftHalf = new BigInteger(base.substring(0,mid));
String newLeftHalf = leftHalf.add(BigInteger.ONE).toString();
String newPalin = genPalin(newLeftHalf.substring(0,mid));
return newPalin;
}
}
else{
if(base.length()%2==1){
BigInteger leftHalf = new BigInteger(base.substring(0,mid));
BigInteger rightHalf = new BigInteger(reverse(base.substring(mid+1,base.length())));
//check if leftHalf is greater than right half
if(leftHalf.compareTo(rightHalf)==1){
String newPalin = genPalin2(base.substring(0,mid),base.charAt(mid));
return newPalin;
}
else{
BigInteger leftHalfMid = new BigInteger(base.substring(0,mid+1));
String newLeftHalfMid = leftHalfMid.add(BigInteger.ONE).toString();
String newPalin = genPalin2(newLeftHalfMid.substring(0,mid),newLeftHalfMid.charAt(mid));
return newPalin;
}
}
else{
BigInteger leftHalf = new BigInteger(base.substring(0,mid));
BigInteger rightHalf = new BigInteger(reverse(base.substring(mid,base.length())));
//check if leftHalf is greater than right half
if(leftHalf.compareTo(rightHalf)==1){
return genPalin(base.substring(0,mid));
}
else{
BigInteger leftHalfMid = new BigInteger(base.substring(0,mid));
String newLeftHalfMid = leftHalfMid.add(BigInteger.ONE).toString();
return genPalin(newLeftHalfMid);
}
}
}
}
public static String genPalin(String base){
return base + new StringBuffer(base).reverse().toString();
}
public static String genPalin2(String base, char middle){
return base + middle +new StringBuffer(base).reverse().toString();
}
public static String reverse(String in){
return new StringBuffer(in).reverse().toString();
}
static boolean isPalindrome(String str) {
int n = str.length();
for( int i = 0; i < n/2; i++ )
if (str.charAt(i) != str.charAt(n-i-1))
return false;
return true;
}
HI Here is another simple algorithm using python,
def is_palindrome(n):
if len(n) <= 1:
return False
else:
m = len(n)/2
for i in range(m):
j = i + 1
if n[i] != n[-j]:
return False
return True
def next_palindrome(n):
if not n:
return False
else:
if is_palindrome(n) is True:
return n
else:
return next_palindrome(str(int(n)+1))
print next_palindrome('1000010')
I have written comments to clarify what each step is doing in this python code.
One thing that need to be taken into consideration is that input can be very large that we can not simply perform integer operations on it. So taking input as string and then manipulating it would be much easier.
tests = int(input())
results = []
for i in range(0, tests):
pal = input().strip()
palen = len(pal)
mid = int(palen/2)
if palen % 2 != 0:
if mid == 0: # if the number is of single digit e.g. next palindrome for 5 is 6
ipal = int(pal)
if ipal < 9:
results.append(int(pal) + 1)
else:
results.append(11) # for 9 next palindrome will be 11
else:
pal = list(pal)
pl = l = mid - 1
pr = r = mid + 1
flag = 'n' # represents left and right half of input string are same
while pl >= 0:
if pal[pl] > pal[pr]:
flag = 'r' # 123483489 in this case pal[pl] = 4 and pal[pr] = 3 so we just need to copy left half in right half
break # 123484321 will be the answer
elif pal[pl] < pal[pr]:
flag = 'm' # 123487489 in this case pal[pl] = 4 and pal[pr] = 9 so copying left half in right half will make number smaller
break # in this case we need to take left half increment by 1 and the copy in right half 123494321 will be the anwere
else:
pl = pl -1
pr = pr + 1
if flag == 'm' or flag == 'n': # increment left half by one and copy in right half
if pal[mid] != '9': # if mid element is < 9 the we can simply increment the mid number only and copy left in right half
pal[mid] = str(int(pal[mid]) + 1)
while r < palen:
pal[r] = pal[l]
r = r + 1
l = l - 1
results.append(''.join(pal))
else: # if mid element is 9 this will effect entire left half because of carry
pal[mid] = '0' # we need to take care of large inputs so we can not just directly add 1 in left half
pl = l
while pal[l] == '9':
pal[l] = '0'
l = l - 1
if l >= 0:
pal[l] = str(int(pal[l]) + 1)
while r < palen:
pal[r] = pal[pl]
r = r + 1
pl = pl - 1
if l < 0:
pal[0] = '1'
pal[palen - 1] = '01'
results.append(''.join(pal))
else:
while r < palen: # when flag is 'r'
pal[r] = pal[l]
r = r + 1
l = l - 1
results.append(''.join(pal))
else: # even length almost similar concept here with flags having similar significance as in case of odd length input
pal = list(pal)
pr = r = mid
pl = l = mid - 1
flag = 'n'
while pl >= 0:
if pal[pl] > pal[pr]:
flag = 'r'
break
elif pal[pl] < pal[pr]:
flag = 'm'
break
else:
pl = pl -1
pr = pr + 1
if flag == 'r':
while r < palen:
pal[r] = pal[l]
r = r + 1
l = l - 1
results.append(''.join(pal))
else:
if pal[l] != '9':
pal[l] = str(int(pal[l]) + 1)
while r < palen:
pal[r] = pal[l]
r = r + 1
l = l - 1
results.append(''.join(pal))
else:
pal[mid] = '0'
pl = l
while pal[l] == '9':
pal[l] = '0'
l = l - 1
if l >= 0:
pal[l] = str(int(pal[l]) + 1)
while r < palen:
pal[r] = pal[pl]
r = r + 1
pl = pl - 1
if l < 0:
pal[0] = '1'
pal[palen - 1] = '01'
results.append(''.join(pal))
for xx in results:
print(xx)
We can find next palindrome easily like below.
private void findNextPalindrom(int i) {
i++;
while (!checkPalindrom(i)) {
i++;
}
Log.e(TAG, "findNextPalindrom:next palindrom is===" + i);
}
private boolean checkPalindrom(int num) {
int temp = num;
int rev = 0;
while (num > 0) {
int rem = num % 10;
rev = rev * 10 + rem;
num = num / 10;
}
return temp == rev;
}
Simple codes and test output:
class NextPalin
{
public static void main( String[] args )
{
try {
int[] a = {2, 23, 88, 234, 432, 464, 7887, 7657, 34567, 99874, 7779222, 2569981, 3346990, 229999, 2299999 };
for( int i=0; i<a.length; i++)
{
int add = findNextPalin(a[i]);
System.out.println( a[i] + " + " + add + " = " + (a[i]+add) );
}
}
catch( Exception e ){}
}
static int findNextPalin( int a ) throws Exception
{
if( a < 0 ) throw new Exception();
if( a < 10 ) return a;
int count = 0, reverse = 0, temp = a;
while( temp > 0 ){
reverse = reverse*10 + temp%10;
count++;
temp /= 10;
}
//compare 'half' value
int halfcount = count/2;
int base = (int)Math.pow(10, halfcount );
int reverseHalfValue = reverse % base;
int currentHalfValue = a % base;
if( reverseHalfValue == currentHalfValue ) return 0;
if( reverseHalfValue > currentHalfValue ) return (reverseHalfValue - currentHalfValue);
if( (((a-currentHalfValue)/base)%10) == 9 ){
//cases like 12945 or 1995
int newValue = a-currentHalfValue + base*10;
int diff = findNextPalin(newValue);
return base*10 - currentHalfValue + diff;
}
else{
return (base - currentHalfValue + reverseHalfValue );
}
}
}
$ java NextPalin
2 + 2 = 4
23 + 9 = 32
88 + 0 = 88
234 + 8 = 242
432 + 2 = 434
464 + 0 = 464
7887 + 0 = 7887
7657 + 10 = 7667
34567 + 76 = 34643
99874 + 25 = 99899
7779222 + 555 = 7779777
2569981 + 9771 = 2579752
3346990 + 443 = 3347433
229999 + 9933 = 239932
2299999 + 9033 = 2309032

Optimizing the largest palindrome from product of two three digit numbers?

I am working on an interview question which I was asked in which I was supposed to write a program to find the largest palindrome from product of two three digit numbers.
Here is the question
I came up with this brute force approach which starts from bottom.
public class LargestPalindromeQuestion {
public static void main(String[] args) {
int value = 0;
for (int i = 100; i <= 999; i++) {
for (int j = i; j <= 999; j++) {
int value1 = i * j;
if (isPalindrome(value1) && value < value1) {
value = value1;
}
}
}
System.out.println(value);
}
private static boolean isPalindrome(final int product) {
int p = product;
int reverse = 0;
while (p != 0) {
reverse *= 10;
reverse += p % 10;
p /= 10;
}
return reverse == product;
}
}
They asked me what are the optimizations I can do in this program? I mentioned that we can try pruning the search space and optimize checking step for each item in the search space but then I am confuse how would I make this work in my above solution?
What are the optimizations we can do in this program? Right now it is executing 810000 steps to find the largest palindrome.
What is the least number of steps we can execute to find the largest palindrome in two three digit numbers?
The program looks very good to me. I would make the i loop count from 999 down to 100, and I would only check j values that would actually give a larger product than the current maximum.
This program is able to finish surprisingly soon, at i == 952 to be precise. The mathematical reason for this is that once the solution 906609 (993 * 913) is found, it will no longer be possible to find a larger palindrome where the larger factor is less than the square-root of 906609, which is 952.160....
public static void main(String[] args) {
int value = 0;
for (int i = 999; i >= 100; i--) {
int r = value / i;
if (r >= i) {
System.out.println("We broke at i = " + i);
break;
}
for (int j = i; j > r; j--) {
int value1 = i * j;
if (isPalindrome(value1)) {
value = value1;
break;
}
}
}
System.out.println(value);
}
One pretty simple way of optimizing this would be to simply start with the highest 3-digit numbers instead of the smallest. Since the solution will most likely be closer to the pair (999 , 999) than to (100 , 100).
One useful mechanism to prune the search tree is to notice that the highest digit of the product a * b doesn't change often. E.g.
a = 111; b = 112 a*b = 12432
; b = 113 a*b = 12543
; b = 114 a*b = 12654
; ...
; b = 180 a*b = 19980
; b = 181 a*b = 20091 = (19980 + a)
Thus, for all the values in between (a = 111, a < b < 181), one already knows the MSB, which must equal to the LSB or (a % 10) * (b % 10) % 10 == MSB.
e.g.
LSB = 1 --> a % 10 == 1, b % 10 == 1
OR a % 10 == 3, b % 10 == 7
OR a % 10 == 7, b % 10 == 3
OR a % 10 == 9, b % 10 == 9
Most of the time there's either none, or just one candidate in set 'b' to be checked for any pair MSB, a % 10.
The least number of steps I could get to is 375. Consider multiplying the three-digit number, a1a2a3, by the three-digit number, b1b2b3:
JavaScript code:
var modHash = new Array(10);
var iterations = 0;
for (var i=1; i<10; i++){
modHash[i] = {0: [0]}
for (var j=1; j<10; j++){
iterations ++;
var r = i * j % 10;
if (modHash[i][r])
modHash[i][r].push(j);
else
modHash[i][r] = [j];
}
}
var highest = 0;
function multiples(x,y,carry,mod){
for (var i in modHash[x]){
var m = (10 + mod - i - carry) % 10;
if (modHash[y][m]){
for (var j in modHash[x][i]){
for (var k in modHash[y][m]){
iterations ++;
var palindrome = num(9,modHash[y][m][k],x,9,modHash[x][i][k],y);
if (x == 3 && mod == 0){
console.log(x + " * " + modHash[x][i][j] + " + "
+ y + " * " + modHash[y][m][k] + ": " + palindrome);
}
var str = String(palindrome);
if (str == str.split("").reverse().join("") && palindrome > highest){
highest = palindrome;
}
}
}
}
}
}
function num(a1,a2,a3,b1,b2,b3){
return (100*a1 + 10*a2 + a3)
* (100*b1 + 10*b2 + b3);
}
var a3b3s = [[7,7,4],[9,1,0],[3,3,0]];
for (var i in a3b3s){
for (var mod=0; mod<10; mod++){
var x = a3b3s[i][0],
y = a3b3s[i][1],
carry = a3b3s[i][2];
multiples(x,y,carry,mod);
}
}
console.log(highest);
console.log("iterations: " + iterations);
Output:
3 * 0 + 3 * 0: 815409
3 * 7 + 3 * 3: 907809
3 * 4 + 3 * 6: 908109
3 * 1 + 3 * 9: 906609
3 * 8 + 3 * 2: 907309
3 * 5 + 3 * 5: 908209
3 * 2 + 3 * 8: 907309
3 * 9 + 3 * 1: 906609
3 * 6 + 3 * 4: 908109
3 * 3 + 3 * 7: 907809
906609
iterations: 375
First optimize isPalindrome by seperating 6 digits as 3 digits. i.e. N = ABCDEF => a = ABC = N/1000, b = DEF = N%1000; Then reverse b and return a==reversed_b;
Secondly while producing palindromes loop through till max_palindrome_so_far/999 which is the minimum value that you would use. max_palindrome_so_far is initially equals N.
public class Solution {
public static boolean isPalindrome(int n){
int a = n/1000;
int b = n%1000;
int d, r = 0, i = 3;
while(i-- > 0){
d = b%10;
r = r*10 + d;
b = b/10;
}
if (a == r)
return true;
return false;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
for(int a0 = 0; a0 < t; a0++){
int n = in.nextInt();
int r=0, m=n;
int i,j;
for(i = 999;i>=100;i--){
for(j = 999;j>=m/999;j--){
if (i*j < n && i*j > 100000 && isPalindrome(i*j)){
r = Math.max(i*j, r);
m = r;
}
}
}
// System.out.println(i + " * " + j + " = " + i*j);
System.out.println(r);
}
}
}

Printing all Possible nCr Combinations in Java

I'm trying to print out all possibilities of nCr, which are the combinations when order doesn't matter. So 5C1 there are 5 possibilities: 1 , 2, 3, 4, 5. 5C2 there are 10 possibilities: 1 2, 1 3, 1 4, 1 5, 2 3, 2 4, 2 5, 3 4, 3 5, 4 5.
I made functions that print what I want for r = 2, r = 3, and r = 4, and I sort of see the pattern, but I cant seem to make a working method for variable r:
public void printCombinationsChoose2(int n, int k) //for when k = 2
{
for (int a = 1; a < n; a++)
{
for (int b = a + 1; b <= n; b++)
{
System.out.println("" + a + " " + b);
}
}
}
public void printCombinationsChoose3(int n, int k) //for when k = 3
{
for (int a = 1; a < n - 1; a++)
{
for (int b = a + 1; b < n; b++)
{
for (int c = b + 1; c <= n; c++)
{
System.out.println("" + a + " " + b + " " + c);
}
}
}
}
public void printCombinationsChoose4(int n, int k) //for when k = 4
{
for (int a = 1; a < n - 2; a++)
{
for (int b = a + 1; b < n - 1; b++)
{
for (int c = b + 1; c < n; c++)
{
for (int d = c + 1; d <= n; d++)
{
System.out.println("" + a + " " + b + " " + c + " " + d);
}
}
}
}
}
public void printCombinations(int n, int k) //Doesn't work
{
int[] nums = new int[k];
for (int i = 1; i <= nums.length; i++)
nums[i - 1] = i;
int count = 1;
while (count <= k)
{
for (int a = nums[k - count]; a <= n; a++)
{
nums[k - count] = a;
for (int i = 0; i < nums.length; i++)
System.out.print("" + nums[i] + " ");
System.out.println();
}
count++;
}
}
So I think the layout of my last method is right, but I'm just not doing the right things, because when I call printCominbations(5, 2), it prints
1 2
1 3
1 4
1 5
1 5
2 5
3 5
4 5
5 5
when it should be what I said earlier for 5C2.
Edit
The last example was bad. This is a better one to illustrate what it's doing wrong: printCombinations(5, 3) gives this:
1 2 3
1 2 4
1 2 5
1 2 5
1 3 5
1 4 5
1 5 5
1 5 5
2 5 5
3 5 5
4 5 5
5 5 5
How do I get it to be:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
How about this:
public class Test {
public static void main(final String[] args) {
print_nCr(7, 4);
}
public static final void print_nCr(final int n, final int r) {
int[] res = new int[r];
for (int i = 0; i < res.length; i++) {
res[i] = i + 1;
}
boolean done = false;
while (!done) {
System.out.println(Arrays.toString(res));
done = getNext(res, n, r);
}
}
/////////
public static final boolean getNext(final int[] num, final int n, final int r) {
int target = r - 1;
num[target]++;
if (num[target] > ((n - (r - target)) + 1)) {
// Carry the One
while (num[target] > ((n - (r - target)))) {
target--;
if (target < 0) {
break;
}
}
if (target < 0) {
return true;
}
num[target]++;
for (int i = target + 1; i < num.length; i++) {
num[i] = num[i - 1] + 1;
}
}
return false;
}
}
The key to this solution for me was to look at the problem as a numbering system and you want to increase a number by one and every time you reach an upper bound, you just carry the excess to the left one and ... You just need to implement the increasing algorithm correctly...
The first point where your code deviates from the expectation is here:
...
1 2 5
1 2 5 <-- first bad output
1 3 5
...
So ask yourself three things:
What should have happened in that line of code with the given state of the variables?
Why doesn't do my code exactly that?
What must be changed to achieve that?
The answer for the first part is like this:
It should have incremented the 2 to 3 and it should have set the following numbers to
4, 5, ... similar to the initialisation of nums.
The second and third part is your part again.
BTW: When you come back because you need more help, please explain in detail what you have deduced so far and clean up and shorten the question quite a bit.
OK... What is the solution when we know we need loops, but not the number of them?? RECURSION...
You need to use a recursive implementation. Have this in mind: ANYTIME, you need loops but the number of the nested loops can only be known at runtime, based on the specific parameters of the problem, you should use recursive methods... I'll give you some time to try it yourself, I'll be back to give you the final implementation...
I have done it in c++
#include <iostream>
using namespace std;
#define ARR_LIMIT 100
int arr[ARR_LIMIT];
void _ncr(int N,int R, int n,int r , int start )
{
if(r>0)
{
for(int i = start ; i <= start + (n-r); i++)
{
arr[R-r] = i;
_ncr(N,R,N-i, r-1, i+1 );
}
}
else
{
for(int i=0;i<R;i++)
{
cout << arr[i] << " ";
if(i==R-1)
cout<<"\n";
}
}
}
void ncr(int n,int r)
{
//Error checking of parameters
bool error = false;
if( n < 1)
{
error = true;
cout<< "ERROR : n should be greater 0 \n";
}
if( r < 1)
{
error = true;
cout<< "ERROR : r should be greater 0 \n";
}
if(r > n)
{
error = true;
cout<< "ERROR : n should be greater than or equal to r \n";
}
// end of Error checking of parameters
if(error)
return;
else
_ncr(n,r,n,r,1);
}
int main()
{
int n,r;
cout << "Enter n : ";
cin >> n;
cout << "Enter r : ";
cin >> r;
ncr(n,r);
return 0;
}
The layout of function printCombination() seems wrong. The while loop will iterate two times, for count = 1 and count = 2.
When count = 1, only values in nums[0][here] will change, since in this case k - count = 1.
Hence,
1,2
1,3
1,4 and
1,5.
And when count = 2, only values in nums[here][1] will change, since here k - count = 0.
Hence
1,5
2,5
3,5
4,5 and
5,5

Categories