Find the pair in array with condition - arrays

Let say I have an array of Int, I want to find a pair of number in this array that the sum of this pair is equal to an number, like so:
func findPair(list: [Int], _ sum: Int) -> (Int, Int)? {
for i in 0..<list.count - 1{
for j in (i+1)..<list.count {
let sumOfPair = list[i] + list[j]
if sumOfPair == sum {
return (list[i], list[j])
}
}
}
return nil
}
The first parameter is an array of Int, the second parameter is an number that we need to compare some pairs in that array.
For example:
findPair([1,2,3,4,5], 7) // will return (2, 5), because 2 + 5 = 7
But the complexity of this algorithm is O(n^2).
Is there any way faster?

Try the following approach:
sort(arr,arr+n);//Sort the array
low=0;
high=n-1; // The final index number (pointing to the greatest number)
while(low<=high)
{
if(arr[low]+arr[high]==num)
{ print(low,high);
break;
}
else if(arr[low]+arr[high]<num)
low++;
else if(arr[low]+arr[high]>num)
high--;
}
Basically, you are following the greedy Approach over here... Hope it works.. :)

Try with this:
func findPair(list: [Int], _ sum: Int) -> (Int, Int)? {
//save list of value of sum - item.
var hash = Set<Int>()
var dictCount = [Int: Int]()
for item in list {
//keep track of count of each element to avoid problem: [2, 3, 5], 10 -> result = (5,5)
if (!dictCount.keys.contains(item)) {
dictCount[item] = 1
} else {
dictCount[item] = dictCount[item]! + 1
}
//if my hash does not contain the (sum - item) value -> insert to hash.
if !hash.contains(sum-item) {
hash.insert(sum-item)
}
//check if current item is the same as another hash value or not, if yes, return the tuple.
if hash.contains(item) &&
(dictCount[item] > 1 || sum != item*2) // check if we have 5+5 = 10 or not.
{
return (item, sum-item)
}
}
return nil
}

There surely is much faster O(n log(n)) to solve this problem. Below is the pseudo algorithm for that :-
1) Sort the given array.
2) Take two pointers. One pointing to the beginning and other pointing to the end.
3) Check if sum of two values pointed by two pointer is equal to given number.
4) If yes then return.
5) If greater than increment first pointer and go to step 3.
6) Else decrement second pointer and go to step 3.*

Related

Find all unsorted pairs in partially sorted array

I have to find (or atleast count) all pairs of (not necessarily adjacent) unsorted elements in a partially sorted array.
If we assume the sorting to be ascending, the array [1 4 3 2 5] has the following unsorted pairs: (4, 3), (3, 2) and (4, 2).
I'm thinking of an algorithm that works along the lines of insertion sort, as insertion sort tends to compare every new element with all elements which are misplaced with respect to the new element.
Edit: While posting the question, I didn't realise that finding the pairs would have a higher time complexity than counting them. Is there a better possible algorithm that just counts how many such pairs exist?
It depends a little bit on what you mean exactly by "partially sorted" - One could argue that every array is partially sorted to some degree.
Since this algorithm has worst-case complexity O(n^2) anyway (consider the input sorted in descending order), you might as well go down the straight-forward route:
ret = []
for i in range(len(array)):
for j in range(i, len(array)):
if array[i] > array[j]:
ret.append((array[i], array[j]))
return ret
This works very well for random arrays.
However, I suppose what you have in mind is more something that there are larger stretches inside the array where the numbers are sorted but that that's not the case for the array as a whole.
In that case, you can save a bit of time over the naive approach above by first identifying those stretches - this can be done in a linear pass. Once you have them, you only have to compare these stretches with each other, and you can use binary search for that (since the stretches are in sort order).
Here's a Python implementation of what I have in mind:
# find all sorted stretches
stretches = []
begin = 0
for i in range(1, len(array)):
if array[i-1] > array[i]:
stretches.append(array[begin:i])
begin = i
if i+1 > begin:
stretches.append(array[begin:])
# compare stretches
ret = []
for i in range(len(stretches)):
stretchi = stretches[i]
stretchi_rev = None
for j in range(i+1, len(stretches)):
stretchj = stretches[j]
if stretchi[-1] > stretchj[0]:
if stretchi_rev is None:
stretchi_rev = list(reversed(stretchi))
hi = len(stretchj)
for x in stretchi_rev:
i = bisect.bisect_left(stretchj, x, 0, hi)
if i == 0:
break
else:
for y in stretchj[:i]:
ret.append((x, y))
hi = i
return ret
For random arrays, this will be slower than the first approach. But if the array is big, and the amount of partially sorted portions is high enough, this algorithm will at some point starting to beat the brute-force search.
As suggested by #SomeDude in the comments, if you just need to count pairs there's an O(nlogn) solution based on building a binary search tree. There are some subtleties involved - we need to keep track of the number of duplicates (ic) at each node, and for performance reasons we also keep track of the number of right children (rc).
The basic scheme for inserting a value v intro the tree rooted at node n is:
def insert(n, v)
if v < n.data
count = 1 + n.ic + n.rc
if n.left is null
n.left = node(v)
return count
return count + insert(n.left, v)
else if v > n.data
if n.right is null
n.right = node(v)
n.rc = 1
return 0
n.rc += 1
return insert(n.right, v)
else // v == n.data
n.ic += 1
return n.rc
And here's some functioning Java code (Ideone):
static int pairsCount(Integer[] arr) {
int count = 0;
Node root = new Node(arr[0]);
for(int i=1; i<arr.length; i++)
count += insert(root, arr[i]);
return count;
}
static int insert(Node n, int v) {
if(v < n.value) {
int count = 1 + n.rc + n.ic;
if(n.left == null) {
n.left = new Node(v);
return count;
}
return count + insert(n.left, v);
}
else if(v > n.value) {
if(n.right == null) {
n.right = new Node(v);
n.rc = 1;
return 0;
}
n.rc += 1;
return insert(n.right, v);
}
else {
n.ic += 1;
return n.rc;
}
}
static class Node {
int value;
Node left, right;
int rc; // right children count
int ic; // duplicate count
Node(int value) {
this.value = value;
}
}
Test:
Integer[] arr = {1, 4, 3, 2, 5};
System.out.println(pairsCount(arr));
Output:
3

Does array.count and array[0 ...< index] slow down a binary search?

today I did a test for a job and was asked to search through an array of integers, this is the question:
The goal of this exercise is to check the presence of a number in an
array.
Specifications:
The items are integers arranged in ascending order.
The array can contain up to 1 million items
Implement the function existsInArray(_ numbers: [Int], _ k: Int) so
that it returns true if k belongs to numbers, otherwise the function
should return false.
Example:
let numbers = [-9, 14, 37, 102]
existsInArray(numbers, 102) // returns true
existsInArray(numbers, 36) //returns false
Note: Try to save CPU cycles
Alright, so I gave my answer which is the code below and waited for the result
func existsInArray(_ numbers: [Int], _ k: Int) -> Bool {
if numbers.isEmpty {
return false
}
let numbersHalfIndex: Int = (numbers.count/2)
if k == numbers[numbersHalfIndex] {
return true
} else if k != numbers[0] && numbers.count == 1 {
return false
} else if k <= numbers[numbersHalfIndex] {
let leftHalfNumbersArray = numbers[0 ..< numbersHalfIndex]
return existsInArray(Array(leftHalfNumbersArray), k)
} else if k > numbers[numbersHalfIndex] {
let rightHalfNumbersArray = numbers[numbersHalfIndex ..< numbers.count]
return existsInArray(Array(rightHalfNumbersArray), k)
} else {
return false
}
}
So turns out that "The solution doesn't work in a reasonable time with one million items" and now I don't know what I did wrong since binary search is fast as f*ck.
My only guess is that maybe number.count or numbers[0 ...< numbersHalfIndex] or numbers[numbersHalfIndex ...< number.count] makes everything go slower than expected.
Am I tripping or something?
Edit:
If anyone is curious I tested my code and Martin R code to see how much of an impact using ArraySlice have in terms of time.
I used an array of 100.000.000 itens in ascending order starting from 0.
Here is how I captured the time:
print("////////// MINE //////////")
var startTime = CFAbsoluteTimeGetCurrent()
print(existsInArray(numbers, 0))
var timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for mine: \(timeElapsed) s.")
print("////////// Martin R //////////")
counter = 0
startTime = CFAbsoluteTimeGetCurrent()
print(existsInArrayOptimal(numbers, 0))
timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for Martin R: \(timeElapsed) s.")
And here is the result:
////////// MINE //////////
true
Time elapsed for mine:
1.2008800506591797 s.
////////// Martin R //////////
true
Time elapsed for Martin R: 0.00012993812561035156 s.
It's about 1000x faster!
Accessing number.count is not a problem because that is a O(1) operation for arrays. And slicing with numbers[0 ...< numbersHalfIndex] is not a problem either. But Array(leftHalfNumbersArray) creates a new array from the slice, and that copies all the elements.
There are two possible ways to avoid that:
Update array indices (for lower and upper bound of the current search range) instead of creating arrays which are passed down the recursion.
Pass array slices down the recursion. Slices share the elements with the original array (as long as they are not mutated).
A demonstration of the second approach:
func existsInArray(_ numbers: ArraySlice<Int>, _ k: Int) -> Bool {
if numbers.isEmpty {
return false
}
let numbersHalfIndex = numbers.startIndex + numbers.count / 2
if k == numbers[numbersHalfIndex] {
return true
} else if k < numbers[numbersHalfIndex] {
return existsInArray(numbers[..<numbersHalfIndex], k)
} else {
return existsInArray(numbers[(numbersHalfIndex + 1)...], k)
}
}
Note that array slices share their indices with the original array so that the indices do not necessarily start at zero. That's why numbers.startIndex is used for the index calculation.
And a wrapper function which takes a “real” array argument:
func existsInArray(_ numbers: [Int], _ k: Int) -> Bool {
return existsInArray(numbers[...], k)
}
As #Leo suggested, you can implement this as a collection method instead of implementing two separate methods. Collection indices are not necessarily integers, but for a RandomAccessCollection the index calculations are guaranteed to be O(1). You can also generalize it to collections of arbitrary comparable elements instead of integers.
Here is a possible implementation:
extension RandomAccessCollection where Element: Comparable {
/// Returns a Boolean value indicating whether the collection contains the
/// given element. It is assumed that the collection elements are sorted
/// in ascending (non-decreasing) order.
///
/// - Parameter element: The element to find in the collection.
/// - Returns: `true` if the element was found in the collection; otherwise,
/// `false`.
///
/// - Complexity: O(log(*n*)), where *n* is the size of the collection.
func binarySearch(for element: Element) -> Bool {
if isEmpty {
return false
}
let midIndex = index(startIndex, offsetBy: count / 2)
if element == self[midIndex] {
return true
} else if element < self[midIndex] {
return self[..<midIndex].binarySearch(for: element)
} else {
return self[index(after: midIndex)...].binarySearch(for: element)
}
}
}
Usage:
let numbers = [-9, 14, 37, 102]
print(numbers.binarySearch(for: 102)) // true
print(numbers.binarySearch(for: 36)) // false
Alternatively a non-recursive method which updates the indices of the search range:
extension RandomAccessCollection where Element: Comparable {
func binarySearch(for element: Element) -> Bool {
var lo = startIndex
var hi = endIndex
while lo < hi {
let mid = index(lo, offsetBy: distance(from: lo, to: hi) / 2)
if element == self[mid] {
return true
} else if element < self[mid] {
hi = mid
} else {
lo = index(after: mid)
}
}
return false
}
}

Get an element with its index counting from the end in Kotlin

Is there a simple function to get an element with its index counting from the end in a Kotlin Array, List, or String? In other words, is there a Kotlin equivalent of negative index slicing in Python?
There is no direct function for slicing, but one can write an user defined function or easily simulate using reversed function, that works with string, lists and arrays.
Strings In Python
pyString = 'Python'
sObject = slice(-1, -4, -1)
print(pyString[sObject]) # output: noh
Strings In Kotlin
val pyString = "Python"
val sObject = pyString.reversed().substring(0, 3).reversed() // index 3 excluded
println(pyString) // output: noh
List(or Arrays) in Kotlin
var py = arrayOf(1, 2, 3, 4, 5, 6, 7, 8)
var sObject = py.reversed().slice(0..2).reversed()
println(sObject)
However you can do method or function overload, using this as implicit object
For instance, you can program reverse substring, but here you cannot use negative numbers, because we need a different parameters profile regarding to the original method:
fun String.substring(a: Int, b: Int = 0, rev: Boolean): String {
if (rev == true)
if (b == 0)
return this.substring(0, this.length - a)
else
return this.substring(this.length - b, this.length - a)
else
if (b == 0)
return this.substring(a)
else
return this.substring(a, b)
}
So "whale".substring(0,2,true) is "le"
You can use similar technique to extend slice method.
I implemented a function similar to python's slicing mechanism
import kotlin.math.abs
fun String.substring(startingIndex: Int, endingIndex: Int, step: Int=1): String {
var start = startingIndex
var end = endingIndex
var string = this
if (start < 0) {
start = string.length + start
}
if (end < 0) {
end = string.length + end
}
if (step < 0) {
string = string.reversed()
}
if (start >= string.length) {
throw Exception("Index out of bounds.")
}
var outString = ""
for ((index, character) in string.withIndex()) {
if (index % abs(step) == 0) {
if (index >= start && index <= end) {
outString += character
}
}
}
return outString
}
Can be used like this:
println("This is some text.".substring(8, -6)) // some
There is but on problem with my function, it is that a negative step messes it up if you also use negative indexes.
These answers are quite complicated. If you just want to use a negative index, all you have to do is
exampleList[exampleList.lastIndex - exampleIndex] which will (basically) do the same as exampleList[-exampleindex] in python.
So for example you would do:
fun main(args: Array<String>) {
val exampleList = mutableListOf<Int>(1, 2, 3, 4, 5)
//Now we want exampleList[-1] or 4. I know in python it would be writen as exampleList[-2], but don't worry about that!
println(exampleList[exampleList.lastIndex - 1])
}
the lastIndex parameter is the key thing to remember.

Second array will not increment after repeating for loop

I am new to Kotlin and am trying to compare the elements of two arrays by seeing which array has the greater element. The arrays are created via user input. The error that I am having is that when I repeat the second for loop (inner loop), which contains the contents of the second array, it will not increment to the next element of the second array unlike the first for loop. So if a = {1,2} and b = {2,1}, a would increment through both 1 and 2, but b would stay at 2 through both iterations of the loop. Here is my function that is giving me a problem:
fun practiceCompareArray(a: Array<Int>, b: Array<Int>): Array<Int> {
var j: Array<Int>
var aPoints = 0
var bPoints = 0
for (x:Int in a) {
---------> for (y: Int in b) {
if (x > y) {
aPoints++
} else if (x < y) {
bPoints++
break
}
}
j = arrayOf(aPoints, bPoints)
return j
}
The for loop with the arrow is giving me the problem. I think it is because of the break statement at the end of the inner loop. Do I even need the inner loop to compare each array? Any help or documentation would be helpful.
If you know that both array have the same length and you want to compare them elementwise you could do something like:
fun practiceCompareArray(a: Array<Int>, b: Array<Int>): Array<Int> {
var aPoints = 0
var bPoints = 0
for ((x,y) in a.zip(b)) {
if (x>y) {
aPoints ++
} else {
bPoints ++
}
}
return arrayOf(aPoints, bPoints)
}
or in a more functional style
fun practiceCompareArray(a: Array<Int>, b: Array<Int>): Array<Int> {
val (aPoints, bPoints) = a.zip(b)
.fold(Pair(0,0), {(aScore, bScore), (x,y) ->
if (x > y) Pair(aScore + 1, bScore) else Pair(aScore, bScore + 1)})
return arrayOf(aPoints, bPoints)
}

Finding a Multiple of a Given Number from a Range of Numbers - Swift

I'm trying to remove elements of an array that are multiples of 2, but I am getting an error:
Fatal error: Index out of range
// remove all multiples from numbers array [2,3,4,5,6,7,......] except the current number which is 2
// num = 2
for i in 0...numbers.count {
if(i == num) {
continue
}
if(num % numbers[i] == 0) {
numbers.remove(at: i)
}
}
The array numbers has 998 elements, and num is equal to 2 then iterates to 3 on the next for loop. In theory, the for loop, when the num is 2 should eliminate [4,8,10,12,...] and so on, but it doesn't.
The immediate issue with your current code is that numbers.count is bigger than the last index of numbers due to the 0 indexing. You should use for i in 0..<numbers.count or rather use for i in numbers.indices. Moreover, the two conditions in your if statements are also wrong, they should be if numbers[i] == num { continue}, and if numbers[i] % num == 0. However, you will still have the issue of modifying the array's length inside the loop, but keeping the loop range constant.
A better solution is to simply use filter to achieve your goal. Just check if the current element is a multiple of the number to be removed using the % operator, then check if the number isn't the the number you are seeking and only remove it if both conditions are fulfilled.
let oneToThousand = [Int](2...1000)
func removeMultiplesOf(num:Int, from array:[Int])->[Int]{
return array.filter({ currentNum->Bool in
//Only discard the number if it's a multiple of num, but it is not num
if currentNum%num == 0 && currentNum != num {
return false
} else {
return true
}
})
}
let withoutMultiplesOfTwo = removeMultiplesOf(num: 2, from: oneToThousand)
Output:
[2, 3, 5, 7, 9, 11, 13,...]
If you prefer concise code over readability, you can write the function simply as
func removeMultiplesOf(num:Int, from array:[Int])->[Int]{
return array.filter({ currentNum in return currentNum%num != 0 || currentNum == num })
}

Resources