Explanation of this prefix Sum Coding Challenge from Codility GenomicRangeQuery in Swift 4.2 - swift

Could someone explain how this prefix sum calculation work as I am confused I mean I understand that it creates an array of Ints with the prefix-sums of the letters but I do not understand how? Could someone perhaps post a more naive logic or some explanation? Or perhaps a shorter version of that MAP function as it is all confusingly complicated.
Link to the challenge just in case someone would like to have a look at it
public func solution(_ S : inout String, _ P : inout [Int], _ Q : inout [Int]) -> [Int] {
//The mapping below needs the explanation
var prefixSumA = S.map({ () -> (Character) -> Int in
var s = 0; return {
if $0 == "A" {
return (s += 1, s).1
}
return s
}
}())//until here
prefixSumA.insert(0, at: 0)
var prefixSumC = S.map({ () -> (Character) -> Int in
var s = 0; return {
if $0 == "C" {
return (s += 1, s).1
}
return s
}
}())
prefixSumC.insert(0, at: 0)
var prefixSumG = S.map({ () -> (Character) -> Int in
var s = 0; return {
if $0 == "G" {
return (s += 1, s).1
}
return s
}
}())
prefixSumG.insert(0, at: 0)
let iterations = min(P.count, Q.count)
var result = [Int]()
for i in 0...iterations - 1 {
let p = P[i]
let q = Q[i] + 1
if prefixSumA[q] - prefixSumA[p] > 0 {
result.append(1)
} else if prefixSumC[q] - prefixSumC[p] > 0 {
result.append(2)
} else if prefixSumG[q] - prefixSumG[p] > 0 {
result.append(3)
} else {
result.append(4)
}
}
return result
}

prefixSumA calculates the number of As from the start to every given index. The same can be said about prefixSumC, and prefixSumG.
For example, if the string S is "CAGCCTA", we'll have:
prefixSumA = [0, 0, 1, 1, 1, 1, 1, 2]
prefixSumC = [0, 1, 1, 1, 2, 3, 3, 3]
prefixSumG = [0, 0, 0, 1, 1, 1, 1, 1]
(Notice the zero inserted at the beginning.)
This block of code:
var prefixSumA = S.map({ () -> (Character) -> Int in
var s = 0; return {
if $0 == "A" {
return (s += 1, s).1
}
return s
}
}())
prefixSumA.insert(0, at: 0)
returns a closure that, if the character is A, would capture the current value of s (which is the last value in the array), increment it, end return it (s).
return (s += 1, s).1 is a fancy way, that could be written as:
s += 1
return s
The whole block can be written more simply:
var prefixSumA = [0]
var countOfA = 0
prefixSumA += S.map { char in
if char == "A" { countOfA += 1 }
return countOfA
}
The same can be done for prefixSumC and prefixSumG.

I tried this one and got 62%. Performance Tests Fails.
public func solution(_ S : inout String, _ P : inout [Int], _ Q : inout [Int]) -> [Int] {
// write your code in Swift 4.2.1 (Linux)
var retArr = [Int]()
var chrArr = [Character]()
for chr in S {
chrArr.append(chr)
}
for i in 0..<P.count {
var minFactor = 4
if P[i] - Q[i] == 0 {
if chrArr[P[i]] == "A"{
minFactor = 1
}else if chrArr[P[i]] == "C"{
minFactor = 2
}else if chrArr[P[i]] == "G"{
minFactor = 3
}
}else {
for j in P[i]...Q[i] {
if chrArr[j] == "A"{
minFactor = 1
break
}else if chrArr[j] == "C"{
minFactor = 2
}else if chrArr[j] == "G"{
if minFactor > 2 {
minFactor = 3
}
}
}
}
retArr.append(minFactor)
}
return retArr
}

Related

Karatsuba multiplication in swift

I was trying to implement Karatsuba multiplication in swift. I wrote the below code and it is working fine for some smaller numbers but as the number gets bigger this code fails to give the correct answer. I have debugged in every possible way I can but could not find the bug. Algorithm wise I think I did correctly write the code. And the code is working fine for smaller numbers. But the final answer is wrong for bigger numbers. If anyone out there can crack down the mistake I'm making, pls do help me
func findMultiplication(x: String, y: String) -> String {
if isZero(str: x) || isZero(str: y) {
return "0"
}
var x = removeLeadingZeros(number: x)
var y = removeLeadingZeros(number: y)
if x.count < 2 || y.count < 2 {
let result = Int(x)!*Int(y)!
return String(result)
}
var middleIndexX: String.Index
var middleIndexY: String.Index
var middleIndex: Int
if x.count >= y.count {
y = addLeftPaddingZeros(numberOfZeros: x.count-y.count, for: y)
middleIndex = x.count / 2
if x.count % 2 != 0 {
middleIndex += 1
}
} else {
x = addLeftPaddingZeros(numberOfZeros: y.count-x.count, for: x)
middleIndex = y.count / 2
if y.count % 2 != 0 {
middleIndex += 1
}
}
middleIndexX = x.index(x.startIndex, offsetBy: middleIndex)
middleIndexY = y.index(y.startIndex, offsetBy: middleIndex)
let a = String(x[x.startIndex..<middleIndexX])
let b = String(x[middleIndexX..<x.endIndex])
let c = String(y[y.startIndex..<middleIndexY])
let d = String(y[middleIndexY..<y.endIndex])
let ac = findMultiplication(x: a, y: c)
let bd = findMultiplication(x: b, y: d)
let aPb = Int(a)! + Int(b)!
let cPd = Int(c)! + Int(d)!
let gauss = findMultiplication(x: String(aPb), y: String(cPd))
let thirdItem = String(Int(gauss)! - Int(ac)! - Int(bd)!)
var returnSum = 0
returnSum += Int(addLeftPaddingZeros(numberOfZeros: x.count, for: ac, isLeft: false)) ?? 0
returnSum += Int(addLeftPaddingZeros(numberOfZeros: middleIndex, for: thirdItem, isLeft: false)) ?? 0
returnSum += Int(bd) ?? 0
return String(returnSum)
}
print(findMultiplication(x: "123400", y: "123711"))
func removeLeadingZeros(number: String) -> String {
var number = number
while number.first == "0" {
number.removeFirst()
}
if number == "" {
return "0"
}
return number
}
//The function name is given like this only. BUt his will help to add padding zero in left and right also
func addLeftPaddingZeros(numberOfZeros: Int, for str: String, isLeft: Bool = true) -> String {
var padding = ""
for _ in 0 ..< numberOfZeros {
padding += "0"
}
if isLeft {
return padding+str
} else {
return str + padding
}
}
func isZero(str: String) -> Bool {
for char in str {
if char != "0" {
return false
}
}
return true
}

Is it possible in Swift to return an Int and a list of int at the same time?

I have to write a function in Swift where I need create a list of int if the counter is different to 0.
Here is my code in Swift :
func compteurZeros(cellule:[[Int]]) -> (compteur:Int, liste:(Int))
{
var compteur = 0;
for i in 0...2
{
for j in 0...2
{
if(cellule[i][j] == 0)
{
compteur = compteur+1
}
}
}
print(compteur)
if (compteur != 0)
{
for i in 0..<(compteur) {
var liste:(Int)
}
}
return (compteur, liste!)
}
But, in the return, I've got this error :
error: use of unresolved identifier 'liste'
return (compteur, liste!)
Thank you for your answer.
You need to change your function somewhat so that it returns an [[Int]] as the second element in the tuple
func compteurZeros(cellule:[[Int]]) -> (compteur:Int, liste:[[Int]]) {
var compteur = 0;
for i in 0...2
{
for j in 0...2
{
if(cellule[i][j] == 0)
{
compteur = compteur+1
}
}
}
var liste = [[Int]]()
if (compteur != 0)
{
for i in 0..<(compteur) {
liste.append([])
}
}
return (compteur, liste)
}
Now this code is not the best so it can be improved by skipping the loops
func compteurZeros(cellule:[[Int]]) -> (compteur:Int, liste:[[Int]]) {
let compteur = cellule.flatMap {$0}.filter {$0 == 0}.count
let liste:[[Int]] = Array(repeating: [], count: compteur)
return (compteur, liste)
}
Since the value compteur is redundant this can be further simplified to
func compteurZeros(cellule:[[Int]]) -> [[Int]] {
return Array(repeating: [], count: cellule.flatMap {$0}.filter {$0 == 0}.count)
}

Compare values calculated from two strings

Two people participate in competition. There will be one easy, difficult and medium question.
Scores per difficulty:
E: 1
M: 3
H: 5
User will enter two strings (A and B) and function should find out greater score or tie.
func winner(A: String, B: String) -> String {
var sumA = 0
var sumB = 0
var sumhigh = 0
var checker: Bool = false
for i in 0..<(A.count-1) {
if (erica[i] == "E") {
sumA += 1
checker = true
} else if (A[i] == "M"){
sumA = sumA + 3
checker = true
} else if (A[i] == "H"){
sumA += 3
checker = true
}
}
return String(sumA)
}
print(winner(A: "EHH", B: "EME"))
Desired result : A Wins // How to achieve this
This will compare the two strings to determine a winner.
func checkWinner(aString: String, bString: String) -> String {
// Make lowercase for comparison, so that input case does not matter
let a = aString.lowercased()
let b = bString.lowercased()
// Dictionary of values
let scoreDict: [Character : Int] = ["e": 1, "m": 3, "h": 5]
// Score variables to increment
var aTotal = 0
var bTotal = 0
// Calculate scores
for char in a {
aTotal += scoreDict[char] ?? 0
}
for char in b {
bTotal += scoreDict[char] ?? 0
}
// Calculate winner
if aTotal == bTotal {
return "It’s a draw"
} else {
return aTotal > bTotal ? "A wins! Score: \(aTotal)" : "B wins! Score: \(bTotal)"
}
}
// Here is an example in which A wins
print(checkWinner(aString: "ehh", bString: "meh"))
check this
func phraseValue(sentence: String) -> Int
{
var count = 0
for letter in sentence
{
if letter == "E"
{
count += 1
}
else if letter == "M"
{
count += 3
}
else if letter == "H"
{
count += 5
}
}
return count
}
and finally
func winner(A: String, B: String) -> String {
var sumA = 0
var sumB = 0
sumA = valuePhrase(sentence: A)
sumB = valuePhrase(sentence: B)
if sumA == sumB
{
return "tie"
}
else if sumA > sumB
{
return String(sumA) + "A wins"
}
else
{
return String(sumB) + "B wins"
}
}

Practical number algorithm too slow

I am trying to write a program to find the practical numbers, from an input from 1 to n.
Practical numbers : https://en.wikipedia.org/wiki/Practical_number
My code is running correctly but it is extremely slow - takes over 20 minutes when it should take 10 seconds. This happens when calculating numbers around 50 - it gets stuck at 44.
It is written in Swift
import Foundation
func getInteger() -> Int {
var firstNum:Int = 0
while true {
// get value from user. Using optional input since readLine returns an optional string.
let input = readLine()
// ensure string is not nil
if let unwrappedInput = input {
if let unwrappedInt = Int(unwrappedInput) {
firstNum = unwrappedInt
break
}
else { // the input doesn't convert into an int
print("`\(unwrappedInput)` is not an integer. Please enter an integer")
}
}
else { // did not enter anything
print("Please enter an integer")
}
}
return firstNum
}
func addOne(signArray: [Int]) -> [Int] { // finds the combinations
var signArray2 = [Int]()
for i in 0...signArray.count-1 {
signArray2.append (signArray[i])
}
for i in 0...signArray2.count-1 {
if signArray2[i] == 1 {
signArray2[i] = 0
}
else {
signArray2[i] = 1
break
}
}
return signArray2
}
func signEval (signArray: [Int], divArray: [Int], inNum: Int) -> Bool {// changes 2nd
var counts = 0
for i in 0...divArray.count-1 {
if signArray[i] == 0 {
counts = divArray[i] + counts }
if counts == inNum {
return true
}
}
return false
}
print("Please enter a number to find the summable numbers up to that number:")
var input2 = getInteger()// if num = 1 print 1 if num = 2 print 1 and 2 else print >2 1, 2
var inNum = 0
var numHalf = 0.0
var numRound = 0.0
var numCheck = false
var numCheck2 = false
var numQuarter = 0.0
var numSixth = 0.0
var divArray:[Int] = []
var theirArray = [Int]()
var signArray = [Int]()// array of 0s and 1s
var summableArray:[Int] = [1,2] // need to check if num is bigger than 2!
for input in 1...input2 {
numHalf = Double (input) / 2.0
numRound = round(numHalf)
if numRound == numHalf {
numCheck = true }
if input > 2 && numCheck == false { // odd numbers greater than one are not summable
}
else { // these are possible summable nums
numQuarter = Double (input) / 4.0
numRound = round(numQuarter)
if numRound == numQuarter {
numCheck = true
}
else {
numCheck = false
}
numSixth = Double(input) / 6.0
numRound = round(numSixth)
if numRound == numSixth {
numCheck2 = true }
else { numCheck2 = false}
if numCheck == true || numCheck2 == true {
theirArray = []
divArray = []
signArray = []
summableArray = []
for i in 1...input {
theirArray.append (i)
}
for i in 1...input { // creates an array of all the diviors of inputted number
if input%i == 0 {
divArray.append (i)
}
}
for j in 1...divArray.count {//
signArray.append(0)
}
for i in 1...input{
let x: Int = Int(pow(Double(2),Double(input-1)))// int 2 to the power of input -1
var Boolcheck = false
for q in 1...x-1 { // i to 2^n -1 (sequence to check)
Boolcheck = (signEval(signArray: signArray, divArray: divArray, inNum: i))// checks
signArray = addOne(signArray: signArray)// adding the ones to the array
if Boolcheck == true {
summableArray.append(i)// creates array of mini summable numbers
break
}
}
if summableArray.count == input {
print ("\(input)")
}
}
}
}
}

swift string advancedBy is slow?

So I am writing in swift to practice some online judge.
Here's the issue: Longest Palindromic Substring
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
So I am using dp to solve it in swift:
class Solution {
func longestPalindrome(s: String) -> String {
var hash = Array(count: s.characters.count, repeatedValue: Array(count: s.characters.count, repeatedValue: false))
for i in 0 ..< s.characters.count {
hash[i][i] = true
}
var maxStart = 0
var maxEnd = 0
var maxCount = 1
for i in 1.stride(through: s.characters.count - 1, by: 1) {
for j in 0 ..< s.characters.count - 1 {
if j + i < s.characters.count {
if isValidPalindrome(j, j + i, s, hash) {
hash[j][j + i] = true
if maxCount < i + 1 {
maxCount = i
maxStart = j
maxEnd = j + i
}
}
}
else {
break
}
}
}
// construct max palindrome string, swift string is so dummy
var str = ""
for i in maxStart...maxEnd {
let index = s.characters.startIndex.advancedBy(i)
str += String(s.characters[index])
}
return str
}
func isValidPalindrome(start: Int, _ end: Int, _ s: String, _ hash: [[Bool]]) -> Bool {
// end <= s's length - 1
let startIndex = s.startIndex.advancedBy(start)
let endIdnex = s.startIndex.advancedBy(end)
if end - start == 1 {
return s[startIndex] == s[endIdnex]
}
else {
let left = start + 1
let right = end - 1
return s[startIndex] == s[endIdnex] && hash[left][right]
}
}
}
I am thinking it's a correct one, but when I submit, always time exceeded for long strings like:
"kyyrjtdplseovzwjkykrjwhxquwxsfsorjiumvxjhjmgeueafubtonhlerrgsgohfosqssmizcuqryqomsipovhhodpfyudtusjhonlqabhxfahfcjqxyckycstcqwxvicwkjeuboerkmjshfgiglceycmycadpnvoeaurqatesivajoqdilynbcihnidbizwkuaoegmytopzdmvvoewvhebqzskseeubnretjgnmyjwwgcooytfojeuzcuyhsznbcaiqpwcyusyyywqmmvqzvvceylnuwcbxybhqpvjumzomnabrjgcfaabqmiotlfojnyuolostmtacbwmwlqdfkbfikusuqtupdwdrjwqmuudbcvtpieiwteqbeyfyqejglmxofdjksqmzeugwvuniaxdrunyunnqpbnfbgqemvamaxuhjbyzqmhalrprhnindrkbopwbwsjeqrmyqipnqvjqzpjalqyfvaavyhytetllzupxjwozdfpmjhjlrnitnjgapzrakcqahaqetwllaaiadalmxgvpawqpgecojxfvcgxsbrldktufdrogkogbltcezflyctklpqrjymqzyzmtlssnavzcquytcskcnjzzrytsvawkavzboncxlhqfiofuohehaygxidxsofhmhzygklliovnwqbwwiiyarxtoihvjkdrzqsnmhdtdlpckuayhtfyirnhkrhbrwkdymjrjklonyggqnxhfvtkqxoicakzsxmgczpwhpkzcntkcwhkdkxvfnjbvjjoumczjyvdgkfukfuldolqnauvoyhoheoqvpwoisniv"
I can get the correct result qahaq after some time, and I am wondering why it's so slow. If I write it in other language, not so bad.
I suspect the API s.startIndex.advancedBy(start) is causing it, but I checked the doc, no time complexity and no other ways to turn an int to the startIndex type?
Any ideas to replace advancedBy? Thank in advance.
For those having the same issue: I turned swift String into Array, and it gets much faster.
I also looked into Swift source code about the advancedBy implementation, it's a O(n) opreation, that's why it's slow.
For whom is interested in the implementation, take a look at https://github.com/apple/swift/blob/8e12008d2b34a605f8766310f53d5668f3d50955/stdlib/public/core/Index.swift
You will see advancedBy is merely multiple successor():
#warn_unused_result
public func advanced(by n: Distance) -> Self {
return self._advanceForward(n)
}
/// Do not use this method directly; call advanced(by: n) instead.
#_transparent
#warn_unused_result
internal func _advanceForward(_ n: Distance) -> Self {
_precondition(n >= 0,
"Only BidirectionalIndex can be advanced by a negative amount")
var p = self
var i : Distance = 0
while i != n {
p._successorInPlace()
i += 1
}
return p
}
This should do the trick. Before implementing it, I recommend checking out some explanations such as this guy's. https://www.youtube.com/watch?v=obBdxeCx_Qs. I'm not affiliated with him, though I do believe his video is somewhat useful.
func longestPalindrome(_ s: String) -> String {
var charArray = [Character("$"), Character("#")]
for i in s.characters {
charArray += [i, Character("#")]
}
charArray += [Character("#")]
var mir = 0, c = 0, r = 0, longestPalindromeIndex = 0, longestPalindromeLength = 0, ss = "", returnString = ""
var p = [Int]()
//MARK: For loop
for i in 0...(charArray.count - 1) {
p += [0, 0]
mir = 2 * c - i
if i < r {
p[i] = min(r - i, p[mir])
}
if i - (1 + p[i]) >= 0 && i + (1 + p[i]) < charArray.count - 1 {
while charArray[i + (1 + p[i])] == charArray[i - (1 + p[i])] {
p[i] += 1
}
}
if p[i] > longestPalindromeLength {
longestPalindromeIndex = i
longestPalindromeLength = p[i]
}
if i + p[i] > r {
c = i
r = i + p[i]
}
}//for loop
for i in Array(charArray[(longestPalindromeIndex - longestPalindromeLength)...(longestPalindromeIndex + longestPalindromeLength)]) {
ss = String(i)
if ss != "#" && ss != "$" && ss != "#" {
returnString += ss
}
}
return returnString
}//func