Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions 0-1Knapsack.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//
// 0-1Knapsack.swift
// DSA-Practice
//
// Created by Paridhi Malviya on 1/20/26.
//

/*
greedy wouldn't work.
so, have exhaustive approach. come up with all the possibilities of choose and not choose
weight array - [10, 20, 30]. Weightts can be chosend only once
profit array = [60, 100, 120]
weight allowed = 50
achieve maximum profit while putting elements within the capacity.
greedy -> first choose 30 to get max profit 120, then choose 20 to have 100 more. profit - 220 greedy works for capacity 50.
If capacity is changed to 30 -> I choose 30, profit attained - 120. Now can't choose any other.
But if I decide to choose 10 and 20 -> total profit - 160.
So, greedy doesn;t work. Chooseing the maximum profit element wouldn't always give us the maximum profit.

If greedy doesn;t work, we have to be exhaustive.
Have all the possibilities of choose and not choose.

eg [10, 20, 30, 40]
At every node, we have 2 options - choose and don't choose.
If we choose an element, then add it's weight and we will be left with rest of the elements.
time complexity - 2^(m + n) -> m -> no of elements in the weight array, n -> capacity
space complexity - (m + n) recursive stack space

We will be encountering repeated subproblems. So, can use DP. We have two input parameters - weights array and the capacity. So, use 2D matrix
In matrix, at each place, choose maximum between choose and no choose scenario.
time complexity - O(m * n)
space complexity - O(m * n)


*/
class ZeroOneKnapsack {

var profit = [60, 100, 120]
var weight = [10, 20, 30]
let capacity = 50

init() {
let totalProfit = helper(profit: [60, 100, 120], weight: [10, 20, 30], capacity: 50, i: 0, totalProfit: 0)
print("ZeroOneKnapsack totalProfit \(totalProfit)")

let profit = findMaximumProfitUsingDP()
print("profit using DP \(profit)")
}

//i - index on weight
func helper(profit: [Int], weight: [Int], capacity: Int, i: Int, totalProfit: Int) -> Int {
//base case
if (i >= weight.count) {
return totalProfit
}

//logic
//no choose
let case0 = helper(profit: profit, weight: weight, capacity: capacity, i: i + 1, totalProfit: totalProfit)

//choose case
var case1 = 0
//only if the current weight is smaller than the capacity
if (weight[i] <= capacity) {
case1 = helper(profit: profit, weight: weight, capacity: capacity - weight[i], i: i + 1, totalProfit: totalProfit + profit[i])
}

return max(case0, case1)

}

func findMaximumProfitUsingDP() -> Int {

let m = weight.count
let n = capacity
var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: m + 1)

for i in 1...m {
for j in 1...n {
if (j < weight[i-1]) {
dp[i][j] = dp[i-1][j]
} else {
dp[i][j] = max(dp[i-1][j], profit[i-1] + dp[i-1][j-weight[i-1]])
}
}
}

return dp[m][n]
}
}
Empty file removed Problem1.cpp
Empty file.
Empty file removed Problem1.java
Empty file.
Empty file removed Problem2.cpp
Empty file.
Empty file removed Problem2.java
Empty file.
3 changes: 0 additions & 3 deletions README.md

This file was deleted.

72 changes: 72 additions & 0 deletions TwoSum.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//
// TwoSum.swift
// DSA-Practice
//
// Created by Paridhi Malviya on 1/6/26.
//

/*
want unique pairs
can think elemets as pairs. Used for
two pointers

-> naive approach- O(n2) -> nested iterations
approach 2 - use hash map. Search for compliment in

-> O(n) time complexity. Space - O(n)
use hash set. and only store numbers or compliment. store number and look for compliment. or vice versa

-> binary search - sort the array. Do binary search for compliment.

->If array is already sorted. time complexity - O(n logn)
for each element we are doingnbinary serahc. So log n for all elements of an array. -> n logn
to sort the array - O(n log n)
time complexity - O(n logn n) + O(n log n) = O(n log n) (avoid constant)

-> Two pointer - keep on increasing the pointer 1 and decreasing the pointer 2
n log n for sortuing. O(n) for two pointers

=> If I have repeats in the numbers array but we don't want repeats in pair.
[-3, 0, -2, -2, -1, -1, 0, 0, 0 7, 7, 6, 1, 1, 9, 9 ,9, -1, 0]
1. can use hash set to avoid duplicated of a pair. O(n) space complexity.

2. Sort the array and use two pointers solution.
[-4, -3, -2, -2, -1, -1, -1, 0, 0 , 0, 1, 1, 1, 2, 2 ]
O (n logn n), no extra space
right pointer value + left pointer value > target, decrease right pointer.
----- < target, increase left pointer to have bigger value to make bigger sum
If we are at the target -> move both the pointers and record the pair.
Move the left and right pointers until we hit the next unique element. In this way, we avoided hash set for storage

Nested iterations can be optimizied using
binary search, hashing, two pointers,


-> 3 sum -> 1 fixed pointer and two sum
-> 4 sum - > take 2 pivots. and 2 pointers

*/

class TwoSum {

init() {
let resultIndex = twoSum(nums: [2,7,11,15], target: 13)
print("resultIndex \(resultIndex)")
}

func twoSum(nums: [Int], target: Int) -> (Int, Int){
var map: Dictionary<Int, Int> = [:]
for i in 0..<nums.count {
map[nums[i]] = i
}

for j in 0..<nums.count {
let complement = target - nums[j]
//If the complment exists in hash map and the index for that number is not equal to the current processed index means these two numbers are placed at different index.
if (map[complement] != nil && map[complement] != j) {
return (j, map[complement]!)
}
}
return (-1, -1)
}
}