Skip to content

Commit

Permalink
Implemented 'Number of Subarrays with Bounded Maximum' challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
wibosco committed Sep 12, 2024
1 parent 4047412 commit 00257a3
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 0 deletions.
8 changes: 8 additions & 0 deletions LeetCode/LeetCode.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,8 @@
43A1F14B2B855D6E004712A7 /* CountNodesWithTheHighestScoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A1F14A2B855D6E004712A7 /* CountNodesWithTheHighestScoreTests.swift */; };
43A30FE72C93377A0054D728 /* KthSmallestPrimeFraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A30FE62C93377A0054D728 /* KthSmallestPrimeFraction.swift */; };
43A30FE92C9337B50054D728 /* KthSmallestPrimeFractionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A30FE82C9337B50054D728 /* KthSmallestPrimeFractionTests.swift */; };
43A30FEB2C93743C0054D728 /* NumberOfSubarraysWithBoundedMaximum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A30FEA2C93743C0054D728 /* NumberOfSubarraysWithBoundedMaximum.swift */; };
43A30FED2C93746A0054D728 /* NumberOfSubarraysWithBoundedMaximumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A30FEC2C93746A0054D728 /* NumberOfSubarraysWithBoundedMaximumTests.swift */; };
43A423C82A0544DD005AFB34 /* PermutationInString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A423C72A0544DD005AFB34 /* PermutationInString.swift */; };
43A423CA2A054725005AFB34 /* PermutationInStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A423C92A054725005AFB34 /* PermutationInStringTests.swift */; };
43A692A629F69FD50043B5D0 /* MaximumProductSubarray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43A692A529F69FD50043B5D0 /* MaximumProductSubarray.swift */; };
Expand Down Expand Up @@ -1971,6 +1973,8 @@
43A1F14A2B855D6E004712A7 /* CountNodesWithTheHighestScoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CountNodesWithTheHighestScoreTests.swift; sourceTree = "<group>"; };
43A30FE62C93377A0054D728 /* KthSmallestPrimeFraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KthSmallestPrimeFraction.swift; sourceTree = "<group>"; };
43A30FE82C9337B50054D728 /* KthSmallestPrimeFractionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KthSmallestPrimeFractionTests.swift; sourceTree = "<group>"; };
43A30FEA2C93743C0054D728 /* NumberOfSubarraysWithBoundedMaximum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberOfSubarraysWithBoundedMaximum.swift; sourceTree = "<group>"; };
43A30FEC2C93746A0054D728 /* NumberOfSubarraysWithBoundedMaximumTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberOfSubarraysWithBoundedMaximumTests.swift; sourceTree = "<group>"; };
43A423C72A0544DD005AFB34 /* PermutationInString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermutationInString.swift; sourceTree = "<group>"; };
43A423C92A054725005AFB34 /* PermutationInStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermutationInStringTests.swift; sourceTree = "<group>"; };
43A692A529F69FD50043B5D0 /* MaximumProductSubarray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaximumProductSubarray.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2516,6 +2520,7 @@
435AFB9A2A5C5D8C00721B88 /* NumberOfPairsOfInterchangeableRectangles.swift */,
3D5C911827A7F7630035C399 /* NumberOfProvinces.swift */,
43F2406C2A68409100FB5964 /* NumberOfSubarraysOfSizeKAndAverageGreaterThanOrEqualToThreshold.swift */,
43A30FEA2C93743C0054D728 /* NumberOfSubarraysWithBoundedMaximum.swift */,
43C42B832A65565100D5881B /* NumberOfSubsequencesThatSatisfyTheGivenSumCondition.swift */,
431F3D572A634CAB00500C0E /* NumberOfZeroFilledSubarrays.swift */,
43F3DF3829E0B61600EDEB1C /* OddEvenLinkedList.swift */,
Expand Down Expand Up @@ -3038,6 +3043,7 @@
435AFB9C2A5C5DD200721B88 /* NumberOfPairsOfInterchangeableRectanglesTests.swift */,
3D5C922E27A7F76B0035C399 /* NumberOfProvincesTests.swift */,
43F2406E2A6840C800FB5964 /* NumberOfSubarraysOfSizeKAndAverageGreaterThanOrEqualToThresholdTests.swift */,
43A30FEC2C93746A0054D728 /* NumberOfSubarraysWithBoundedMaximumTests.swift */,
43C42B852A6556B200D5881B /* NumberOfSubsequencesThatSatisfyTheGivenSumConditionTests.swift */,
431F3D592A634CE700500C0E /* NumberOfZeroFilledSubarraysTests.swift */,
43F3DF3A29E0B6B100EDEB1C /* OddEvenLinkedListTests.swift */,
Expand Down Expand Up @@ -3849,6 +3855,7 @@
3D5C914827A7F7630035C399 /* GraphVertice.swift in Sources */,
43495F6B2B221D6A0037FEA7 /* MaximumAverageSubtree.swift in Sources */,
3D5C919027A7F7630035C399 /* CapacityToShipPackagesWithinDDays.swift in Sources */,
43A30FEB2C93743C0054D728 /* NumberOfSubarraysWithBoundedMaximum.swift in Sources */,
3D5C91DE27A7F7630035C399 /* BinaryTreeInorderTraversal.swift in Sources */,
437119442A5EEE6B000E0EE5 /* GridGame.swift in Sources */,
439910472B07CAF30020E9CC /* MaximumLevelSumOfABinaryTree.swift in Sources */,
Expand Down Expand Up @@ -3937,6 +3944,7 @@
438EBCB12AEFB206007083B7 /* FindClosestNodeToGivenTwoNodesTests.swift in Sources */,
438C2EDD2B1F550900C43AAA /* SmallestStringStartingFromLeafTests.swift in Sources */,
4335FB152B89455100416BB6 /* CheckIfNAndItsDoubleExistTests.swift in Sources */,
43A30FED2C93746A0054D728 /* NumberOfSubarraysWithBoundedMaximumTests.swift in Sources */,
3D5C932B27A7F76C0035C399 /* CloneBinaryTreeWithRandomPointerTests.swift in Sources */,
3D7F318B27F791A600200775 /* UniquePathsIITests.swift in Sources */,
3D8424DD27F1AFEC00B91AAB /* MeetingRoomsTests.swift in Sources */,
Expand Down
102 changes: 102 additions & 0 deletions LeetCode/LeetCode/Challenges/NumberOfSubarraysWithBoundedMaximum.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// NumberOfSubarraysWithBoundedMaximum.swift
// LeetCode
//
// Created by William Boles on 12/09/2024.
//

import Foundation

//https://leetcode.com/problems/number-of-subarrays-with-bounded-maximum/
struct NumberOfSubarraysWithBoundedMaximum {

//Time: O(n) where n is the number of elements in `nums`
//Space: O(1)
//array
//two pointers
//sliding window
//counting
//fast forward
//
//Solution Description:
//Let's see a simplifed example that remove `left` and `right`:
//
//[3,2,1]
//
//If we work from left to right (ignore the general subarray counting forumla) we would end up with a pattern like this:
//
//[3], [3,2], [2], [3,2,1], [2,1], [1]
//
//For a total of 6 subarrays. Notice that each time we add an element, we produce the same number of new subarrays pluse 1 more
//than the previous iteration i.e. `1->2->3` - this is a pattern that continues the more elements we add.
//
//Now lets add back in our constraints:
//
//[3,2,1], left = 3, right = 5
//
//So in order a subarray to be valid, at least one element must be above `left` and all elements must be below `right` so the
//valid subarrays are:
//
//[3], [3,2], [3,2,1]
//
//The pattern this time has changed, it is now `1->1->1`. Notice that when a value is added that is below `left` we add the same
//number of new subarrays that we added previous. Take this bigger example:
//
//[3,4,2,1]
//
//[3], [3,4], [4], [3,4,2], [4,2], [3,4,2,1], [4,2,1]
//
//The pattern above is `1->2->2->2`.
//
//Final example, lets add another value on that is greater than or equal to `left`
//
//[3,4,2,1,3]
//
//[3], [3,4], [4], [3,4,2], [4,2], [3,4,2,1], [4,2,1], [3,4,2,1,3], [4,2,1,3], [2,1,3], [1,3], [3]
//
//The pattern above is `1->2->2->2->5`.
//
//So from these patterns we can see:
//
//1. If the current value is within range then take the count of the elements in that subarray and add to our total.
//2. If the current value is lower than our range we take the previous count and add it our total.
//
//(If the current value is greater than our range we reset count).
//
//Using a sliding window we can iterate through `nums` and calculate the number for valid subarrays in that window by using the
//formula given above. We keep two counts - `totalValidSubArraysCount` for overall count and `currentSubArraysCount` for that
//current windows count. Where we encounter a `nums` element that is within range we work out how many possible subarrays could
//be made including that `nums` element and add it to `totalValidSubArraysCount`; where we encounter `nums` element below our
//range we add the `currentSubArraysCount` to `totalValidSubArraysCount` as while new subarrays can be created `nums` element
//can not form a subarray on it's own; where we encounter a `nums` element greater than our range we reset
//`currentSubArraysCount` as this element is a break in subarrays. Finally when we run out of elements we return the total count.
func numSubarrayBoundedMax(_ nums: [Int], _ left: Int, _ right: Int) -> Int {
var p1 = 0

var totalValidSubArraysCount = 0

while p1 < nums.count {
var p2 = p1
var currentSubArraysCount = 0

while p2 < nums.count, nums[p2] <= right { //fast-forward
if nums[p2] >= left {
let count = (p2 - p1) + 1 //+1 to get the count
totalValidSubArraysCount += count
currentSubArraysCount = count //to be used incase `nums[p2]` is below `left`
} else {
//`nums[p2]` is below `left` so can't make a new valid subarray on it's own but can be added to
//the exsiting valid subarray count to extend those subarrays
totalValidSubArraysCount += currentSubArraysCount
}

p2 += 1
}


p1 = p2 + 1 //`p2` is at a value outside the range so jump to the next index
}

return totalValidSubArraysCount
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// NumberOfSubarraysWithBoundedMaximumTests.swift
// LeetCodeTests
//
// Created by William Boles on 12/09/2024.
//

import XCTest

@testable import LeetCode

final class NumberOfSubarraysWithBoundedMaximumTests: XCTestCase {

// MARK: - Tests

func test_A() {
let nums = [2,1,4,3]
let left = 2
let right = 3

let result = NumberOfSubarraysWithBoundedMaximum().numSubarrayBoundedMax(nums, left, right)

XCTAssertEqual(result, 3)
}

func test_B() {
let nums = [2,9,2,5,6]
let left = 2
let right = 8

let result = NumberOfSubarraysWithBoundedMaximum().numSubarrayBoundedMax(nums, left, right)

XCTAssertEqual(result, 7)
}

func test_C() {
let nums = [3,2,1]
let left = 3
let right = 5

let result = NumberOfSubarraysWithBoundedMaximum().numSubarrayBoundedMax(nums, left, right)

XCTAssertEqual(result, 3)
}

func test_D() {
let nums = [3,2,1,4]
let left = 3
let right = 5

let result = NumberOfSubarraysWithBoundedMaximum().numSubarrayBoundedMax(nums, left, right)

XCTAssertEqual(result, 7)
}

func test_E() {
let nums = [3,2,1,4,1]
let left = 3
let right = 5

let result = NumberOfSubarraysWithBoundedMaximum().numSubarrayBoundedMax(nums, left, right)

XCTAssertEqual(result, 11)
}
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ A collection of coding challenges and their solutions from:
| "Merge", "Intervals", "Neighbors" | `sort` |
| "Rotate by k" | `(i + k) % array.count` |

**When unable to spot a pattern, stop and write out the steps involved in the given example - work the problem without code.**

## Need to... Tips

| Need to... | Technique | Example |
Expand Down

0 comments on commit 00257a3

Please sign in to comment.