LeetCode 299. Bulls and Cows, Swift Code - swift

The OJ page is: 299. Bulls and Cows, Swift Code
My Swift Code is:
func getHint(secret: String, _ guess: String) -> String
{
let count = secret.characters.count
var ans = ""
var countA = 0
var countB = 0
var numsCount = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
for i in 0 ..< count
{
let curSecretIndex = secret.startIndex.advancedBy(i)
let curGuessIndex = guess.startIndex.advancedBy(i)
if secret[curSecretIndex] == guess[curGuessIndex]
{
countA += 1
}
else
{
let curSecretNum = Int(String(secret[curSecretIndex]))!
let curGuessNum = Int(String(guess[curGuessIndex]))!
if numsCount[curSecretNum] > 0
{
countB += 1
}
if numsCount[curGuessNum] < 0
{
countB += 1
}
numsCount[curSecretNum] -= 1
numsCount[curGuessNum] += 1
}
}
ans = String(countA) + "A" + String(countB) + "B"
return ans
}
The result it 'Time Limit Exceeded' when running the case:
"6342125515600209181500897947396070342608717883958593622428977819470145518981094482423670643602640743135109789842055897996388630146186752661167826378847934464616412304716111808304498782005822162883686211337836911445498225004774354586168838560300965168000411392051373086314099651372076489284613220040070817961103856849197569739439674339914883676284322398392068700339678002599137137279304395401279115346633764844174685348142841166612675248803215000249557405129671377750613405565000541484366826871257668988459106913268432182614110919996681746630972155917317871065083728781479655332598828637865325616648485574880796687189161689539391392553041342138974604486863793131125744568750189486989526831390549186801009323526430712299903383659261758477604285513561656265905238724724774327396452598472436892619082685728038313372432807929513713314602774582152430611189205157910570001968051407417723280898588867721259234562110839321097595400391525102339288526258798825449826942020614695348904788907661932993430488593552", "2029388157754123013579930824032835962698439709529058700566544658243563588105123607416485416240508396898633255420749620114578170997813662130792145648053315140036623409978307287859342924657549449161362779317296010762442132229389529024391729227555488965589257218766928737602934082420388840064521623805135789781907460246852282793026912370042044884703394961008247101686942091465646505425818246546319109188403876239911011831539311377016115552962442767907020896812732576449580620680669604714802174904961265522985701150408238410077557827782193833638029934745703495039208558090425795228240968930462177363142995202879750991368837565022531005343218914976811148294727154364844319794156224312278949985742616475018653587238917107571280831446981869075410523704462504535667036707669945712843129399060874345018414837070546836481691874559666339572723901027743847187340764130312322743860946054990407323560232897592869469337005471407593834874319157599015450827399558773751402417232829362967857998884017081049757447739946"
How can I improve the performance?
Anyone help? THANKS!

Not sure how did you get the 'Time Limit Exceeded'. Try this in playground:
import Foundation
func bowsAndBulls (guess: String, secret: String) -> String {
if guess.characters.count != secret.characters.count {
return "ERROR"
}
//use counter variables works too
var countA = [String]()
var countB = [String]()
for i in 0..<guess.characters.count {
let start = guess.startIndex.advancedBy(i)
let end = guess.startIndex.advancedBy(i+1)
let single = guess.substringWithRange(start..<end)
if secret.containsString(single) {
if secret.substringWithRange(start..<end) == single {
countA.append(single)
}else{
countB.append(single)
}
}
}
return String(countA.count) + "A" + String(countB.count) + "B"
}
print(bowsAndBulls("5234", secret: "5346"))

Related

Union-find: largest component size by common factor algorithm gives different results on every run

I was practicing data structure algorithm and made a Union - Find solution for the question.
The problem is, I think the code seems ok, but when I run it on Xcode playground, it shows different answers for the same input.
For example, I put an array [4, 6, 15, 35] in the function largestComponentSize, then it shows 2, 3, or 4 as the answer. I don't understand what's happening behind.
class Solution {
var uf = UnionFind()
func largestComponentSize(_ nums: [Int]) -> Int {
var maxNum:Int = 0
var numFactorMap = [Int:Int]()
var factorAdded = Set<Int>()
for num in nums {
var pFactors = getPrimeFactors(num)
numFactorMap[num] = pFactors[0]
for (i, val) in pFactors.enumerated() {
if !factorAdded.contains(val) {
uf.addSet(val)
factorAdded.insert(val)
}
if i > 0 {
uf.union(pFactors[i-1], val)
}
}
}
var groupCountMap = [Int:Int]()
for num in nums {
var groupId = uf.find(numFactorMap[num]!)!
if groupCountMap.keys.contains(groupId) {
groupCountMap[groupId]! += 1
} else {
groupCountMap[groupId] = 1
}
maxNum = max(maxNum, groupCountMap[groupId]!)
}
return maxNum
}
func getPrimeFactors(_ num: Int) -> [Int] {
var ans:Set<Int> = []
if num == 1 {
return []
}
var crrNum = num
var deno = 2
while crrNum >= deno {
if crrNum % deno == 0 {
ans.insert(deno)
crrNum = crrNum / deno
} else {
deno = deno + 1
}
}
return Array(ans)
}
class UnionFind {
var index = [Int: Int]()
var parent: [Int]
var size: [Int]
init() {
parent = []
size = []
}
func addSet(_ ele: Int) {
index[ele] = parent.count
parent.append(parent.count)
size.append(1)
}
func getSetSize(_ ele: Int) -> Int {
if let found = find(ele) {
return size[found]
}
return 0
}
func find(_ ele: Int) -> Int? {
if let indexOfEle = index[ele] {
if parent[indexOfEle] == indexOfEle {
return indexOfEle
} else {
if let found = find(parent[indexOfEle]) {
parent[indexOfEle] = found
}
return parent[indexOfEle]
}
} else {
return nil //never come here
}
}
func union(_ first: Int, _ second: Int) {
guard let indexOfFirst = index[first], let indexOfSecond = index[second] else {
return
}
if parent[indexOfFirst] == parent[indexOfSecond] {
return
}
var indexOfLarger = indexOfFirst
var indexOfSmaller = indexOfSecond
if size[indexOfFirst] < size[indexOfSecond] {
indexOfLarger = indexOfSecond
indexOfSmaller = indexOfFirst
}
parent[indexOfSmaller] = indexOfLarger
size[indexOfLarger] += size[indexOfSmaller]
return
}
}
}
var sol = Solution()
var nums = [4, 6, 15, 35]
var ans = sol.largestComponentSize(nums)
Thank you for your help in advance!
I just tried it on Xcode playground.

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
}

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"
}
}

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

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
}

Levenshtein distance in Swift3

I'm using a tutorial from Rosetta Code to calculate Levenshtein distance. It seems their code is in Swift2 so I get this error Binary operator '+' cannot be applied to operands of type '[Int]' and 'Repeated<String.CharacterView>' when doing this: var cur = [i + 2] + empty where let empty = repeatElement(s, count: 0). How can I go about this?
There were a couple of changes to make.
The construction of the Array empty.
enumerate() is now enumerated()
successor() doesn't exist anymore so I replaced it with +1
So the function is now
Swift 4:
func levDis(_ w1: String, _ w2: String) -> Int {
let empty = [Int](repeating:0, count: w2.count)
var last = [Int](0...w2.count)
for (i, char1) in w1.enumerated() {
var cur = [i + 1] + empty
for (j, char2) in w2.enumerated() {
cur[j + 1] = char1 == char2 ? last[j] : min(last[j], last[j + 1], cur[j]) + 1
}
last = cur
}
return last.last!
}
Swift 3:
func levDis(w1: String, w2: String) -> Int {
let (t, s) = (w1.characters, w2.characters)
let empty = Array<Int>(repeating:0, count: s.count)
var last = [Int](0...s.count)
for (i, tLett) in t.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in s.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
return last.last!
}
Updated and improved answer to Swift 4, based on #Spads answer.
extension String {
func levenshteinDistanceScore(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Float {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating:0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
// maximum string length between the two
let lowestScore = max(firstString.count, secondString.count)
if let validDistance = last.last {
return 1 - (Float(validDistance) / Float(lowestScore))
}
return 0.0
}
}
infix operator =~
func =~(string: String, otherString: String) -> Bool {
return string.levenshteinDistanceScore(to: otherString) >= 0.85
}
func ~=(string: String, otherString: String) -> Bool {
return string.levenshteinDistanceScore(to: otherString) >= 0.85
}
Since #Daniel Illescas answer is not working, here is working version with Int return type and with assert.
extension String {
func levenshteinDistance(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Int {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating: 0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j]) + 1
}
last = cur
}
if let validDistance = last.last {
return validDistance
}
assertionFailure()
return 0
}
}