0% found this document useful (0 votes)
14 views30 pages

DAA Project Part 1

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)
14 views30 pages

DAA Project Part 1

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/ 30

Design & Analysis

of Algorithms part 1

ANUM AKHTAR (k22-4827)


AREEBA ABDUL RASOOL (k22-4821)
AIMAN AMJAD DAUDPOTA (k22-5168)
Question 1

Part a
1
Pseudocode:
MinMax(arr, low, high)
if p== q then
return (arr[p], arr[p])
else if high == low + 1 then
if arr[p] < arr[q] then
return (arr[p], arr[q])
else
return (arr[q], arr[p])
mid = (p + q) / 2
MinMax(arr, p, mid) = (leftMin, leftMax)
MinMax(arr, mid + 1, q) = (rightMin, rightMax)
min(leftMin, rightMin) = min_num
max(leftMax, rightMax) = max_num
return (min_num , max_num )

Implementation:
import java.util.Scanner;

public class MinMaxDivideConquer {

public static int[] MinMax(int[] arr, int p, int q) {


int[] result = new int[2];

if (p == q) {
result[0] = arr[p];
result[1] = arr[p];
return result;
}

int mid = (p + q) / 2;

int[] left = MinMax(arr, p, mid);


int[] right = MinMax(arr, mid + 1, q);

result[0] = Math.min(left[0], right[0]);


result[1] = Math.max(left[1], right[1]);
return result;
}

public static void main(String[] args) {


System.out.println("22k4827\n22k5168\n22k4821");
System.out.println();
int[] arr = {2,44,56,78,23,90,75,34,55,78};

for (int i=0; i<arr.length-1; i++){


System.out.printf(arr[i] + "\t");
}

System.out.println();
int[] result = MinMax(arr, 0, arr.length - 1);

System.out.println("\nMinimum element: " + result[0]);


System.out.println("Maximum element: " + result[1]);
}
}
Output:
2
3
A divide-and-conquer algorithm for this problem is more efficient than the brute-force
algorithm by a constant factor.

In the brute force algorithm, we compare every element twice, once to find the minimum and
once to find the maximum. This increases the comparison rate by a constant factor of 2.
No of comparisons: 2(n-1)

The divide and conquer algorithm makes n-1 number of comparisons to accomplish the same
task.

Both brute-force and divide-and-conquer have linear time complexity O(n), but the constant
factor for the divide-and-conquer approach is smaller so it does the same work in fewer
comparisons.

Part b
1
Power(num, n)
if n = 0 then
return 1
if n is even then
c = Power(num, n / 2)
return c * c
else
c = Power(num, (n - 1) / 2)
return a * c * c
CODE
public class PowerCalculation {
public static long Power(long num, int n) {
if (n == 0) {
return 1;
}
long c = Power(num, n / 2);
if (n % 2 == 0) {
return c * c;
} else {
return num * c * c;
}
}
public static void main(String[] args) {
long num = 2;
int n = 15;
long answer = Power(num, n);
System.out.println(num + "^" + n + " = " + answer);
}
}

OUTPUT
2
Setting Up and Solving Recurrence Relation
3
The brute force algorithm would compute an by multiplying a , n number of times
which would lead to a time complexity of O(n). For example to compute 21024 we
would do: 2*2* 2*2… *2 (1024 times)
In comparison Divide and Conquer approach recursively divides the n by half.If the n is
even the division is n/2. If the n is odd the division is (n-1)/2. This is done recursively
till we reach a 0 or 1.

Part c
To find the total number of inversions in an array, we can use many approaches including an
algorithm that is similar to merge sort.
In my code, I have demonstrated how to use a self balancing binary search tree to find
inversions in an array in O(nlogn) time.
Pseudocode:
class Node{
value
left
right
countLeftNodes
}

//the insert function will count inversions for each element while inserting it in the BST
function insert(root, value){
if root is NULL:
root = create_new_node(value)
return root, 0

if value <= root.value:


root.left, inversions = insert(root.left, value)
root.countLeftNodes += 1
return root, inversions

else:
root.right, inversions = insert(root.right, value)
inversions += (root.countLeftNodes + 1)
return root, inversions
}

function countInversions(arr){
root = NULL
total_inversions = 0

for value in arr:


root, inversions = insert(root, value)
total_inversions += inversions

return total_inversions
}

Implementation:
class Node {
int value;
Node left;
Node right;
int leftCount;

Node(int value) {
this.value = value;
this.left = null;
this.right = null;
this.leftCount = 0;
}
}

public class InversionCounter {


public static Result insertAndCountInversions(Node root, int value) {
if (root == null) {
return new Result(new Node(value), 0);
}

int inversions = 0;

if (value <= root.value) {


Result result = insertAndCountInversions(root.left, value);
root.left = result.node;
root.leftCount++;
inversions += result.inversions;
} else {
Result result = insertAndCountInversions(root.right, value);
root.right = result.node;
inversions += (root.leftCount + 1);
inversions += result.inversions;
}

return new Result(root, inversions);


}

public static int countInversions(int[] arr) {


Node root = null;
int totalInversions = 0;

for (int value : arr) {


Result result = insertAndCountInversions(root, value);
root = result.node;
totalInversions += result.inversions;
}

return totalInversions;
}

static class Result {


Node node;
int inversions;

Result(Node node, int inversions) {


this.node = node;
this.inversions = inversions;
}
}

public static void main(String[] args) {


int[] arr = {4, 15, 8, 7, 5, 6};
int result = countInversions(arr);
System.out.println("Number of inversions are: " + result);
}
}

Output:

Part d
● Worst case time complexity for quickSort : O(n^2)

when the pivot divides the array in an unbalanced way, such as always choosing the smallest
or largest element as the pivot. In such cases, one partition has n−1 elements, and the other
has 0, leading to n recursive calls and a total of n^6 comparisons.

● Best-case time complexity of quicksort : O(nlog⁡n)

when the pivot divides the array into two equal parts. the array size is halved, and each level
processes n elements resulting in O(nlog⁡n) comparisons
Part e
Example 5.5 (1)

1. Sort the array of numbers and divide the array into half
2. Recursively perform a linear scan of the array to find the closest pair in each half.
3. Compare the closest pairs found in both halves.
4. Additionally, check if the closest pair could lie between the largest element of the left
half and the smallest element of the right half

2. Is this a good algorithm

Sorting takes O(nlog⁡n). After sorting, we perform a linear scan of the array to find the closest
pair, O(n). overall time complexity of algorithm is O(nlog⁡n)

The divide and conquer guarantees a more efficient search for the closest pair compared to a
brute force O(n2). Whereas time complexity of O(nlog⁡n) is optimal for this problem, given
that sorted array is needed .

Code

package CollectionFrameWork_gui;

public class algoassignment {

public static void mergeSort(double[] arr,int left,int right) {

if (left < right) {

int mid = (left + right) / 2;

mergeSort(arr, left, mid);

mergeSort(arr, mid + 1, right);

merge(arr, left, mid, right); }

public static void merge(double[] arr, int left, int mid, int right) {

int n1 = mid-left+1;
int n2 = right-mid;

double[] leftArray =new double[n1];

double[] rightArray =new double[n2];

System.arraycopy(arr, left, leftArray, 0, n1);

System.arraycopy(arr, mid+1, rightArray, 0, n2);

int i = 0, j = 0, k =left;

while (i<n1 && j<n2) {

if (leftArray[i] <= rightArray[j]) {

arr[k++] = leftArray[i++]; }

else { arr[k++] = rightArray[j++]; }

while (i<n1) {

arr[k++] = leftArray[i++]; }

while (j <n2) {

arr[k++] = rightArray[j++]; }

public static double[] closestPair(double[] arr,int left, int right) {

if (right - left <= 0) {

return new double[]{Double.MAX_VALUE, Double.MAX_VALUE,


Double.MAX_VALUE}; } //no valid pair

if (right-left == 1) {

return new double[]{arr[left], arr[right], Math.abs(arr[right] -


arr[left])};

}
int mid = (left+right) /2;

double[] leftResult = closestPair(arr, left, mid);

double[] rightResult = closestPair(arr, mid+1, right);

double[] pair;

if (leftResult[2] < rightResult[2]) { pair = leftResult; }

else { pair = rightResult; }

double boundaryDistance = Math.abs(arr[mid]-arr[mid + 1]);

if (boundaryDistance < pair[2]) {

pair = new double[]{arr[mid], arr[mid + 1], boundaryDistance};

return pair;

public static void main(String[] args) {

double[] numbers = {3.5, 1.2, 7.8, 4.9, 2.3, 8};

mergeSort(numbers, 0, numbers.length-1);

double[] closestPairResult = closestPair(numbers,0,numbers.length -


1);

System.out.println("closest pair is: (" + closestPairResult[0] + ",


" + closestPairResult[1] +

") with a distance of: " + String.format("%.3f",


closestPairResult[2]));

}
Part f
ALGORITHM:

1. We first check the middle element A[n/2] and compare it with its neighbors A[n/2
- 1] and A[n/2 + 1].

2. If A[n/2 - 1] < A[n/2] < A[n/2 + 1], the peak must lie on the right half (
increasing array).

3. If A[n/2 - 1] > A[n/2] > A[n/2 + 1], the peak must lie on the left half (
decreasing array).

4. If A[n/2] is greater than both its neighbors, then A[n/2] is the peak.

IMPLEMENTATION:
public class FindPeak {

public static int findPeak(int[] A, int low, int high) {


if (low == high) {
return low;
}
int mid = (low + high) / 2;

if (mid + 1 < A.length && A[mid] < A[mid + 1]) {


return findPeak(A, mid + 1, high);
}

if (mid - 1 >= 0 && A[mid] < A[mid - 1]) {


return findPeak(A, low, mid - 1);
}

return mid;
}

public static int peakElement(int[] A) {


return findPeak(A, 0, A.length - 1);
}

public static void main(String[] args) {


System.out.printf("22k4827\n22k5168\n22k4821\n");

int[] A = {1, 3, 16, 20, 1, 0};


int peakIndex = peakElement(A);

System.out.println("\nPeak element is at index: " + peakIndex);


System.out.println("Value: " + A[peakIndex]);
}
}
OUTPUT:

Part g
Approach: We divide our input of prices array into sub array. There might be three possible
cases where we get the profit. In our solution, we calculate all three possibilities and then
compare them to get the maximum profit.
ALGORITHM
Input: An array of prices. The array index shows the day number.
1. If there are only 1 day then profit is 0. (start >=end)
2. Divide the array from mid into sets.
● Left Half: Start to Mid
● Rigth Half: Mid+1 to end
3. Recursively find the profit in the left half and the right half
4. Find the cross Profit which would be a minimum buy in the left half and a maximum
sell in the right half. Find min in the left half and max in the right half.
5. Compare the three possible profits and find the max. The possible profits are:
● Maximum Profit in Left Half
● Maximum Profit in Right Half
● Cross Profit
The maximum profit along with the corresponding day for buy and sell is returned.
6. Display the results.

CODE
public class StockProfit {
private static int MinIndex(int[] p, int start, int end) {
int minPrice = p[start];
int minIndex = start;
for (int i = start + 1; i <= end; i++) {
if (p[i] < minPrice) {
minPrice = p[i];
minIndex = i;
}
}
return minIndex;
}
private static int MaxIndex(int[] p, int start, int end) {
int maxPrice = p[start];
int maxIndex = start;
for (int i = start + 1; i <= end; i++) {
if (p[i] > maxPrice) {
maxPrice = p[i];
maxIndex = i;
}
}
return maxIndex;
}
public static int[] maximumProfitCalculation(int[] p, int i, int j) {
if (i >= j) {
return new int[]{0, -1, -1};
}
int mid = (i + j) / 2;

int[] lResult = maximumProfitCalculation(p, i, mid);


int[] rResult = maximumProfitCalculation(p, mid + 1, j);
int minDay = MinIndex(p, i, mid);
int maxDay = MaxIndex(p, mid + 1, j);
int CP = p[maxDay] - p[minDay];

if (lResult[0] >= rResult[0] && lResult[0] >= CP) {


return lResult;
} else if (rResult[0] >= lResult[0] && rResult[0] >= CP) {
return rResult;
} else {
return new int[]{CP, minDay + 1, maxDay + 1};
}
}

public static void main(String[] args) {

int[] prices = {5,1,5,6,3,10,4};


int n = prices.length;
int[] result = maximumProfitCalculation(prices, 0, n - 1);
System.out.println("Maximum profit earned: " + result[0]);
if (result[1] != -1 && result[2] != -1) {
System.out.println("Buying on day: " + result[1]);
System.out.println("Selling on day: " + result[2]);
} else {
System.out.println("No valid buying and selling days for profit.");
}
}
}

OUTPUT
Part h

1. Counting no of inversions (q2)

Algorithm

1. Apply merge sort for divide and conquer for o(nlogn)


2. While merging, for each element in the left half, count elements in the right half form
a significant inversion.
3. maintain a sorted list of the right half as you merge and compare elements from the
left with the right using the condition
ai > 2aj
4. Return the sum of inversions from the two recursive calls and the merge step.

package CollectionFrameWork_gui;
public class algoassignment {

public static int mergeAndCount(int[] arr, int left, int mid, int right)
{
int count = 0;

int[] leftArr = new int[mid - left+1];


int[] rightArr = new int[right - mid];

System.arraycopy(arr, left, leftArr, 0, leftArr.length);


System.arraycopy(arr, mid+1, rightArr, 0, rightArr.length);

int i = 0, j = 0;
while (i <leftArr.length && j <rightArr.length) {
if (leftArr[i] > 2 * rightArr[j]) {
count += leftArr.length - i;
j++; }
else { i++; }
}

i = 0; j = 0;
int k = left;

while (i < leftArr.length && j < rightArr.length) {


if (leftArr[i] <= rightArr[j]) {
arr[k++] = leftArr[i++];
} else {
arr[k++] = rightArr[j++]; }
}

while (i <leftArr.length) {
arr[k++] = leftArr[i++];
}

while (j <rightArr.length) {
arr[k++] = rightArr[j++];
}

return count;
}

public static int mergeSortAndCount(int[] arr, int left, int right) {


if (left >= right) {
return 0;
}

int mid = (left+right) /2;


int count = mergeSortAndCount(arr, left, mid) +
mergeSortAndCount(arr, mid+1, right);

count += mergeAndCount(arr,left,mid,right);
return count;
}

public static void main(String[] args) {


int[] arr = {5, 3, 4,2,1, 7, 6};
int n = arr.length;

int Inversions = mergeSortAndCount(arr, 0, n-1);


System.out.println("significant inversions: " +Inversions);
}
}
2. Bank fraud card detection problem q3

● Iterate through the list of bank cards to find a candidate that might represent a
majority.
● use the equivalence tester class to compare bank card objs
● After identifying a potential candidate having repeated usage , check how
many times this candidate appears in the list.
● confirm if it appears more than n/2.

Code and output


package CollectionFrameWork_gui;
import java.util.ArrayList;
import java.util.List;

public class algoassignment {


public static void main(String[] args) {
List<BankCard> cards = new ArrayList<>();

cards.add(new BankCard("Anam akhtar","12345"));


cards.add(new BankCard("aiman amjad","98765"));
cards.add(new BankCard("Anam akhtar","12345"));
cards.add(new BankCard("Anam akhtar","12345"));
cards.add(new BankCard("Areeba","09007"));

boolean result =
FraudDetection.findMajorityEquivalent(cards);
System.out.println("is majority equivalent set? " + result);
}
}
class BankCard {
private String accountHolderName;
private String accountNumber;

public BankCard(String accountHolderName, String accountNumber)


{
this.accountHolderName = accountHolderName;
this.accountNumber = accountNumber;
}

public String getAccountHolderName() {


return accountHolderName;
}

public String getAccountNumber() {


return accountNumber;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof BankCard other))
return false;
return accountNumber.equals(other.accountNumber);
}

@Override
public int hashCode() {
return accountNumber.hashCode();
}
}

class EquivalenceTester {
public boolean areEquivalent(BankCard card1, BankCard card2) {
return card1.equals(card2);
} }

class FraudDetection {

public static boolean findMajorityEquivalent(List<BankCard>


cards) {
if (cards.isEmpty()) return false;

EquivalenceTester tester = new EquivalenceTester();


BankCard candidate = null;
int count = 0;

//candidate
for (BankCard card : cards) {
if (count == 0) {
candidate = card;
count = 1;
} else {
if (tester.areEquivalent(card, candidate)) {
count++;
} else {
count--;
}
}
}
count = 0;
for (BankCard card : cards) {
if (tester.areEquivalent(card, candidate)) {
count++; }
}

// chekbank cards that exceeds 𝑛/2


return count > cards.size() / 2;
}
}

3. Hidden surface removal to determine which parts of a 3D scene are


visible from a given viewpoint q5
1. arrange the lines in order from top to bottom based on where they cross the
y-axis.
2. Create a list of events that will happen as the sweep line moves. There are two
types of events: when a line starts and when a line ends.
3. While there are still events in the queue:
○ Take the next event from the queue.
○ If the event is a starting line
○ Add the line to a list of active lines.
○ Check if this line is the highest line at this point. If it is, add it to the list
of visible lines.
○ If the event is a line ending, remove the line from the list of active lines.
○ Check if the line below the removed line is now the highest. If it is, add
it to the list of visible lines.
4. Return the list of visible lines containing the lines that should be drawn to
show the visible parts of the picture.
package CollectionFrameWork_gui;
import java.util.*;

public class alogoq3 {


public static void main(String[] args) {
List<Line> lines = Arrays.asList(
new Line(1, 2),
new Line(-2, 4),
new Line(0.5, -1),
new Line(3, 0),
new Line(-1, 1)
);

List<Line> visibleLines =
HiddenSurfaceRemoval.findVisibleLines(lines);
System.out.println("visible lines: y = ax + b");
for (Line line : visibleLines) {
System.out.println(line.a + "x + " + line.b);
}
}
}

class Line {
double a, b;

public Line(double a, double b) {


this.a = a;
this.b = b;
}

public double y(double x) {


return a * x + b; // y = ax + b
}
}

class Event {
double x;
Line line;
int type;
//1 for start, -1 for end

public Event(double x, Line line, int type) {


this.x = x;
this.line = line;
this.type = type;
}
}

class HiddenSurfaceRemoval {
public static List<Line> findVisibleLines(List<Line> lines) {

List<Event> events = new ArrayList<>();

for (Line line : lines) {

events.add(new Event(Double.NEGATIVE_INFINITY, line, 1));


events.add(new Event(Double.POSITIVE_INFINITY, line, -1));
}
events.sort(Comparator.comparingDouble(e -> e.x));

List<Line> activeLines = new ArrayList<>();


List<Line> visibleLines = new ArrayList<>();

for (Event event : events) {


if (event.type == 1) {
activeLines.add(event.line);
if (isTopmost(activeLines, event.line, event.x)) {
visibleLines.add(event.line);
}
} else {
activeLines.remove(event.line);
if (!activeLines.isEmpty() && isTopmost(activeLines,
activeLines.get(activeLines.size() - 1), event.x)) {
visibleLines.add(activeLines.get(activeLines.size() -
1));
}
}
} return visibleLines;
}
private static boolean isTopmost(List<Line> lines, Line line, double
x) {
for (Line otherLine : lines) {
if (otherLine != line && otherLine.y(x) > line.y(x)) {
return false;
}
}
return true;
}

You might also like