package com.interview.leetcode.math;
/**
* Created_By: stefanie
* Date: 14-11-13
* Time: 下午9:03
*
* Handle the numbers
* 1. swap a and b without using extra variable {@link #swap(int, int)}
* 2. divide 2 numbers without using multiple, division and mod operation {@link #divide(int, int)}
* 3. calculate the sqrt of a number {@link #sqrt(int)}
* 4. reverse digits of an integer. {@link #reverse(int)}
* 5. calculate the n pow of x, which is x^n {@link #pow(double, int)}
* 6. Given a non-negative number represented as an array of digits, plus one to the number. {@link #plusOne(int[])}
* The digits are stored such that the most significant digit is at the head of the list.
* 7. Given a number, check if it's a palindrome. {@link #isPalindrome(int)}
*
*/
public class Numbers {
public static void swap(int a, int b){
a = a + b;
b = a - b; // a + b - b = a
a = a - b; // a + b - a = b
}
public static int[] generatePrim(int N) {
int[] primes = new int[N];
int k = 0;
int i = 2;
while(k < N){
int j = 0;
for(; j < k; j++){
if(i % primes[j] == 0) break;
}
if(j == k) primes[k++] = i;
i++;
}
return primes;
}
public static int divide(int dividend, int divisor) {
boolean negative = (dividend > 0 && divisor < 0) ||
(dividend < 0 && divisor > 0);
long a = Math.abs((long)dividend);
long b = Math.abs((long)divisor);
int ans = 0;
while (a >= b) {
int shift = 0;
while ((b << shift) <= a) {
shift++;
}
ans += 1 << (shift-1);
a = a - (b << (shift-1));
}
return negative ? -ans : ans;
}
public static int sum(int a, int b){
int sum, carry;
do {
sum = a ^ b;
carry = (a & b) << 1;
a = sum;
b = carry;
} while (b != 0);
return a;
}
/**
* do binary search between 0 ~ x, to find target * target = x
*/
public static int sqrt(int x) {
long lo = 0;
long hi = x;
while (hi >= lo) {
long mid = (hi + lo)/2;
if (x < mid * mid) {
hi = mid-1; // not hi = mid
} else {
lo = mid+1;
}
}
return (int) hi;
}
/**
* ret = ret * 10 + x % 10 and x /= 10 until x == 0
* handle overflow/underflow by check the abs
*/
public int reverse(int x) {
int ret = 0;
while (x != 0) {
// handle overflow/underflow
if (Math.abs(ret) > 214748364) {
return 0;
}
ret = ret * 10 + x % 10;
x /= 10;
}
return ret;
}
/**
* use recursively call, and should consider n be positive and negative
* 1. the edge case is:
* n == 0 return 1
* n == 1 return x;
* n == -1 return 1.0/x
* 2. do the recursively call
* when n is even: pow(x, n / 2) * pow(x, n / 2);
* when n is odd: pow(x, n / 2) * pow(x, n / 2) * (x or 1.0/x based on n > 0 or n < 0)
*/
public double pow(double x, int n) {
if(n == 0) return 1;
else if(n == 1) return x;
else if(n == -1) return 1.0 / x;
if(n % 2 == 0){
double pow = pow(x, n / 2);
return pow * pow;
} else {
if(n > 0){
double pow = pow(x, (n - 1)/2);
return pow * pow * x;
} else {
double pow = pow(x, (n + 1)/2);
return pow * pow * (1.0/x);
}
}
}
/**
* using carry to hold when sum larger than 10
*/
public int[] plusOne(int[] digits) {
int carry = 1;
for(int i = digits.length - 1; i >= 0; i--){
int sum = digits[i] + carry;
digits[i] = sum % 10;
carry = sum / 10;
}
if(carry == 0) return digits;
int[] newDigits = new int[digits.length + 1];
newDigits[0] = 1;
for(int i = 1; i < newDigits.length; i++) newDigits[i] = digits[i - 1];
return newDigits;
}
/**
* recursively call given a reverse of scanned number
*/
public boolean isPalindrome(int x) {
if(x < 0) return false;
return isPalindrome(x, 0);
}
/**
* prev is the reverse of scanned x.
*/
private boolean isPalindrome(int x, int prev){
int mod = x % 10;
prev = prev * 10 + mod;
if(prev == x) return true; //odd offset
x = x / 10;
if(prev == x) return true; //even offset
if(prev == 0 && x != 0) return false;
//when the lower offset contains 0, and higher is not empty, shouldn't have palindrome,
//since the highest offset can't be 0
if(x > 0) return isPalindrome(x, prev);
else return false;
}
/**
* define a clear scan sequence for valid, use sign = -1/1 as the flag for positive and negative
*/
static int max = Integer.MAX_VALUE / 10;
public static int atoi(String str) {
int i = 0; int sign = 1; int n = str.length(); int num = 0;
while (i < n && Character.isWhitespace(str.charAt(i))) i++;
if(i < n && str.charAt(i) == '+') i++;
else if(i < n && str.charAt(i) == '-'){
sign = -1;
i++;
}
while(i < n && Character.isDigit(str.charAt(i))){
int digit = Character.getNumericValue(str.charAt(i));
if(num > max || num == max && digit >= 8)
return sign == 1? Integer.MAX_VALUE : Integer.MIN_VALUE;
num = num * 10 + digit;
i++;
}
return sign * num;
}
/**
* define a clear scan sequence for valid
*/
public boolean isNumber(String str) {
int i = 0; int n = str.length(); boolean isNumber = false;
while(i < n && Character.isWhitespace(str.charAt(i))) i++;
if(i < n && (str.charAt(i) == '+' || str.charAt(i) == '-')) i++;
while(i < n && Character.isDigit(str.charAt(i))){
isNumber = true;
i++;
}
if(i < n && str.charAt(i) == '.'){
i++;
while(i < n && Character.isDigit(str.charAt(i))) {
isNumber = true;
i++;
}
}
if(isNumber && i < n && str.charAt(i) == 'e'){
i++;
isNumber = false;
if(i < n && (str.charAt(i) == '+' || str.charAt(i) == '-')) i++;
while(i < n && Character.isDigit(str.charAt(i))) {
isNumber = true;
i++;
}
}
while(i < n && Character.isWhitespace(str.charAt(i))) i++;
return isNumber && i == n;
}
}