Swift: Find closest value in array with binary search - arrays

I I try to find the closest value in an array using binary search. Everything works fine as long as the value I am looking for is not smaller than the smallest value in the array.
Unfortunately, the debugger did not result in anything helpful. So I ask the community now. You can also try the code directly in the Xcode Playground. I tried to change an other searched value to a smaller value as in the array, but got the same error.
Error: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
func closestValue(_ arr: [Int],_ target: Int) -> Int {
var leftPointer = 0
var rightPointer = arr.count-1
while leftPointer < rightPointer {
let middleIndex = (leftPointer + rightPointer) / 2
let middleValue = arr[middleIndex]
if middleValue == target {
return middleValue
}
//Check for out of bounds error
let leftIndex = middleIndex-1
let leftValue = arr[leftIndex]
if leftValue <= target && middleValue >= target {
let leftDistance = abs(leftValue-target)
let rightDistance = abs(middleValue-target)
if leftDistance <= rightDistance {
return leftValue
} else {
return middleValue
}
}
if middleValue <= target {
leftPointer = middleIndex+1
} else {
rightPointer = middleIndex
}
}
guard let first = arr.first, let last = arr.last else {
fatalError()
}
if target <= first {
return first
} else if target >= last {
return last
} else {
fatalError()
}
}
let first = [1,2,3,5,5,5,7,9,19,11] // 6 --> 5
let second = [1,2,3] // 8 --> 3
let third = [9, 10, 22, 59, 67, 72, 100] // 70 --> 72
let fourth = [100, 101, 102] //5 --> 100 => Heres the error
print(closestValue(first, 6))
print(closestValue(second, 8))
print(closestValue(third, 110))
print(closestValue(fourth, 5))
I expected the fourth output 100. Because 100 is the closest value to 5 in the fourth array.

I can see you put in some boundary checks, but they should happen at the beginning of the function instead of the end. Allow me to rewrite the whole function:
func closestValue(_ arr: [Int],_ target: Int) -> Int {
// Array must not be empty
guard arr.count > 0 else { fatalError("Array must not be empty") }
// If array has only 1 element, that element is the closest
guard arr.count > 1 else { return arr[0] }
// To use binary search, your array must be ever-increasing or ever-decreasing
// Here, we require that the array must be ever-increasing
for index in 1..<arr.count {
if arr[index - 1] > arr[index] {
fatalError("Array must be monotonous increasing. Did you forget to sort it?")
}
}
// If the target is outside of the range of the array,
// return the edges of the array
guard arr.first! <= target else { return arr.first! }
guard target <= arr.last! else { return arr.last! }
// Now some actual searching
var left = 0
var right = arr.count - 1
while left < right {
if left == right - 1 {
return abs(arr[left] - target) <= abs(arr[right] - target) ? arr[left] : arr[right]
}
let middle = (left + right) / 2
switch arr[middle] {
case target:
return target
case ..<target:
left = middle
default:
right = middle
}
}
fatalError("It should never come here")
}
let first = [1,2,3,5,5,5,7,9,11,19] // 6 --> 5
let second = [1,2,3] // 8 --> 3
let third = [9, 10, 22, 59, 67, 72, 100] // 70 --> 72
let fourth = [100, 101, 102] //5 --> 100
print(closestValue(first, 6))
print(closestValue(second, 8))
print(closestValue(third, 70))
print(closestValue(fourth, 5))
Some notes:
if left == right - 1 { ... } allows the while loop to terminate. Otherwise, integer division will round middle down to `left, resulting in a infinite loop.
case ..<target is a short hand for "when arr[middle] < target"
The while should always find a solution and return from inside but I have not thoroughly tested that yet. If you find a case where it reaches the last fatalError, let me know.
The first example has two answers: both 5 and 7 are 1-away from target = 6.

Related

Need help to solve challenging Data structure problem

I came across this problem where given an array of integers, tell if the sequence of
integers will exit the array from left, right or
deadend. You enter the array from the left and move
N indices(where N is the value of the integer) in the
specified direction(positive is right, negative
is left)
Examples
[1,1,1] -> Exits Right
[1,-2]=> Exits Left
[2,0,-1]-> Deadends
[2,5,1,-2,0]-> Exits Right
One solution which comes to my mind is if value of all integers are positive then
Exits Right or Exits Left. However this solution does not cover all the scenario.
I need help to solve this problem.
You can do this:
Create a variable to hold index position and initialize it with first value
Loop over array and on every iteration, compute new value of index by adding value of pointed index.
At the end of loop, check:
Right: If index >= array.length`
Left: if index < 0
Deadend: If index is in bounds
Based on this, below is an example using Javascript:
function printDirection(arr) {
let index = arr[0];
for (let i = 1; i < arr.length; i++) {
/**
* Below condition covers following cases:
* 1. If the value is undefined. This will happen if index is out of bound
* 2. If value is 0. In this case, `index` will never change and remaining iterations can be skipped
*/
if (!arr[index]) break;
index += arr[index]
}
if (index >= arr.length) {
console.log('Exit Right')
} else if (index < 0) {
console.log('Exit Left')
} else {
console.log('Deadend')
}
}
const data = [
[1, 1, 1],
[1, -2],
[2, 0, -1],
[2, 5, 1, -2, 0],
]
data.forEach((arr) => printDirection(arr))
Here some hacky golang:
package main
import (
"fmt"
)
func WhereIsTheExit(arr []int) {
if (len(arr) == 0) {
fmt.Println("No elements")
return
}
i := arr[0]
for p := 1; p < len(arr); p++ {
fmt.Printf("Current value: %d\n", i)
if (i > len(arr) - 1 || i < 0) {
break
}
i += arr[i]
fmt.Printf("Next value: %d\n", i)
}
if (i >= len(arr)) {
fmt.Println("====> right")
} else if (i < 0) {
fmt.Println("====> left")
} else {
fmt.Println("====> deadend")
}
}
func main() {
empty := []int{}
deadend := []int{1,2,0,-3}
deadend2 := []int{1,0,-1}
right := []int{2,0,3,0,0}
right2 := []int{1,2,0,4,0,2,7,1}
left := []int{1,-2}
left2 := []int{1,2,0,3,0,0,-10}
WhereIsTheExit(empty)
WhereIsTheExit(deadend)
WhereIsTheExit(deadend2)
WhereIsTheExit(right)
WhereIsTheExit(right2)
WhereIsTheExit(left)
WhereIsTheExit(left2)
}
Try out: https://play.golang.org/p/KU4mapYf_b3

Performance of moving zeros to the end of an array programming exercise

I wonder why my solution to this LeetCode "Move Zeros" problem is slower than the majority of other submissions. Is there a better way to approach this problem to make it faster?
The question is as follows:
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. You must do this in-place without making a copy of the array.
Example:
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
This is my solution:
func moveZeroes(_ nums: inout [Int]) {
var index = 0
for (i,n) in nums.enumerated()
{
if n != 0
{
nums[index] = n
index += 1
}
}
while index < nums.count
{
nums[index] = 0
index += 1
}
}
LeetCode gives me these statistics:
Runtime: 52 ms, faster than 40.50% of Swift online submissions for Move Zeroes.
Memory Usage: 19.4 MB, less than 13.33% of Swift online submissions for Move Zeroes.
EDIT 1:
If I approach the problem as follows, it does not move the zeros at the end,
EDIT 2:
Here is 36ms in-place solution for you :
class Solution {
func moveZeroes(_ nums: inout [Int]) {
if nums.count < 2 {
return
}
var j = 0
while j < nums.count, nums[j] != 0 {
j += 1
}
if j < nums.count - 1 {
for i in j+1..<nums.count {
if nums[i] != 0 {
nums.swapAt(i, j)
j += 1
}
}
}
}
}
From what I can see, it's likely other submissions are doing this
Check and count 0's in string
Remove 0's
Replace number of 0's at the end of the string
A logical method no doubt, but I'd say yours just picks the basic needs of the challenge and goes for it.
I would personally use:
input = input.filter { $0 != 0 } + input.filter { $0 == 0 }
which can be simplified to one pass:
let nonZeros = input.filter { $0 != 0 }
input = nonZeros + Array(repeating: 0, count: input.count - nonZeros.count)
EDIT: The simplest version without creating a new array would be some primitive version of bubble sort, e.g.:
var numZeros = 0
// iterate array from start to end
for (offset, element) in input.enumerated() {
if element == 0 {
// count every zero
numZeros += 1
} else if numZeros > 0 {
// move every non-zero element left
input[offset - numZeros] = element
// replace with zero
input[offset] = 0
}
}
Another approach is the half-stable-partition algorithm. The benefit is the items are swapped rather than removed and inserted/appended.
Half-stable means the order of the left side of the split point is preserved.
extension Array {
mutating func halfStablePartition(indexes : IndexSet) { // code is O(n)
guard var i = indexes.first, i < count else { return }
var j = index(after: i)
var k = indexes.integerGreaterThan(i) ?? endIndex
while j != endIndex {
if k != j { swapAt(i, j); formIndex(after: &i) }
else { k = indexes.integerGreaterThan(k) ?? endIndex }
formIndex(after: &j)
}
}
}
var input = [0,1,0,3,12]
let indices = IndexSet(input.indices.filter{input[$0] == 0})
input.halfStablePartition(indexes: indices)
Swift 4.2 or later using removeAll mutating method:
Mutating the input:
class Solution {
func moveZeroes(_ nums: inout [Int]) {
var counter = 0
nums.removeAll {
if $0 == 0 {
counter += 1
return true
}
return false
}
nums += repeatElement(0, count: counter)
}
}
A similar approach for Swift 4.1 or earlier
func moveZeroes(_ nums: inout [Int]) {
var counter = 0
nums.indices.reversed().forEach {
if nums[$0] == 0 {
counter += 1
nums.remove(at: $0)
}
}
nums += repeatElement(0, count: counter)
}
var input = [0,1,0,3,12]
moveZeroes(&input)
input // [1, 3, 12, 0, 0]
Non mutating approach:
func moveZeroes(_ nums: [Int]) -> [Int] {
var counter = 0
return nums.filter {
if $0 == 0 { counter += 1 }
return $0 != 0
} + repeatElement(0, count: counter)
}
let input = [0,1,0,3,12]
let zerosMoved = moveZeroes(input)
zerosMoved // [1, 3, 12, 0, 0]
For modifying array in place, and keeping it:
O(n) for Time Complexity
O(1) for Space Complexity
Cracked my head way to long for this one. The cleanest way if you swap element that is NOT zero:
func moveZeroes(_ nums: inout [Int]) {
// amount of swaps, will be used a as reference for next swap index
var j = 0
for (i, e) in nums.enumerated() {
if e != 0 {
nums.swapAt(j, i)
j += 1
}
}
}
One fast solution is to shift non-zero elements to the left by the amount of zeros encountered until then:
func moveZeroes(_ nums: inout [Int]) {
var offset = 0
for i in 0..<nums.count {
if nums[i] == 0 { offset += 1 }
else { nums.swapAt(i, i-offset) }
}
}
This solution takes exactly N steps, and at each step we either perform an addition, or a swap, which are both quite fast.
Your solution, on the other hand required two iterations, resulting in 2*N steps, which is why it was slower than other solutions.

How to factor an integer into an array of powers of 2?

I'm trying to implement something like binary masking where I turn an Int into an array of it's components (powers of 2), for example:
69 = [64, 4, 1]
I don't want to use binary masking and shifting, because I want to use Swift enums for interface elements:
enum State: Int{
case readyButton = 1
case workingButton = 2
case sleepingButton = 4
//etc
}
then 7 = [.sleepingButton, .workingButton, .readyButton] // 7 = 4+2+1
Are there some tools built in Swift to help me turn an Int into power of 2 components?
You may be looking for something like this. As it is written, it will crash when the values do not match up, but you can adapt it for your purposes. Though it does use shifting, it still converts to your enum nicely.
extension UInt32 {
func state() -> [State] {
var bitvals: [UInt32] = []
var mask: UInt32 = 1
while mask > 0 {
if mask & self > 0 {
bitvals.append(mask)
}
mask = mask << 1
}
let state = bitvals.map { State(rawValue: $0)! }
return state
}
}
enum State: UInt32 {
case readyButton = 1
case workingButton = 2
case sleepingButton = 4
}
let val: UInt32 = 7
print(val.state())
This would print out the example you gave at the end of your question.
Updated answer to convert any Int into an array of powers of 2. Uncomment fatal error if you want it to crash on negative values
enum State: Int {
case illegal = -1
case readyButton = 1
case workingButton = 2
case sleepingButton = 4
}
Here is a general solution for decomposing integers into powers of 2:
extension Int {
func toPowersOf2() -> [Int] {
guard self > 0 else {
// fatalError("The number should be strictly positive")
print("The number should be strictly positive")
return [-1] //not really - use fatal error above to enforce crash if you don't want this behavior
}
var arrayOfPowers: [Int] = [] //Will hold the desired powers
var remainder: Int = self //We will substract found powers from the original number
//Since Ints are coded on 64 bits (the 64th is for the sign)
//Let's create an array of all the powers of 2 that
//could be used to decompose an integer
let powers = (0...62).map { NSDecimalNumber(decimal: pow(2.0, $0)).intValue }
//Let's go from the highest to the lowest power
for i in (0 ..< powers.count).reversed() {
//Here we are looking for the power just smaller than the remainder
if i < powers.count - 1, powers[i] <= remainder, powers[i + 1] > remainder {
let p = powers[i]
arrayOfPowers.append(p)
remainder -= p
}
//if this is the biggest power and it is smaller than the number, then add it to arrayOfPowers
else if i == powers.count - 1, powers[i] <= remainder {
let p = powers[i]
arrayOfPowers.append(p)
}
}
return arrayOfPowers
}
func toStateArray() -> [State] {
let array = self.toPowersOf2().map{ State(rawValue: $0) }.filter{ $0 != nil }
return array as! [State]
}
}
And you could use it like so:
(-1).toStateArray()//[illegal]
0.toStateArray() //[illegal]
7.toPowersOf2() //[4, 2, 1]
7.toStateArray() //[sleepingButton, workingButton, readyButton]

Hiow to obtain enumerated .map values for .filter on lower and higher results, (_:max) applied

Following on from my earlier answered question:
Why does map(_:) in Swift Playground return a String and not a tuple?
Given an array of orders, a player has a number of goods for sale
let orders = [2,3,5]
let goods = 1
Note: The array should not be ordered.
I'm wanting to apply some equality rules and return an index and value tuple for three rules;
(a) Perfect match
Resolved in earlier question
(b) When lower number rule is valid
The number of goods does not equal to any of the orders;
moreover he has fewer goods than the highest order value.
Post-effect: Only return the highest order value && index
In this example, the answer is an array of
[2, 3, 5] because goods = 1 and is lower than any of the orders
Similarly if goods = 4 then the answer would be: [5]
When this rule is true; only return the highest order value.
Currently I do this via:
let lower = orders.filter({goods < $0})
print ("Lower: \(lower)")
// Output is Lower: [2, 3, 5]
or to put it more accurately, I use:
let lower = orders.filter({goods < $0}).max() ?? 0 as Int
// Output is 5
However; this does not get me the index of the orders array where this rule is true.
(c) When higher number rule is valid
The player has more goods than the highest order value
showing in the orders array
Post-effect: Only return highest order value && index
Example:
If goods = 8
let higher = orders.filter({goods > $0 }).max() ?? 0 as Int
print ("Higher: \(higher)")
// Output is: 5
However; this does not get me the index of the orders array where this rule is true.
Question >
How do I enumerate through the above filters() where .max() is applied to return the array index & array value for the given lowest and higher number rules?
Many thanks
Edit: Update
I've now compiled it into an if-statement;
// should only return the first result; regardless of how many results returned
let perfectMatch = orders.enumerated().filter({goods == $0.element}).flatMap({
[($0.offset, $0.element)]
}).first
if let perfectMatch = perfectMatch {
print ("Perfect Match: \(perfectMatch)")
}
else {
let lower = orders.enumerated().max(by: {goods < $1.element}).flatMap({
[($0.offset, $0.element)]
})
if let lower = lower {
print("Lower \(lower)")
}
else {
let higher = orders.enumerated().max(by: {goods > $1.element}).flatMap({[($0.offset, $0.element)]})
print("higher \(higher!)")
// if higher fails (unlikely), return a nil
}
}
The problem is that if goods are higher than any/all numbers, ie: 8 and orders are [1,1,1] then the lower boundary should fail / fall through but it always returns
Lower [(0, 1)]
Have you tried using the enumerated() instance method on orders?
This returns an EnumeratedSequence, essentially providing an index value and element value.
let orders = [2,3,5]
// goods == 8
let higher = orders.enumerated().max(by: {goods > $1.element}).flatMap({[($0.offset, $0.element)]})
print(higher!) // Prints [(2, 5)]
// goods == 1
let lower = orders.enumerated().filter({goods < $0.element})
print(lower) // Prints [(0, 2), (1, 3), (2, 5)]
// goods == 4
let lower = orders.enumerated().filter({goods < $0.element})
print(lower) // Prints [(2, 5)]
EDIT:
Made changes based on your comments.
Order type that encapsulates an Int array and your rule checks.
struct Order {
private var _orders: [Int]
var orders: [Int] {
return _orders
}
init(orders: [Int]) {
_orders = orders
}
func match(_ good: Int) -> (Int, Int)? {
var match = _orders.enumerated().filter {
good == $0.element
}
match = match.flatMap {
[($0.offset, $0.element)]
}
return match.first
}
func lower(_ good: Int) -> (Int, Int)? {
let lower = _orders.enumerated().max {
a, b in
return a.element > b.element
}
let upper = _orders.enumerated().max {
a, b in
return a.element < b.element
}
guard let lowerValue = lower?.1, let upperValue = upper?.1 else {
return nil
}
let range = Range(uncheckedBounds: (lowerValue, upperValue))
let inRange = range.contains(good)
if inRange || good < range.lowerBound {
return upper
} else {
return nil
}
}
func higher(_ good: Int) -> (Int, Int)? {
let upper = _orders.enumerated().max {
a, b in
return a.element < b.element
}
guard let upperValue = upper?.element else {
return nil
}
if good > upperValue {
return upper
} else {
return nil
}
}
}
Usage:
var order = Order(orders: [2, 3, 5])
let good = 8
if let match = order.match(good) {
print("Found match for: \(good) in \(order.orders) at index: \(match.0)")
} else {
print("No Match.. Checking Lower...")
if let lower = order.lower(good) {
print("Found lower for: \(good) in \(order.orders) at index: \(lower.0)")
} else {
print("No Lower.. Checking Higher...")
if let higher = order.higher(good) {
print("Found higher for: \(good) in \(order.orders) at index: \(higher.0)")
} else {
print("Failure.")
}
}
}
Output:
No Match.. Checking Lower...
No Lower.. Checking Higher...
Found higher for: 8 in [2, 3, 5] at index: 2

Executing bad excess on receiving a function return array?

What is the problem with the following function to receive and execute:
func FibFast(num: Int) -> Array<Int> {
var fib_arr = [Int](num)
if num < 1 {
fib_arr[0] = 0
return fib_arr
} else if num < 2 {
fib_arr[1] = 1
return fib_arr
}else {
for var i = 2; i < num; i++ {
fib_arr[i] = fib_arr[i-1] + fib_arr[i-2]
}
return fib_arr
}
}
when I am trying to receive the array like:
var newArray = FibFast(10)
it's producing a bad execution.
You are attempting to subscript the array with indexes that don't exist, similarly in your else case you are trying to subscript to an index of 2 when the array is empty.
the line var fib_arr = [Int]() creates an empty array on integers. when you use fib_arr[0] = 0 you are trying to assign the value at index 0 to have a value of 0 but no value currently exists. I would recommend using the append(_) method ie. fib_arr.append(0).
Also when you pass in a value of 10 or anything that is 2 or more as the num parameter your if-else if-else statement is executing the for loop where you are attempting to access the index of 0 and 1 which have not been set as the earlier statements were never executed as they were skipped by the if-else if-else block.
The for loop and assign the values with subscripts is very indicative of the fact that you've probably learnt a different language before swift. You should note that the classic c-style for loop you are trying to use will be removed from swift soon so its better to get in the habbit of no using it. Ive rewritten your code as close to the way you wrote yours, please don't hesitate to ask if you have any questions about it.
func fib(num: Int) -> [Int] {
var fib_arr = [Int]()
if num == 0 {
fib_arr.append(0)
} else if num == 1 {
fib_arr.append(0)
fib_arr.append(1)
} else {
fib_arr = [0, 1]
for i in 2..<num {
fib_arr.append(fib_arr[i - 1] + fib_arr[i - 2])
}
}
return fib_arr
}
The answer proposed by Blake Lockley can also be coded like this:
func FibFast(num: Int) -> Array<Int> {
var fib_arr = [Int]() // empty array
if num < 1 {
fib_arr += [0] // add element [0]
return fib_arr
} else if num < 2 {
fib_arr += [0] // add element [0]
fib_arr += [1] // add element [1]
return fib_arr
}else {
fib_arr = [0, 1] // init with [0, 1]
for var i = 2; i < num; i++ {
// add computed element
fib_arr += [fib_arr[i-1] + fib_arr[i-2]]
}
return fib_arr
}
}

Resources