Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
3 views14 pages

CP Unit-2

Uploaded by

vaihan1528
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views14 pages

CP Unit-2

Uploaded by

vaihan1528
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

We cannot use BigInteger or directly convert to integers, so we must add digit by digit

(like we do on paper).

Steps (Algorithm):

1.​ Start from the last digit (units place) of both strings.​

2.​ Add the two digits + carry.​

3.​ Store the result digit (sum % 10) in a StringBuilder.​

4.​ Carry forward (sum / 10) to the next step.​

5.​ Continue until both strings are fully traversed and no carry is left.​

6.​ Reverse the StringBuilder (since digits were added from right to left).​

7.​ Return the final string.​

public static String addStrings(String num1, String num2) {


StringBuilder result = new StringBuilder();

int i = num1.length() - 1; // pointer for num1


int j = num2.length() - 1; // pointer for num2
int carry = 0;

while (i >= 0 || j >= 0 || carry != 0) {


int digit1 = (i >= 0) ? num1.charAt(i) - '0' : 0;
int digit2 = (j >= 0) ? num2.charAt(j) - '0' : 0;

int sum = digit1 + digit2 + carry;


result.append(sum % 10); // store unit digit
carry = sum / 10; // update carry

i--;
j--;
}
return result.reverse().toString();
}
Time Complexity Analysis

●​ Each digit of both numbers is processed once.​

●​ Suppose m = length(num1), n = length(num2).​

●​ The loop runs at most max(m, n) times.​

●​ Each iteration does O(1) operations.​

●​ Reversing the StringBuilder also takes O(max(m, n)).

✅ Time Complexity: O(max(m, n))​


✅ Space Complexity: O(max(m, n)) (to store result string).
MULTIPLICATION :

public static String multiply(String num1, String num2) {


if (num1.equals("0") || num2.equals("0")) return "0";

int m = num1.length();
int n = num2.length();
int[] product = new int[m + n]; // maximum digits

// Multiply each digit


for (int i = m - 1; i >= 0; i--) {
for (int j = n - 1; j >= 0; j--) {
int mul = (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
int sum = mul + product[i + j + 1];

product[i + j] += sum / 10; // carry


product[i + j + 1] = sum % 10; // store remainder
}
}

// Build result string


StringBuilder result = new StringBuilder();
for (int num : product) {
if (!(result.length() == 0 && num == 0)) { // skip leading zeros
result.append(num);
}
}

return result.toString();


Time Complexity = O(m × n)​
Space Complexity = O(m + n) (for product array, final result string).
Modular Binary Exponentiation
Modular Binary Exponentiation (a.k.a. Fast Exponentiation or Exponentiation by Squaring)
is a method to compute

efficiently in O(log n) time by repeatedly squaring.

Recursive Version (Java)

public static long powerRecursive(long a, long n, long m) {


if (n == 0) return 1 % m;

long half = powerRecursive(a, n / 2, m);


long result = (half * half) % m;

if (n % 2 == 1) {
result = (result * a) % m;
}

return result;
}

Iterative version (java)

public static long powerIterative(long a, long n, long m) {


long result = 1;
a = a % m; // reduce base first

while (n > 0) {
if ((n & 1) == 1) { // if n is odd
result = (result * a) % m;
}
a = (a * a) % m; // square the base
n >>= 1; // divide n by 2
}
return result;
}
Modular Fast Multiplication:

It is a technique to compute efficiently without


causing overflow, by breaking multiplication into smaller steps
using divide-and-conquer.

Recursive Version
public static long modMultiplyRecursive(long a, long b, long m) {
if (b == 0) return 0;

long half = modMultiplyRecursive(a, b / 2, m);


long result = (half + half) % m;

if (b % 2 == 1) {
result = (result + a) % m;
}
return result;
}

Iterative Version (Java)

public static long modMultiplyIterative(long a, long b, long m) {


long result = 0;
a = a % m;

while (b > 0) {
if ((b & 1) == 1) { // if b is odd
result = (result + a) % m;
}
a = (2 * a) % m;
b >>= 1; // divide b by 2
}

return result;
}
Tribonacci series:

The Tribonacci series is defined as:

Transformation Matrix T

MATRIX EXPONENTION
static long[][] multiply(long[][] A, long[][] B) {
long[][] C = new long[2][2];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % MOD;
}
}
}
return C;
}

// Fast matrix exponentiation


static long[][] power(long[][] M, int exp) {
long[][] result = { {1, 0}, {0, 1} }; // Identity matrix
while (exp > 0) {
if ((exp & 1) == 1) result = multiply(result, M);
M = multiply(M, M);
exp >>= 1;
}
return result;
}

// Compute nth Fibonacci


static long fibonacci(int n) {
if (n == 0) return 0;
long[][] F = { {1, 1}, {1, 0} };
long[][] Fn = power(F, n - 1);
return Fn[0][0]; // F(n)
}

// Compute sum of Fibonacci numbers up to F(n)


public static long fibonacciSum(int n) {
if (n < 0) return 0;
return (fibonacci(n + 2) - 1 + MOD) % MOD;
}
floating-point errors

Floating-point numbers (IEEE-754 standard) represent real numbers


with finite binary precision. This leads to errors programmers often
overlook. Here are four common pitfalls, each with explanation and
example:

1. Precision/Representation Error:
Computers store floating-point numbers in binary (base-2). Some
decimal numbers cannot be represented exactly in binary.

Why? 0.1 and 0.2 cannot be represented exactly in binary


floating-point, so small rounding errors appear.

2) Rounding Error

●​ During calculations, results are rounded to the nearest


representable number

Why? 1/3 is an infinite decimal and must be rounded to fit finite bits.​
3) Loss of Significance (Cancellation Error)

●​ When subtracting two very close numbers, most significant digits


cancel out, leaving only rounding noise.

●​ Why? Subtraction amplifies tiny floating-point representation


errors.​

4) Overflow and Underflow

●​ Overflow: When a number is too large to represent → becomes


Infinity.​

●​ Underflow: When a number is too small (close to 0) → becomes


0.0.​

●​ Example:


Given an array of integers arr[] of size n and an integer k,
count the number of non-empty subarrays whose sum is
divisible by k.Formally, count pairs (i, j) such that:

Java Implementation
public class SubarrayDivisibleByK {
public static int countSubarraysDivByK(int[] nums, int k) {
Map<Integer, Integer> count = new HashMap<>();
count.put(0, 1); // remainder 0 occurs once initially

int prefix = 0, result = 0;

for (int num : nums) {


prefix += num;
int remainder = prefix % k;

if (remainder < 0) remainder += k; // handle negative values

if (count.containsKey(remainder)) {
result += count.get(remainder);
}

count.put(remainder, count.getOrDefault(remainder, 0) + 1);


}

return result;
}
Implement a Python or Java method to compute the factorial of a
given number n, where the result may exceed the range of standard
integer types
Sols)
Store the result as an array of digits (least significant digit at index
0).

i.​ Initially, factorial result = 1.


ii.​ For every i = 2 to n, multiply result by i digit
by digit.
iii.​ Carry over digits as in manual multiplication
iv.​ After finishing, print digits in reverse order.

for (int i = 0; i < resSize; i++) {


int prod = res[i] * x + carry;
res[i] = prod % 10; // store last digit
carry = prod / 10; // carry forward
}

// store carry digits


while (carry > 0) {
res[resSize] = carry % 10;
carry /= 10;
resSize++;
}static void factorial(int n) {
int[] res = new int[10000]; // array to hold large result
res[0] = 1;
int resSize = 1; // number of digits in result

for (int x = 2; x <= n; x++) {


resSize = multiply(x, res, resSize);
}

// print result in reverse order


for (int i = resSize - 1; i >= 0; i--) {
System.out.print(res[i]);
}
Implement a method in Java or Python to determine the last
non-zero digit of a given factorial n!.

// Function to find last non-zero digit of n!


static int lastNonZeroDigit(int n) {
if (n == 0) return 1;

// Recurrence relation:
// D(n) = D(n/5) * Dsmall(n%5) * 2^(n/5) (mod 10)
int[] small = {1, 1, 2, 6, 4}; // last non-zero digits of
0!,1!,2!,3!,4!

int quotient = n / 5;
int remainder = n % 5;

int result = lastNonZeroDigit(quotient); // recurse on n/5


result = (result * small[remainder]) % 10; // multiply last
digits of remainder factorial

// Adjust for powers of 2 contributed by quotient (since 2s >


5s)
if (quotient % 2 != 0) {
result = (result * 4) % 10; // 2^(odd) cycles affect result
}

return result;
}

Each step does O(1) work.​

Time Complexity: O(log n)​

Space Complexity: O(log n) (recursive stack).


(a) Counting Trailing Zeros in n!

public class TrailingZeros {


public static int countTrailingZeros(int n) {
int count = 0;
while (n >= 5) {
n /= 5;
count += n;
}
return count;
}

Time Complexity: O(log⁡n)O(\log n)O(logn)


Space Complexity: O(1)O(1)O(1) (just uses a counter).

b) finding duplicates

int slow = nums[0];


int fast = nums[0];
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);

// Phase 2: Find entrance of cycle


slow = nums[0];
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
c) fining majority:

public static int majorityElement(int[] nums) {


int count = 0, candidate = 0;
for (int num : nums) {
if (count == 0) {
candidate = num;
}
count += (num == candidate) ? 1 : -1;
}
return candidate;
}

Binary exponentiation :

def binary_exponentiation(a, n):


result = 1
base = a

while n > 0:
if n % 2 == 1: # if n is odd
result *= base
base *= base # square the base
n //= 2 # halve the exponent

return result
We have an array A of size n, with each element a 64-bit integer.
Adjacent elements differ in exactly one bit (like a Gray code path).​
We need to check if there exist four distinct indices (a, b, c, d)
such that:

public static boolean hasFourXORZero(long[] A) {


int n = A.length;
Map<Long, Pair> map = new HashMap<>();

// Check all pairs


for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
long xorVal = A[i] ^ A[j];

if (map.containsKey(xorVal)) {
Pair prev = map.get(xorVal);
// Ensure distinct indices
if (prev.first != i && prev.second != j &&
prev.first != j && prev.second != i) {
return true; // Found 4 numbers
}
} else {
map.put(xorVal, new Pair(i, j));
}
}
}
return false;
}

You might also like