Skip to content

Commit

Permalink
Solution of Shortest Subarray With OR at Least K II problem
Browse files Browse the repository at this point in the history
  • Loading branch information
ashtanko committed Nov 10, 2024
1 parent 5f700e7 commit 6eb4411
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 10 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@

### Metrics
```text
13601 number of properties
9348 number of functions
8350 number of classes
13611 number of properties
9356 number of functions
8357 number of classes
184 number of packages
3182 number of kt files
3184 number of kt files
```


### Complexity Report
```text
233583 lines of code (loc)
145646 source lines of code (sloc)
106605 logical lines of code (lloc)
62742 comment lines of code (cloc)
22897 cyclomatic complexity (mcc)
19178 cognitive complexity
233757 lines of code (loc)
145749 source lines of code (sloc)
106676 logical lines of code (lloc)
62790 comment lines of code (cloc)
22918 cyclomatic complexity (mcc)
19200 cognitive complexity
0 number of total code smells
43 comment source ratio
214 mcc per 1,000 lloc
Expand Down
1 change: 1 addition & 0 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ style:
- '26'
- '30'
- '32'
- '35'
- '50'
- '70'
- '255'
Expand Down
117 changes: 117 additions & 0 deletions src/main/kotlin/dev/shtanko/algorithms/leetcode/MinSubarrayLen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright 2024 Oleksii Shtanko
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shtanko.algorithms.leetcode

import dev.shtanko.algorithms.annotations.BinarySearch
import dev.shtanko.algorithms.annotations.SlidingWindow
import dev.shtanko.algorithms.annotations.level.Medium

/**
* 3097. Shortest Subarray With OR at Least K II
* @see <a href="https://leetcode.com/problems/shortest-subarray-with-or-at-least-k-ii/">Source</a>
*/
@Medium("https://leetcode.com/problems/shortest-subarray-with-or-at-least-k-ii")
fun interface MinSubarrayLen {
operator fun invoke(nums: IntArray, k: Int): Int
}

@BinarySearch
class MinSubarrayLenBinarySearch : MinSubarrayLen {
override fun invoke(nums: IntArray, k: Int): Int {
var left = 1
var right = nums.size
var minLength = -1

while (left <= right) {
val mid = left + (right - left) / 2

if (hasValidSubarray(nums, k, mid)) {
minLength = mid
right = mid - 1 // Try to find smaller length
} else {
left = mid + 1 // Try larger length
}
}

return minLength
}

private fun hasValidSubarray(nums: IntArray, targetSum: Int, windowSize: Int): Boolean {
val bitCounts = IntArray(32) // Tracks count of set bits at each position

// Sliding window approach
for (right in nums.indices) {
// Add current number to window
bitCounts.updateBitCounts(nums[right], 1)

// Remove leftmost number if window exceeds size
if (right >= windowSize) {
bitCounts.updateBitCounts(nums[right - windowSize], -1)
}

// Check if current window is valid
if (right >= windowSize - 1 && bitCounts.convertBitsToNum() >= targetSum) {
return true
}
}

return false
}
}

@SlidingWindow
class MinSubarrayLenSlidingWindow : MinSubarrayLen {
override fun invoke(nums: IntArray, k: Int): Int {
var minLength = Int.MAX_VALUE
var windowStart = 0
var windowEnd = 0
val bitCounts = IntArray(32) // Tracks count of set bits at each position

// Expand window until end of array
while (windowEnd < nums.size) {
// Add current number to window
bitCounts.updateBitCounts(nums[windowEnd], 1)

// Contract window while OR value is valid
while (windowStart <= windowEnd && bitCounts.convertBitsToNum() >= k) {
// Update minimum length found so far
minLength = minOf(minLength, windowEnd - windowStart + 1)

// Remove leftmost number and shrink window
bitCounts.updateBitCounts(nums[windowStart], -1)
windowStart++
}

windowEnd++
}

return if (minLength == Int.MAX_VALUE) -1 else minLength
}
}

private fun IntArray.updateBitCounts(number: Int, delta: Int) {
// Update counts for each set bit in the number
for (pos in 0 until 32) {
if (number and (1 shl pos) != 0) {
this[pos] += delta
}
}
}

private fun IntArray.convertBitsToNum(): Int {
return (0 until 32).sumOf { pos -> if (this[pos] > 0) 1 shl pos else 0 }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2024 Oleksii Shtanko
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package dev.shtanko.algorithms.leetcode

import java.util.stream.Stream
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.ArgumentsProvider
import org.junit.jupiter.params.provider.ArgumentsSource

abstract class MinSubarrayLenTest<out T : MinSubarrayLen>(private val strategy: T) {
private class InputArgumentsProvider : ArgumentsProvider {
override fun provideArguments(context: ExtensionContext?): Stream<out Arguments> = Stream.of(
Arguments.of(
intArrayOf(1, 2, 3),
2,
1,
),
Arguments.of(
intArrayOf(2, 1, 8),
10,
3,
),
Arguments.of(
intArrayOf(1, 2),
0,
1,
),
)
}

@ParameterizedTest
@ArgumentsSource(InputArgumentsProvider::class)
fun minimumSubarrayLengthTest(nums: IntArray, k: Int, expected: Int) {
val actual = strategy(nums, k)
assertThat(actual).isEqualTo(expected)
}
}

class MinSubarrayLenBinarySearchTest : MinSubarrayLenTest<MinSubarrayLen>(MinSubarrayLenBinarySearch())
class MinSubarrayLenSlidingWindowTest : MinSubarrayLenTest<MinSubarrayLen>(MinSubarrayLenSlidingWindow())

0 comments on commit 6eb4411

Please sign in to comment.