diff --git a/Array/ContainerWithMostWater.swift b/Array/ContainerWithMostWater.swift new file mode 100644 index 0000000..93bf245 --- /dev/null +++ b/Array/ContainerWithMostWater.swift @@ -0,0 +1,44 @@ + +// You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]). + +// Find two lines that together with the x-axis form a container, such that the container contains the most water. + +// Return the maximum amount of water a container can store. + +// Notice that you may not slant the container. + +// Input: height = [1,8,6,2,5,4,8,3,7] +// Output: 49 +// Explanation: The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49. +// Example 2: + +// Input: height = [1,1] +// Output: 1 +// https://leetcode.com/problems/container-with-most-water/ + + + +class Solution { + func maxArea(_ height: [Int]) -> Int { + var maxArea = 0 + var startPointer = 0 + var endPointer = height.count - 1 + + while (startPointer < endPointer) { + let minHeight = min(height[startPointer],height[endPointer]) + let distance = endPointer - startPointer + let area = minHeight * distance + if area > maxArea { + maxArea = area + } + + if height[startPointer] < height[endPointer] { + startPointer += 1 + }else{ + endPointer -= 1 + } + } + + return maxArea + } +} diff --git a/Array/Kadane'sAlgo_maxSubarray.swift b/Array/Kadane'sAlgo_maxSubarray.swift new file mode 100644 index 0000000..5aa2df3 --- /dev/null +++ b/Array/Kadane'sAlgo_maxSubarray.swift @@ -0,0 +1,30 @@ +/* +Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum. +A subarray is a contiguous part of an array. + +Example 1: +Input: nums = [-2,1,-3,4,-1,2,1,-5,4] +Output: 6 +Explanation: [4,-1,2,1] has the largest sum = 6. + +Kadanes algo +https://medium.com/@rsinghal757/kadanes-algorithm-dynamic-programming-how-and-why-does-it-work-3fd8849ed73d +*/ + + +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + let size = nums.count + var localMax = 0 + var globalMax = Int.min + + for i in 0 ..< size { + localMax = max(nums[i],nums[i] + localMax) + if localMax > globalMax{ + globalMax = localMax + } + } + + return globalMax + } +} diff --git a/Array/LongestSubArraySlidingWindow.swift b/Array/LongestSubArraySlidingWindow.swift new file mode 100644 index 0000000..7289c34 --- /dev/null +++ b/Array/LongestSubArraySlidingWindow.swift @@ -0,0 +1,40 @@ +// +// LongestSubArraySlidingWindow.swift +// +// +// Created by Tarun Kaushik on 19/10/21. +// + +func findLongestSubArrayUsingSlidingWindow(array:[Int],s: Int) -> [Int] { + var window = [Int]() + var arraySum = 0 + var largestArray = [Int]() + + for i in array { + // update the array sum and append on window + arraySum += i + window.append(i) + + // check if the arraysum become more than the required sum + if arraySum > s { + // if yes than remove the first element from the window till the array sum is greater than required sum + while arraySum > s { + let firstElement = window[0] + arraySum -= firstElement + window.removeFirst() + } + } + + // check if sum is equal than update the largest array + if arraySum == s { + if largestArray.count < window.count { + largestArray = window + } + } + } + + return largestArray +} + +print(findLongestSubArrayUsingSlidingWindow(array: [1,2,4,3,0,0,0,0,10], s: 10)) + diff --git a/DataStructure/LinkedList/CacheLRU.swift b/DataStructure/LinkedList/CacheLRU.swift new file mode 100644 index 0000000..e8cd186 --- /dev/null +++ b/DataStructure/LinkedList/CacheLRU.swift @@ -0,0 +1,126 @@ +typealias LinkedListNode = DoublyLinkedList.Node + +final class DoublyLinkedList{ + + final class Node { + var payload: T + var previous: Node? + var next: Node? + + init(payload: T){ + self.payload = payload + } + } + + private(set) var count:Int = 0 + private(set) var head: Node? + private(set) var tail: Node? + + func addToHead(_ payload: T) -> Node{ + let node = Node(payload: payload) + defer{ + head = node + count += 1 + } + + guard let head = head else { + tail = node + return node + } + + head.previous = node + + node.next = head + node.previous = nil + + return node + } + + func moveToHead(node: Node?) { + guard node !== head else {return} + let next = node?.next + let previous = node?.previous + + previous?.next = next + next?.previous = previous + + node?.previous = nil + node?.next = head + + if tail === node { + tail = previous + } + + self.head = node + } + + func removeLast() -> Node?{ + guard let tail = tail else {return nil} + + let previous = tail.previous + previous?.next = nil + self.tail = previous + + if count == 1{ + head = nil + } + + count -= 1 + + return tail + } +} + +final class CacheLRU{ + + private struct CachePayload{ + let key: Key + let value: Value + } + + private let list = DoublyLinkedList() + private var nodeDict = [Key: LinkedListNode]() + + private let capacity: Int + + init(capacity: Int){ + self.capacity = capacity + } + + func setValue(_ value: Value,for key: Key) { + let payload = CachePayload(key:key,value:value) + let node = LinkedListNode(payload:payload) + + if let existingNode = nodeDict[key] { + existingNode.payload = payload + list.moveToHead(node:existingNode) + }else{ + list.addToHead(payload) + nodeDict[key] = node + } + + if list.count > capacity{ + let removedNode = list.removeLast() + if let key = removedNode?.payload.key{ + nodeDict[key] = nil + } + } + } + + func getValue(for key: Key) -> Value?{ + guard let node = nodeDict[key] else {return nil} + list.moveToHead(node:node) + return node.payload.value + } +} + +let cache = CacheLRU(capacity: 2) + +cache.getValue(for: 5) // nil + +cache.setValue("One", for: 1) +cache.setValue("Eleven", for: 11) +cache.setValue("Twenty", for: 20) + +cache.getValue(for: 1) // nil. We exceeded the capacity with the previous `setValue` and `1` was the last element. +cache.getValue(for: 11) // Eleven diff --git a/DataStructure/LinkedList/LinkList.swift b/DataStructure/LinkedList/LinkList.swift new file mode 100644 index 0000000..2e4600d --- /dev/null +++ b/DataStructure/LinkedList/LinkList.swift @@ -0,0 +1,136 @@ +class LinkedListNode { + var value: T + weak var previous: LinkedListNode? + var next: LinkedListNode? + + init(value: T) { + self.value = value + } +} + + +class LinkList { + typealias Node = LinkedListNode + + var head: Node? + var tail: Node? { + if last === head { + return nil + } + return last + } + + var isEmpty: Bool { + return head == nil + } + + var first: Node? { + return head + } + + var last: Node? { + guard var node = head else {return nil} + + while let next = node.next { + node = next + } + + return node + } + + var count: Int { + guard var node = head else { return 0} + + var count = 1 + + while let next = node.next{ + node = next + count += 1 + } + + return count + } + + func print() { + guard var node = head else {Swift.print("empty"); return} + var str = "Head(\(node.value))" + + while let next = node.next { + node = next + str += next.next == nil ? " -> Tail(\(next.value))" : " -> (\(next.value))" + } + + Swift.print(str) + } + + func append(value : T) { + let newNode = Node(value: value) + + if let lastNode = last { + newNode.previous = lastNode + lastNode.next = newNode + } else { + head = newNode + } + } + + func reverse() { + var node = head + + while let currentNode = node { + node = currentNode.next + // swap the previous and next references + let previous = currentNode.previous + currentNode.previous = node + currentNode.next = previous + head = currentNode + } + } + + func insert(atIndex index: Int, value: T) { + let newNode = Node(value: value) + + if index == 0 { + newNode.next = head + head?.previous = newNode + head = newNode + } else { + let prev = self.node(atIndex: index - 1 ) + let next = prev.next + + newNode.previous = prev + newNode.next = next + prev.next = newNode + next?.previous = newNode + } + } + + func node(atIndex index: Int) -> Node { + if index == 0 { + return head! + } else { + var node = head!.next + + for _ in 1 ..< index { + node = node?.next + if node == nil { + break + } + } + + return node! + } + } +} + +let list = LinkList() +list.isEmpty +list.first +list.append(value: "Test1") +list.append(value: "Test2") +list.append(value: "Test3") +list.last?.value +list.count +//list.insert(atIndex: 1, value: "Func") +//list.node(atIndex: 2) +//list.print() diff --git a/DataStructure/LinkedList/LinkedListCycle.swift b/DataStructure/LinkedList/LinkedListCycle.swift new file mode 100644 index 0000000..5a62a82 --- /dev/null +++ b/DataStructure/LinkedList/LinkedListCycle.swift @@ -0,0 +1,35 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * } + * } + */ + +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + guard head?.next != nil else {return false} + + var slowPointer = head + var fastPointer = head + + while fastPointer?.next != nil { + slowPointer = slowPointer?.next + if let fast = fastPointer?.next?.next { + fastPointer = fast + }else{ + break + } + + if slowPointer === fastPointer{ + return true + } + } + + return false + } +} diff --git a/DataStructure/LinkedList/Merge_Two_Linked_Lists.swift b/DataStructure/LinkedList/Merge_Two_Linked_Lists.swift new file mode 100644 index 0000000..5caa61c --- /dev/null +++ b/DataStructure/LinkedList/Merge_Two_Linked_Lists.swift @@ -0,0 +1,64 @@ +func mergeLinkedLists(headA: LinkedListNode, headB: LinkedListNode) -> LinkedListNode{ + // we will create a dummy node which will be the first node + let dummyNode = LinkedListNode(value: 0) + var a: LinkedListNode? = headA + var b: LinkedListNode? = headB + + // we will create a tail node which will always be the last node of the linked list + var tail = dummyNode + + // we will run a while loop and keep updating tail node to next and check for headA data and headB data values + while true { + + // check if a is nil + if a == nil { + // reference the tail next to b head + tail.next = b + // break + break + } + + // check if b is nil + if b == nil{ + // reference the tail next to a head + tail.next = a + // break + break + } + + if a!.value <= b!.value { + tail.next = a + a = a!.next + }else { + tail.next = b + b = b!.next + } + + tail = tail.next! + } + + // return dummyNode.Next + return dummyNode.next! +} + +let listA = LinkList() +listA.append(value: 10) +listA.append(value: 21) +listA.append(value: 100) +listA.print() + +let listB = LinkList() +listB.append(value: 9) +listB.append(value: 22) +listB.append(value: 101) +listB.print() + +let listC = LinkList() +listC.head = mergeLinkedLists(headA: listA.head!, headB: listB.head!) +listC.print() + + +// OUTPUT +// Head(10) -> (21) -> Tail(100) +// Head(9) -> (22) -> Tail(101) +// Head(9) -> (10) -> (21) -> (22) -> (100) -> Tail(101) diff --git a/DataStructure/LinkedList/ReverseALinkedListInKGroup.swift b/DataStructure/LinkedList/ReverseALinkedListInKGroup.swift new file mode 100644 index 0000000..09724a9 --- /dev/null +++ b/DataStructure/LinkedList/ReverseALinkedListInKGroup.swift @@ -0,0 +1,47 @@ +// Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list. +// k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is. +// You may not alter the values in the list's nodes, only nodes themselves may be changed. + +// Input: head = [1,2,3,4,5], k = 2 +// Output: [2,1,4,3,5] + +// Input: head = [1,2,3,4,5], k = 3 +// Output: [3,2,1,4,5] + +class Solution { + func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { + guard let root = head else { return head} + + var current = head + var previous: ListNode? + var count = 0 + + guard isReversable(root,k) else {return current} + + while current != nil && count < k { + let next = current?.next + current?.next = previous + previous = current + current = next + count += 1 + } + + if current != nil { + root.next = reverseKGroup(current,k) + } + + return previous + } + + func isReversable(_ head: ListNode?, _ k: Int) -> Bool { + var current = head + var count = 0 + + while current != nil && count < k{ + current = current?.next + count += 1 + } + + return count == k + } +} diff --git a/DataStructure/LinkedList/reverseLinkedList.swift b/DataStructure/LinkedList/reverseLinkedList.swift new file mode 100644 index 0000000..379ed3a --- /dev/null +++ b/DataStructure/LinkedList/reverseLinkedList.swift @@ -0,0 +1,15 @@ +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + var current = head + var previous:ListNode? = nil + + while(current != nil) { + var temp = current?.next + current?.next = previous + previous = current + current = temp + } + + return previous + } +} diff --git a/Dynamic Programming/Fibbonci&Tribonacci_Series.swift b/Dynamic Programming/Fibbonci&Tribonacci_Series.swift new file mode 100644 index 0000000..2a955d6 --- /dev/null +++ b/Dynamic Programming/Fibbonci&Tribonacci_Series.swift @@ -0,0 +1,36 @@ +// Fibonacci +class Solution { + var cache = [Int:Int]() + func fib(_ n: Int) -> Int { + // base condition + if n <= 1 { + return n + } + + if let value = cache[n]{ + return value + }else{ + let value = fib(n-1) + fib(n-2) + cache[n] = value + return value + } + + } +} + +// Tribonacci +class Solution { + var cache:[Int:Int] = [:] + func tribonacci(_ n: Int) -> Int { + if n <= 1 { + return max(0,n) + } + if let value = cache[n]{ + return value + }else{ + let value = tribonacci(n-1) + tribonacci(n-2) + tribonacci(n-3) + cache[n] = value + return value + } + } +} diff --git a/Dynamic Programming/MinimumStairsCost.swift b/Dynamic Programming/MinimumStairsCost.swift new file mode 100644 index 0000000..839a695 --- /dev/null +++ b/Dynamic Programming/MinimumStairsCost.swift @@ -0,0 +1,75 @@ +// https://leetcode.com/problems/min-cost-climbing-stairs/ + +// You are given an integer array cost where cost[i] is the cost of ith step on a staircase. Once you pay the cost, you can either climb one or two steps. + +// You can either start from the step with index 0, or the step with index 1. + +// Return the minimum cost to reach the top of the floor. + + + +// Example 1: + +// Input: cost = [10,15,20] +// Output: 15 +// Explanation: You will start at index 1. +// - Pay 15 and climb two steps to reach the top. +// The total cost is 15. +// Example 2: + +// Input: cost = [1,100,1,1,1,100,1,1,100,1] +// Output: 6 +// Explanation: You will start at index 0. +// - Pay 1 and climb two steps to reach index 2. +// - Pay 1 and climb two steps to reach index 4. +// - Pay 1 and climb two steps to reach index 6. +// - Pay 1 and climb one step to reach index 7. +// - Pay 1 and climb two steps to reach index 9. +// - Pay 1 and climb one step to reach the top. +// The total cost is 6. + +// Simple solution +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + // knapsack problem + var numberOfStairs = cost.count + // creating minCostArray + var minCostArray = [Int](repeating:-1,count:numberOfStairs) + var stairLocation = 0 + + while stairLocation < numberOfStairs { + if stairLocation >= 2 { + minCostArray[stairLocation] = min(minCostArray[stairLocation - 1],minCostArray[stairLocation - 2]) + cost[stairLocation] + }else if stairLocation == 1{ + minCostArray[stairLocation] = min(minCostArray[0] + cost[1],cost[1]) + }else{ + minCostArray[stairLocation] = cost[stairLocation] + } + + // storing minimum cost to current array by using formula + // min(minCostArray[n-1],minCostArray[n-2]) + currentCost -> This formula looks similar to fibbonacci series but we need to find a way to keep cost + + stairLocation += 1 + } + + return min(minCostArray[stairLocation - 1],minCostArray[stairLocation - 2]) + } +} + + +// Simplified +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + // knapsack problem + var numberOfStairs = cost.count + var minCostArray = [Int](repeating:-1,count:numberOfStairs) + minCostArray[0] = cost[0] + minCostArray[1] = cost[1] + + for i in 2 ..< numberOfStairs { + minCostArray[i] = min(minCostArray[i - 1],minCostArray[i - 2]) + cost[i] + } + + return min(minCostArray[numberOfStairs - 1],minCostArray[numberOfStairs - 2]) + } +} diff --git a/README.md b/README.md index 3780f27..9a81e2c 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,54 @@ An algorithm is a procedure that transforms/converts an input into an output. In an algorithm, a **series of computations** are applied on an input to get an output. We can call this sequential series of computations a **procedure**, and this procedure is what we call an **algorithm**. +# OOPS with Swift +Polymorphism, Inheritance, Encapsulation, Properties, Methods, Overriding versus Overloading, Types versus Instances +, Composition, Access Control + # Algorithms-With-Swift Writing this project for learning purposes. We have started with simple algorithms, and we will try to cover more as we go further. We will be solving algorithm problem statements using Swift Programming Language to begin with. +## DataStructure +### LRU Cache +- [LRU Cache](DataStructure/LinkedList/CacheLRU.swift) - My Playground leedcode --> https://leetcode.com/playground/ZrvCR76F + +### LinkedLists +- [Linked List](DataStructure/LinkedList/LinkList.swift) +- [Merge two link Lists](DataStructure/LinkedList/Merge_Two_Linked_Lists.swift) +- [Reverse a linked list](DataStructure/LinkedList/reverseLinkedList.swift) +- [Linked List Cycle](DataStructure/LinkedList/LinkedListCycle.swift) +- [Reverse a linked list in K Group](DataStructure/LinkedList/ReverseALinkedListInKGroup.swift) + +### Trees +- [Binary Tree Traversals](Trees/TreeTreversals.swift) +- [Tree BFS and DFS Logic](Trees/Tree_BFS_DFS.swift) -> [Explanation Link](https://holyswift.app/the-simplest-bfs-and-dfs-templates-for-algorithms-in-swift) +- [Level order traversal Using BFS](Trees/LevelOrderTravesalUsingBFS.swift) -> [Leetcode](https://leetcode.com/problems/binary-tree-level-order-traversal/) +- [Binary Tree Paths](Trees/Binary_Tree_Paths.swift) -> [LeetCode 257](https://leetcode.com/problems/binary-tree-paths/) +- [Invert Binary Tree Along Root](Trees/InvertBinaryTreeAlongRoot.swift) +- [Lowest Common Ancestor](Trees/lowestCommonAncestor.swift) +- [Leetcode 1026](Trees/MaxDiffBetweenNodeAndAncestor.swift) +- [Burn a Binary Tree Using Graph](Trees/BurnBinaryTreeUsingGraph.swift) -> [Interview Bit](https://www.interviewbit.com/problems/burn-a-tree/) +- [Right View of binary tree](Trees/rightViewOfBinaryTree.swift) -> [LeetCode](https://leetcode.com/problems/binary-tree-right-side-view/) + +### BST +- [Validate Binary Search Tree](Trees/isValidBST.swift) -> [LC](https://leetcode.com/problems/validate-binary-search-tree/) + +### Disjoint sets (Important for graph) +- [Ranked disjoint set](graphs/disjointSets/rankedDisjointSet.swift) + - [Number of provices](graphs/disjointSets/numberOfProvices.swift) + - [Graph Valid Tree](graphs/disjointSets/GraphValidTree.swift) +### Graphs +- [Adjanecy list graph](graphs/adjancenyListGraph.swift) +- [DFS - Number of islands](graphs/numberOfIslands.swift) -> [LC](https://leetcode.com/problems/number-of-islands/) +- Dijkestra + - [PriorityQueue](graphs/dijkstra/priorityQueue.swift) + +## Dynamic Programing +- [Fibonaci & Tribonacci series](Dynamic%20Programming/Fibbonci&Tribonacci_Series.swift) +- [Minimum Stair Cost](Dynamic%20Programming/MinimumStairsCost.swift) + ## Algorithms ### Array @@ -32,10 +75,13 @@ We will be solving algorithm problem statements using Swift Programming Language - [Kids With the Greatest Number of Candies](Array/KidsWithCandies.swift) - [Number Of Good Pairs](Array/NumberOfGoodPairs.swift) - [Numbers With Even Digits](Array/NumbersWithEvenDigits.swift) +- [Longest SubArray using sliding window](Array/LongestSubArraySlidingWindow.swift) +- [Kadanes algo longest subarray with max sum](Array/Kadane'sAlgo_maxSubarray.swift) - [Leetcode 66](Array/LeetCode66.swift) - [Leetcode 392](Array/Leetcode392.swift) - [Leetcode1528](Array/Leetcode1528.swift) - [Leetcode1365](Array/Leetcode1365.swift) +- [Two pointer -> Container with most water](Array/ContainerWithMostWater.swift) -> [LC](https://leetcode.com/problems/container-with-most-water/) ### Strings @@ -46,8 +92,11 @@ We will be solving algorithm problem statements using Swift Programming Language - [Find Anagram](String/find_anagram.swift) - [Unique String](String/Unique_string.swift) - [Buddy Strings Leetcode](String/BuddyStrings.swift) +- [Sliding window - count anagrams](String/SlidingWindowCheckAnagram.swift) - [Longest Substring Without Repeating Characters](String/longestSubstringWithoutRepeatingCharacters.swift) - [Leetcode2158](String/Leetcode2108.swift) +- [print Fibbonaci series](String/printFibbonaciSeries.swift) +- [Tribonacci](String/tribonacci.swift) ### Sort @@ -58,9 +107,9 @@ We will be solving algorithm problem statements using Swift Programming Language - [Binary Search](Search/BinarySearch.swift) -### Trees -- [Leetcode 1026](Trees/MaxDiffBetweenNodeAndAncestor.swift) + + diff --git a/Search/BinarySearch.swift b/Search/BinarySearch.swift index 73fea63..503146d 100644 --- a/Search/BinarySearch.swift +++ b/Search/BinarySearch.swift @@ -1,11 +1,4 @@ -// -// BinarySearch.swift -// Binary Search Algorithm -// -// Created by Akshansh Thakur on 21/08/20. -// Copyright Β© 2020 Akshansh Thakur. All rights reserved. -// - +// Binary Search var data: [Int] { var array: [Int] = [] @@ -43,3 +36,43 @@ func BinarySearch(_ array: [Int], target: Int) -> Bool { return false } + +// Returns index of the search value else return -1 +func binarySearch(_ nums:[Int],_ target:Int,_ startIndex:Int,_ endIndex:Int) -> Int{ + if startIndex > endIndex { + return -1 + } + + let mid = startIndex + (endIndex - startIndex)/2 + let midValue = nums[mid] + + if midValue == target { + return mid + }else if target > midValue{ + return binarySearch(nums,target,mid+1,endIndex) + }else if target < midValue{ + return binarySearch(nums,target,startIndex,mid - 1) + } + + return -1 +} + +// Binary Search Using loop +func search(_ nums: [Int], _ target: Int) -> Int { + var startIndex: Int = 0 + var endIndex: Int = nums.count - 1 + + while(startIndex <= endIndex){ + let mid = startIndex + (endIndex - startIndex)/2 + let midValue = nums[mid] + if midValue == target{ + return mid + }else if target > midValue{ + startIndex = mid + 1 + }else{ + endIndex = mid - 1 + } + } + + return -1 +} diff --git a/String/SlidingWindowCheckAnagram.swift b/String/SlidingWindowCheckAnagram.swift new file mode 100644 index 0000000..56e8545 --- /dev/null +++ b/String/SlidingWindowCheckAnagram.swift @@ -0,0 +1,42 @@ +// +/* +++++++++++++++++++++++sliding window++++++++++++*/ +// first string XYYZXZYZXXYZ +// SECOND string XYZ +// find the number of anagram in strings in the string + +func findNumberOfAnagrams(a: String, b: String) -> Int { + var window = [Character]() + let set: Set = Set(b) + var n = 0 + + for (i,val) in a.enumerated(){ + + if i < b.count{ + // fill the window till the index of set lenght + window.append(val) + }else{ + let windowSet = Set(window) + // check if window is subset of the finding string + if set.isSubset(of: windowSet){ + // update the score if yes + n += 1 + } + + //update the window remove first and append at last. + window.removeFirst() + window.append(val) + } + } + + // check if window is subset of the finding string + let windowSet = Set(window) + if set.isSubset(of: windowSet){ + // update the score if yes + n += 1 + } + + return n +} + +let anaGramsCount = findNumberOfAnagrams(a: "XYYZXZYZXXYZYYZXXZY",b:"XYZ") +print("number of anagrams count is \(anaGramsCount)") diff --git a/String/longestSubstringWithoutRepeatingCharacters.swift b/String/longestSubstringWithoutRepeatingCharacters.swift index c0a4c95..3113c48 100644 --- a/String/longestSubstringWithoutRepeatingCharacters.swift +++ b/String/longestSubstringWithoutRepeatingCharacters.swift @@ -4,6 +4,35 @@ Given a string s, find the length of the longest substring without repeating characters. */ +// simplere version + +class Solution { + func lengthOfLongestSubstring(_ s: String) -> Int { + var window = [Character]() + var length:Int = 0 + + for i in s { + if window.isEmpty{ + window.append(i) + }else{ + if window.contains(i) { + if length < window.count { + length = window.count + } + + while window.contains(i) { + window.remove(at:0) + } + } + + window.append(i) + } + } + + return max(length,window.count) + } +} + class Solution { func lengthOfLongestSubstring(_ s: String) -> Int { diff --git a/String/printFibbonaciSeries.swift b/String/printFibbonaciSeries.swift new file mode 100644 index 0000000..67fae7b --- /dev/null +++ b/String/printFibbonaciSeries.swift @@ -0,0 +1,15 @@ +import Foundation + +func printFib(_ n: Int){ + for i in 0 ..< n { + print(fib(i)) + } +} + +func fib(_ n: Int) -> Int { + if n == 0 {return 0} + else if n == 1 {return 1} + return fib(n-1) + fib(n-2) +} + +printFib(6) diff --git a/String/tribonacci.swift b/String/tribonacci.swift new file mode 100644 index 0000000..6eb52b6 --- /dev/null +++ b/String/tribonacci.swift @@ -0,0 +1,6 @@ +func tribonacci(_ n: Int) -> Int { + if n <= 1 { + return max(0,n) + } + return tribonacci(n-1) + tribonacci(n-2) + tribonacci(n-3) +} diff --git a/Trees/Binary_Tree_Paths.swift b/Trees/Binary_Tree_Paths.swift new file mode 100644 index 0000000..b1bcb98 --- /dev/null +++ b/Trees/Binary_Tree_Paths.swift @@ -0,0 +1,72 @@ +// Binary Tree Paths + +// Share +// Given the root of a binary tree, return all root-to-leaf paths in any order. + +// A leaf is a node with no children. +// Example 1: +// Input: root = [1,2,3,null,5] +// Output: ["1->2->5","1->3"] +// 1 ["1"] +// 2 3 ["1->2"],["1->3"] +// 4 5 6 7 +// ["1->2->4","1->2->5","1->3->6","1->3->7"] +// +// Example 2: +// Input: root = [1] +// Output: ["1"] + +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ + +// 1 ["1"] +// 2 3 ["1->2"],["1->3"] +// 4 5 6 7 + +// ["1->2->4","1->2->5","1->3->6","1->3->7"] + +class Solution { + func binaryTreePaths(_ root: TreeNode?) -> [String] { + guard let node = root else {return [""]} + var paths:[String] = [] + getBinaryTreePaths(node,value:"",paths:&paths) + return paths + } + + func getBinaryTreePaths(_ root:TreeNode?,value:String,paths:inout [String]){ + guard let node = root else {return} + + var updatedString = "" + if value.count == 0{ + updatedString = "\(node.val)" + }else{ + updatedString = value + "->" + "\(node.val)" + } + + if node.left == nil && node.right == nil{ + paths.append(updatedString) + return + } + + if let left = node.left { + getBinaryTreePaths(left,value:updatedString,paths: &paths) + } + + if let right = node.right { + getBinaryTreePaths(right,value:updatedString,paths: &paths) + } + } +} diff --git a/Trees/BurnBinaryTreeUsingGraph.swift b/Trees/BurnBinaryTreeUsingGraph.swift new file mode 100644 index 0000000..0011708 --- /dev/null +++ b/Trees/BurnBinaryTreeUsingGraph.swift @@ -0,0 +1,112 @@ +import Foundation + +/** + * Definition for a binary tree node + * + * class TreeNode { + * var val: Int = 0 + * var left: TreeNode? + * var right: TreeNode? + * } + * + */ + +class Solution { + func solve(_ A: TreeNode?, _ B: inout Int) -> Int { + + //1. Initiating a graph + var graph = [Int:[TreeNode]]() + + //2. Building a graph from tree node + buildGraph(&graph,A,nil) + + //3. checks if the value presents in the graph and get its edges + guard let targetNodes = graph[B] else {return 0} + + //4. create a set of visited nodes with Int i.e graph vertex + var visited = Set() + + //5. insert given leaf as visited + visited.insert(B) + + //6. insert given leaf edges in the queue + var queue = targetNodes + var seconds = 0 + + // implementing BFS + //7. Until the queue is not empty we run this while loop + while !queue.isEmpty { + seconds += 1 + + //8. iterating through all the elements inside the existing queue + print("Values inside queue before looping",queue.map{$0.val}) + for node in queue{ + + //9. Removing the node from the queueu + queue.remove(at: 0) + print("removing node",node.val,"from queue") + + //10. check if edges are present for particular queue and insert it inside the queue + guard let nodes = graph[node.val] else {continue} + print("attemping to append nodes",nodes.map{$0.val}) + + //11. check which edge node is not visited and insert it inside the queue + for i in nodes{ + + //12. check if visited contains the node if not than insert inside the queue + if !visited.contains(i.val){ + print("appending",i.val,"in the queue") + queue.append(i) + }else{ + print("node is already in visited =>",i.val) + } + } + + //13. adding the node to visited + print("adding node",node.val,"to visited") + visited.insert(node.val) + } + } + + // while loop is broken as queue is empty now + print("Queue is empty now") + + // Return the seconds + return seconds + } + + // Buids bidirectional graph from a tree node + func buildGraph(_ graph: inout [Int:[TreeNode]],_ node: TreeNode?,_ parent: TreeNode?) { + + //1.hecks if node is not nil + guard let root = node else { + print("empty node found") + return} + let value = root.val + + + //2. insert a new vertex in the graph with value as key + print("Inserting node value",value) + graph[value] = [] + + //3. check if node had a parent + if let parentNode = parent { + + //4. inserts the edge node on exisiting vertex with parent node + graph[value]!.append(parentNode) + + //5. Insert the edge child on parent vertex + graph[parentNode.val]!.append(root) + } + + //6. check if node have left child and insert as edge + if let leftNode = root.left{ + buildGraph(&graph,leftNode,root) + } + + //7. checks if node have right child and insert as edge + if let rightNode = root.right{ + buildGraph(&graph,rightNode,root) + } + } +} diff --git a/Trees/InvertBinaryTreeAlongRoot.swift b/Trees/InvertBinaryTreeAlongRoot.swift new file mode 100644 index 0000000..7e1faeb --- /dev/null +++ b/Trees/InvertBinaryTreeAlongRoot.swift @@ -0,0 +1,31 @@ +// Given the root of a binary tree, invert the tree, and return its root. + +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let node = root else {return nil} + + let temp = node.left + node.left = node.right + node.right = temp + + invertTree(node.left) + invertTree(node.right) + + return node + } +} diff --git a/Trees/LevelOrderTravesalUsingBFS.swift b/Trees/LevelOrderTravesalUsingBFS.swift new file mode 100644 index 0000000..5b81c70 --- /dev/null +++ b/Trees/LevelOrderTravesalUsingBFS.swift @@ -0,0 +1,54 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + guard let rootNode = root else {return []} + + //1. Take one queue and append the first node + var queue = [rootNode] + var result:[[Int]] = [[rootNode.val]] + + //2. run the while loop until the queue is not empty + while !queue.isEmpty { + var values = [Int]() + //3. loop through every element inside the queue + for node in queue { + //4. remove the first or visited element from the queue + // TODO: the for loop will work for the original queue and not the updated one and hence will loop though all previous values in queue + queue.remove(at:0) + + //5. check for left node and insert inside the queue + if let leftNode = node.left { + queue.append(leftNode) + values.append(leftNode.val) + } + + //6. Check for right node and insert inside the queue + if let rightNode = node.right { + queue.append(rightNode) + values.append(rightNode.val) + } + } + + // append the values collected from the loop in the array + if !values.isEmpty{ + result.append(values) + } + } + + return result + } +} diff --git a/Trees/TreeTreversals.swift b/Trees/TreeTreversals.swift new file mode 100644 index 0000000..c062565 --- /dev/null +++ b/Trees/TreeTreversals.swift @@ -0,0 +1,119 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ + +class Solution { + + /* INORDER TREVERSAL (LRR) + inorder treversal is defined as left, root , right + */ + func inorderTraversal(_ root: TreeNode?) -> [Int] { + // Base condition + guard let rootNode = root else {return []} + + let leftTraversal = inorderTraversal(rootNode.left) + let root = rootNode.val + let rightTraversal = inorderTraversal(rootNode.right) + + var array = leftTraversal + array.append(root) + array.append(contentsOf:rightTraversal) + + return array + } + + /* PREORDER TREVERSAL (RLR) + for a binary try preorder treversal is defined as root,left,right + */ + func preorderTraversal(_ root: TreeNode?) -> [Int] { + // Base condition + guard let rootNode = root else {return []} + + let root = rootNode.val + let leftArray = preorderTraversal(rootNode.left) + let rightArray = preorderTraversal(rootNode.right) + + var array:[Int] = [root] + array.append(contentsOf:leftArray) + array.append(contentsOf:rightArray) + + return array + } + + /* POSTORDER TREVERSAL (L,R,R) + for a binary try postorder treversal is defined as left,right,root + */ + func postorderTraversal(_ root: TreeNode?) -> [Int] { + // Base condition + guard let rootNode = root else {return []} + + let leftArray = postorderTraversal(rootNode.left) + let rightArray = postorderTraversal(rootNode.right) + let root = rootNode.val + + var array = leftArray + array.append(contentsOf:rightArray) + array.append(root) + + return array + } + + /* + Level order traversal -> travers very level + */ + func levelOrder(_ root: TreeNode?) -> [[Int]] { + let height = heightOfTree(root) + + var array:[[Int]] = [] + for i in 0 ..< height { + let values = currentLevel(root,level:i) + array.append(values) + } + + return array + } + + func currentLevel(_ root: TreeNode?,level: Int) -> [Int] { + guard let node = root else {return []} + + if level == 0 { + return [node.val] + } + + let leftLevel = currentLevel(node.left,level:level - 1) + let rightLevel = currentLevel(node.right,level:level - 1) + + var array = leftLevel + array.append(contentsOf: rightLevel) + + return array + } + + /* + Height of tree + */ + func heightOfTree(_ root: TreeNode?) -> Int { + guard let node = root else {return 0} + + let leftHeight = heightOfTree(node.left) + let rightHeight = heightOfTree(node.right) + + if leftHeight > rightHeight{ + return leftHeight + 1 + }else{ + return rightHeight + 1 + } + } +} diff --git a/Trees/Tree_BFS_DFS.swift b/Trees/Tree_BFS_DFS.swift new file mode 100644 index 0000000..e57bcea --- /dev/null +++ b/Trees/Tree_BFS_DFS.swift @@ -0,0 +1,55 @@ +// for explanation visit this link --> https://holyswift.app/the-simplest-bfs-and-dfs-templates-for-algorithms-in-swift + + +struct SimpleTree { + var value : Int + var children : [SimpleTree]? +} + +var simpleNode = SimpleTree(value: 2, children: [SimpleTree(value: 5, children: nil), SimpleTree(value: 6, children: nil)]) +var simpleRoot = SimpleTree(value: 1, children: [simpleNode, + SimpleTree(value: 4, children: nil), + SimpleTree(value: 3, children: [SimpleTree(value: 12, children: nil)])]) + +func resolveBFS(_ tree: SimpleTree) -> [Int] { + + var result = [Int]() + var queueTree = [tree] + + while !queueTree.isEmpty { + + let current = queueTree.remove(at: 0) // FIFO - remove the first entry + result.append(current.value) // process node + if let children = current.children { + for tree in children { + queueTree.append(tree) + } + } + } + + return result +} + +print(resolveBFS(simpleRoot).debugDescription, "BFS") + +func resolveDFS(_ tree: SimpleTree) -> [Int] { + + var stackResult = [Int]() + var stackTree = [tree] + + while !stackTree.isEmpty { + + let current = stackTree.popLast() // remove the last one added, O(1) + guard let currentUnwrap = current else {return stackResult} + stackResult.append(currentUnwrap.value) // process node + if let children = currentUnwrap.children { + for tree in children { + stackTree.append(tree) + } + } + } + + return stackResult +} + +print(resolveDFS(simpleRoot).debugDescription, "DFS") diff --git a/Trees/isValidBST.swift b/Trees/isValidBST.swift new file mode 100644 index 0000000..1f4255c --- /dev/null +++ b/Trees/isValidBST.swift @@ -0,0 +1,44 @@ +// 98. Validate Binary Search Tree +// https://leetcode.com/problems/validate-binary-search-tree/ +// Share +// Given the root of a binary tree, determine if it is a valid binary search tree (BST). + +// A valid BST is defined as follows: + +// The left subtree of a node contains only nodes with keys less than the node's key. +// The right subtree of a node contains only nodes with keys greater than the node's key. +// Both the left and right subtrees must also be binary search trees. + + +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + let lowestVal = Int.min + let hightVal = Int.max + return isValid(root,lowestVal,hightVal) + } + + func isValid(_ root: TreeNode?, _ left: Int, _ right: Int) -> Bool{ + guard let node = root else {return true} + + if node.val >= right || node.val <= left { + return false + } + + return isValid(node.left,left,node.val) && isValid(node.right, node.val, right) + } +} diff --git a/Trees/lowestCommonAncestor.swift b/Trees/lowestCommonAncestor.swift new file mode 100644 index 0000000..633604c --- /dev/null +++ b/Trees/lowestCommonAncestor.swift @@ -0,0 +1,47 @@ +/* +Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. +According to the definition of LCA on Wikipedia: β€œThe lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).” +*/ + +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Solution { + func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { + if root == nil { + return nil + } + // check if the root is equal to p or q + if (root === p) || (root === q){ + return root + } + // if not + // get the root with values of p and q for left and right side. + let leftroot = lowestCommonAncestor(root!.left,p,q) + let rightRoot = lowestCommonAncestor(root!.right,p,q) + + // if both left and right root node presents i.e both p and q nodes are separated by current node and current node is the common ancestor + if leftroot != nil && rightRoot != nil { + return root + } + + // if only left root exists that means q and p values are present on the one side and since left root value is found so other value must also be present under it + // and hence the non nil root becomes the least ancestor + if leftroot != nil { + return leftroot + }else { + return rightRoot + } + } +} diff --git a/Trees/rightViewOfBinaryTree.swift b/Trees/rightViewOfBinaryTree.swift new file mode 100644 index 0000000..ebfcf7a --- /dev/null +++ b/Trees/rightViewOfBinaryTree.swift @@ -0,0 +1,68 @@ +// Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom. +// Input: root = [1,2,3,null,5,null,4] +// Output: [1,3,4] + + +/// simpler code + +class Solution { + func rightSideView(_ root: TreeNode?) -> [Int] { + var queue = [root] + var arr:[Int] = [] + + while queue.count > 0 { + + if let rightMostNode = queue.last,let value = rightMostNode?.val { + arr.append(value) + } + + for node in queue { + if let left = node?.left { + queue.append(left) + } + + if let right = node?.right { + queue.append(right) + } + + queue.remove(at:0) + } + } + + return arr + } +} + +class Solution { + func rightSideView(_ root: TreeNode?) -> [Int] { + var queue = [root] + var arr:[Int] = [] + + while queue.count > 0 { + var firstVal: Int? + + for node in queue { + if firstVal == nil { + if let value = node?.val{ + firstVal = value + } + } + if let right = node?.right{ + queue.append(right) + } + + if let left = node?.left { + queue.append(left) + } + + queue.remove(at:0) + } + + if let value = firstVal { + arr.append(value) + } + } + + return arr + } +} diff --git a/graphs/adjancenyListGraph.swift b/graphs/adjancenyListGraph.swift new file mode 100644 index 0000000..4be1468 --- /dev/null +++ b/graphs/adjancenyListGraph.swift @@ -0,0 +1,34 @@ +class Graph { + private var adjacencyList: [String: Set] = [:] + + func addNode(_ node: String) { + if adjacencyList[node] == nil { + adjacencyList[node] = [] + } + } + + func addEdge(to: String, from: String) { + addNode(to) + addNode(from) + adjacencyList[to]?.insert(from) + adjacencyList[from]?.insert(to) + } + + func print() { + for (key,value) in adjacencyList { + Swift.print("\(key) : \(value.joined(separator: "->"))") + } + } +} + +let graph = Graph() + +graph.addEdge(to: "A", from: "B") +graph.addEdge(to: "A", from: "C") +graph.addEdge(to: "B", from: "D") +graph.print() + +// B : A->D +// C : A +// D : B +// A : B->C diff --git a/graphs/dijkstra/priorityQueue.swift b/graphs/dijkstra/priorityQueue.swift new file mode 100644 index 0000000..7c0b070 --- /dev/null +++ b/graphs/dijkstra/priorityQueue.swift @@ -0,0 +1,119 @@ +class PriorityQueue { + private var heap: [T] = [] + private var comparator: (T,T) -> Bool + + // Init + init(comparator: @escaping (T,T) -> Bool) { + self.comparator = comparator + } + + func enqueue(_ element: T) { + heap.append(element) + bubbleUp(heap.count - 1) + } + + func deqeue() -> T? { + guard heap.count >= 0 else { return nil } + let item = heap.first + if heap.count > 1 { + heap[0] = heap[heap.count - 1] + heapify(0) + } + heap.removeLast() + return item + } + + func printQueue() { + print(heap) + } + + // Private + + private func bubbleUp(_ index: Int) { + // we check if the index is > 0 or not + // we get the parent index with formula (index - 1)/2 + // we compare if the index is > 0 and if the parent value satify the comparator or now + // if yes than swap and repeat the bubbleing up + + guard index > 0 else { + return + } + + let parentIndex = (index - 1)/2 + + if comparator(heap[index],heap[parentIndex]) { + swap(index, parentIndex) + bubbleUp(parentIndex) + } + } + + + private func heapify(_ index: Int) { + // 1. Get left and right indexes of the child using (2* index + 1) and (2*index + 2) + // 2. Store the index in best variable + // 3. check if left index satifies heap length and compare the with best index + // 3.a Store index in best of comparator satifies + // 4. Check similar for right and store on best + // 5. If best is changed or != index + // 5.a Swap the best with index + // 5.b Heapify again + // 6. The recussion will terminate when best == index + + + let leftIndex = 2 * index + 1 + let rightIndex = 2 * index + 2 + + var best = index + + if leftIndex < heap.count, comparator(heap[leftIndex], heap[best]) { + best = leftIndex + } + + if rightIndex < heap.count, comparator(heap[rightIndex], heap[best]) { + best = rightIndex + } + + if best != index { + swap(best, index) + heapify(best) + } + } + + private func swap(_ i: Int, _ j: Int) { + var temp = heap[i] + heap[i] = heap[j] + heap[j] = temp + } +} + +// Creating queue +let queue = PriorityQueue { left, right in + left < right +} + +queue.enqueue(1) +queue.enqueue(5) +queue.enqueue(3) +queue.enqueue(4) +queue.enqueue(2) +queue.printQueue() +// Output [1, 2, 3, 5, 4] + +queue.deqeue() +queue.printQueue() +queue.deqeue() +queue.printQueue() +queue.deqeue() +queue.printQueue() +queue.deqeue() +queue.printQueue() +queue.deqeue() +queue.printQueue() + +// Output +// [2, 4, 3, 5] +// [3, 4, 5] +// [4, 5] +// [5] +// [] + diff --git a/graphs/disjointSets/GraphValidTree.swift b/graphs/disjointSets/GraphValidTree.swift new file mode 100644 index 0000000..aa5d2a4 --- /dev/null +++ b/graphs/disjointSets/GraphValidTree.swift @@ -0,0 +1,60 @@ +// You have a graph of n nodes labeled from 0 to n - 1. +// You are given an integer n and a list of edges where edges[i] = [ai, bi] +// indicates that there is an undirected edge between nodes ai and bi in the graph. +// Return true if the edges of the given graph make up a valid tree, and false otherwise. + +// https://leetcode.com/explore/learn/card/graph/618/disjoint-set/3910/ + + +class DisjointSets { + private var parent:[Int] + private var rank:[Int] + private(set) var count:Int + + init(_ size:Int) { + self.parent = Array(0 ..< size) + self.rank = Array(repeating:0, count: size) + self.count = size + } + + func find(_ x: Int) -> Int { + if parent[x] != x { + parent[x] = find(parent[x]) + } + return parent[x] + } + + func union(_ x: Int, _ y: Int) -> Bool { + let parentX = find(x) + let parentY = find(y) + + if parentX != parentY { + if rank[parentX] > rank[parentY] { + parent[parentY] = parentX + } else if rank[parentX] < rank[parentY] { + parent[parentX] = parentY + } else { + parent[parentY] = parentX + rank[parentX] += 1 + } + count -= 1 + return true + } + return false + } + +} + + +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + let ds = DisjointSets(n) + for row in edges { + if ds.union(row[0],row[1]) == false { + return false + } + } + + return ds.count == 1 + } +} diff --git a/graphs/disjointSets/numberOfProvices.swift b/graphs/disjointSets/numberOfProvices.swift new file mode 100644 index 0000000..547ff90 --- /dev/null +++ b/graphs/disjointSets/numberOfProvices.swift @@ -0,0 +1,86 @@ +// https://leetcode.com/explore/learn/card/graph/618/disjoint-set/3845/ +// Number of Provinces +// There are n cities. Some of them are connected, while some are not. +// If city a is connected directly with city b, and city b is connected directly with city c, then city a is connected indirectly with city c. +// A province is a group of directly or indirectly connected cities and no other cities outside of the group. +// You are given an n x n matrix isConnected where isConnected[i][j] = 1 if the ith city and the jth city are directly connected, and isConnected[i][j] = 0 otherwise. +// Return the total number of provinces. + +// Example 1: +// Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]] +// Output: 2 + +// Example 2: +// Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]] +// Output: 3 + + +// Constraints: + +// 1 <= n <= 200 +// n == isConnected.length +// n == isConnected[i].length +// isConnected[i][j] is 1 or 0. +// isConnected[i][i] == 1 +// isConnected[i][j] == isConnected[j][i] + + + +class DisjointSet{ + private var root:[Int] + private var rank:[Int] + private var count: Int + + init(_ size: Int ) { + root = Array(0.. Int { + if root[x] != x { + root[x] = find(root[x]) + } + return root[x] + } + + func union(_ x: Int, _ y: Int) { + let rootX = find(x) + let rootY = find(y) + + guard rootX != rootY else { + // perform no operation and return + return + } + + if rank[rootX] < rank[rootY] { + root[rootX] = rootY + } else if rank[rootX] > rank[rootY] { + root[rootY] = rootX + } else { + root[rootY] = rootX + rank[rootX] += 1 + } + count -= 1 + // since number of provices are cities which do not union.so we reduce each city after union + } + + func getCount() -> Int { + return count + } +} + +class Solution { + func findCircleNum(_ isConnected: [[Int]]) -> Int { + guard isConnected.count > 0 else {return 0} + let ds = DisjointSet(isConnected.count) + for row in 0 ..< isConnected.count - 1 { + for col in row + 1 ..< isConnected.count { + if isConnected[row][col] == 1 { + ds.union(row,col) + } + } + } + return ds.getCount() + } +} diff --git a/graphs/disjointSets/rankedDisjointSet.swift b/graphs/disjointSets/rankedDisjointSet.swift new file mode 100644 index 0000000..c72637d --- /dev/null +++ b/graphs/disjointSets/rankedDisjointSet.swift @@ -0,0 +1,144 @@ +// Disjoint set + +class DisjointSet { + private var parent:[Int] + private var rank:[Int] + + init(_ size: Int) { + self.parent = Array(0.. Int { + if parent[x] != x { + parent[x] = find(parent[x]) + } + return parent[x] + } + + func union(_ x: Int, _ y: Int) { + let rootX = find(x) + let rootY = find(y) + + if rootX != rootY { + if rank[rootX] > rank[rootY] { + parent[rootY] = rootX + } else if rank[rootX] < rank[rootY] { + parent[rootX] = rootY + } else { + parent[rootY] = rootX + rank[rootX] += 1 + } + } + } + + func printParents(_ x: Int) -> String { + var str = "\(x)" + if parent[x] != x { + let root = printParents(parent[x]) + str = "\(x) -> \(root)" + } else { + str = "\(x)(Root)" + } + return str + } +} + +let ds = DisjointSet(10) +ds.union(0, 1) +ds.union(2, 3) +ds.union(4, 5) +ds.union(6, 7) +ds.union(8, 9) + +ds.union(0, 2) +ds.union(4, 6) +ds.union(8, 0) + +print(ds.find(8)) +print(ds.printParents(7)) +// 7 -> 6 -> 4(Root) + + + +let’s visualize how path compression flattens the tree in Disjoint Set, and why it leads to amortized O(1). + +πŸ”Ή Step 1: Initial State + +We have 6 elements: + +0 1 2 3 4 5 + + +Each is its own parent. + +parent = [0, 1, 2, 3, 4, 5] + +πŸ”Ή Step 2: Perform Unions + +Let’s union them in a chain: + +union(0, 1) β†’ 1 β†’ 0 + +union(1, 2) β†’ 2 β†’ 1 β†’ 0 + +union(2, 3) β†’ 3 β†’ 2 β†’ 1 β†’ 0 + +union(3, 4) β†’ 4 β†’ 3 β†’ 2 β†’ 1 β†’ 0 + +union(4, 5) β†’ 5 β†’ 4 β†’ 3 β†’ 2 β†’ 1 β†’ 0 + +Now the tree looks like a linked list (bad case): + +5 β†’ 4 β†’ 3 β†’ 2 β†’ 1 β†’ 0 + + +find(5) would take O(n) = 6 steps here. + +πŸ”Ή Step 3: Path Compression in Action + +Call find(5): + +It sees parent[5] = 4 (not root). + +Recursively finds root β†’ find(4), then find(3), … until root = 0. + +While returning, it updates all parents along the path to point directly to root. + +After this single find(5): + +5 β†’ 0 +4 β†’ 0 +3 β†’ 0 +2 β†’ 0 +1 β†’ 0 +0 β†’ 0 + +πŸ”Ή Step 4: Tree After Compression + +Now the structure is: + + 0 + / | | | | \ +1 2 3 4 5 + + +Depth = 1. + +Next time we do find(5) (or any other node), it’s direct O(1). + +πŸ”Ή Why is this Amortized? + +The first find(5) was expensive (O(n)). + +But it flattened the tree for everyone. + +All future finds are cheap (O(1)). + +Over many operations, the average cost is ~O(1), not O(n). + +Formally, this averages to O(Ξ±(n)), where Ξ±(n) (inverse Ackermann) is ≀ 4 for all realistic n. + +βœ… That’s why we say Union-Find with path compression + rank has amortized O(1) operations. + +πŸ‘‰ Do you also want me to show how union by rank avoids even creating that long chain in the first place (so path compression has less work to do)? diff --git a/graphs/numberOfIslands.swift b/graphs/numberOfIslands.swift new file mode 100644 index 0000000..40cbba6 --- /dev/null +++ b/graphs/numberOfIslands.swift @@ -0,0 +1,137 @@ +// 200. Number of Islands +// Medium +// https://leetcode.com/problems/number-of-islands/ +// Share +// Given an m x n 2D binary grid grid which represents a map of '1's (land) and '0's (water), return the number of islands. + +// An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. + + + +// Example 1: + +// Input: grid = [ +// ["1","1","1","1","0"], +// ["1","1","0","1","0"], +// ["1","1","0","0","0"], +// ["0","0","0","0","0"] +// ] +// Output: 1 +// Example 2: + +// Input: grid = [ +// ["1","1","0","0","0"], +// ["1","1","0","0","0"], +// ["0","0","1","0","0"], +// ["0","0","0","1","1"] +// ] +// Output: 3 + +// Elegant DFS solution + struct DFSElement:Hashable{ + let row: Int + let col: Int + + init(_ row: Int, _ col: Int){ + self.row = row + self.col = col + } + } + + func numIslands(_ grid: [[Character]]) -> Int { + var result = 0 + var visited = Set() + + for i in 0 ..< grid.count{ + for j in 0 ..< grid[0].count { + guard !visited.contains(DFSElement(i,j)) else {continue} + if grid[i][j] == "1" { + result += 1 + dfs(grid,i,j,&visited) + } + } + } + + return result + } + + func dfs(_ grid: [[Character]],_ row:Int, _ col: Int,_ visited: inout Set) { + visited.insert(DFSElement(row,col)) + + for (row1,col1) in [(row + 1,col),(row - 1,col),(row,col + 1),(row,col - 1)] { + guard (row1 >= 0 && row1 < grid.count && col1 >= 0 && col1 < grid[0].count) else { + continue + } + + guard !visited.contains(DFSElement(row1,col1)) else { + continue} + if grid[row1][col1] == "1"{ + dfs(grid,row1,col1,&visited) + } + } + } +} + +// Other solution +class Solution { + var visitedNodes:[[Bool]] = [[]] + func numIslands(_ grid: [[Character]]) -> Int { + if grid.count == 0 {return 0} + + let rowCount = grid[0].count + let colCount = grid.count + + let visitedRows = Array(repeating:false,count: rowCount) + visitedNodes = Array(repeating:visitedRows,count: colCount) + + var count = 0 + + for i in 0 ..< colCount{ + for j in 0 ..< rowCount{ + if visitedNodes[i][j] { + continue + } + + if grid[i][j] == "1"{ + count += 1 + findTheIsLand(grid,row:j,col:i) + } + + visitedNodes[i][j] = true + } + } + + return count + } + + func findTheIsLand(_ grid:[[Character]], row:Int,col: Int) { + visitedNodes[col][row] = true + + // top + if col > 0{ + if visitedNodes[col-1][row] == false && grid[col - 1][row] == "1"{ + findTheIsLand(grid,row:row,col:col-1) + } + } + + // bottom + if col < grid.count - 1{ + if visitedNodes[col+1][row] == false && grid[col + 1][row] == "1"{ + findTheIsLand(grid,row:row,col:col+1) + } + } + // left + if row > 0{ + if visitedNodes[col][row - 1] == false && grid[col][row - 1] == "1"{ + findTheIsLand(grid,row:row - 1,col:col) + } + } + + // right + if row < grid[col].count - 1{ + if visitedNodes[col][row + 1] == false && grid[col][row + 1] == "1"{ + findTheIsLand(grid,row:row + 1,col:col) + } + } + } +}