Breadth First Search: Shortest Reach (BFS) - ios

https://www.hackerrank.com/challenges/bfsshortreach
My strategy is to keep an array of the Node and its corresponding adjacent nodes using an integer and unordered set.
Then I start at the starting node and iterate throughout, keeping a set of all the corresponding adjacent nodes and terminating if I visit any node I've already visited.
Thanks for any Swifters willing to help me! Spent a day trying to figure it out and it's driving me crazy. :(
let testCases : Int = Int(readLine()!)!
for i in 0..<testCases
{
let inputArray : [Int] = String(readLine()!).characters.split(" ").map{Int(String($0))!}
let numberOfNodes : Int = inputArray[0]
let numberOfEdges : Int = inputArray[1]
var dictionary : [Int : Set<Int>] = [:]
var countDictionary : [Int : Int] = [:]
for j in 0..<numberOfEdges
{
let edge : [Int] = String(readLine()!).characters.split(" ").map{Int(String($0))!}
let start : Int = edge[0]
let end : Int = edge[1]
if let val = dictionary[start]
{
dictionary[start]!.insert(end)
}
else
{
dictionary[start] = Set.init(arrayLiteral: end)
}
if let val = dictionary[end]
{
dictionary[end]!.insert(start)
}
else
{
dictionary[end] = Set.init(arrayLiteral: start)
}
}
let temp : [Int] = String(readLine()!).characters.split(" ").map{Int(String($0))!}
let startPoint : Int = temp[0]
var traversed : Set<Int> = Set()
func iterate(node : Int, _ count : Int)
{
let newCount = count + 6
var temp : [Int] = []
if let val = dictionary[node]
{
for i in val
{
temp.append(i)
}
}
if let val = countDictionary[node]
{
if count < val
{
countDictionary[node]! = count
}
}
else
{
countDictionary[node] = count
}
if traversed.contains(node)
{
return
}
traversed.insert(node)
for j in temp
{
iterate(j, newCount)
}
}
iterate(startPoint, 0)
for z in 0..<numberOfNodes
{
if let val = countDictionary[z + 1]
{
if val > 0
{
print(val, terminator: " ")
}
}
else
{
print(-1, terminator: " ")
}
}
print(" ")
}

Related

Gradually and randomly visualize string

I am currently working on a simple program to gradually and randomly visualize a string in two iteration. Right now I have managed to get the first iteration but I'm not sure how to do the second one. If someone could give any example or advice I would be very grateful. My code looks like this:
let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45
var n = s.filter({ $0 != " " }).count // # of non-space characters
var m = lrint(factor * Double(n)) // # of characters to display
let t = String(s.map { c -> Character in
if c == " " {
// Preserve space
return " "
} else if Int.random(in: 0..<n) < m {
// Replace
m -= 1
n -= 1
return c
} else {
// Keep
n -= 1
return "_"
}
})
print(t) // h_l__ _l_______d
To clarify, I want to use factor2 in the second iteration to print something that randomly add letters on top of t that looks something like this h_l_o pl_g_____d.
Replacing Characters
Starting from #MartinR's code, you should remember the indices that have been replaced. So, I am going to slightly change the code that replaces characters :
let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45
var n = s.filter({ $0 != " " }).count // # of non-space characters
let nonSpaces = n
var m = lrint(factor * Double(n)) // # of characters to display
var indices = Array(s.indices)
var t = ""
for i in s.indices {
let c = s[i]
if c == " " {
// Preserve space
t.append(" ")
indices.removeAll(where: { $0 == i })
} else if Int.random(in: 0..<n) < m {
// Keep
m -= 1
n -= 1
t.append(c)
indices.removeAll(where: { $0 == i })
} else {
// Replace
n -= 1
t.append("_")
}
}
print(t) //For example: _e___ ______ou_d
Revealing Characters
In order to do that, we should calculate the number of characters that we want to reveal:
m = lrint((factor2 - factor) * Double(nonSpaces))
To pick three indices to reveal randomly, we shuffle indices and then replace the m first indices :
indices.shuffle()
var u = t
for i in 0..<m {
let index = indices[i]
u.replaceSubrange(index..<u.index(after: index), with: String(s[index]))
}
indices.removeSubrange(0..<m)
print(u) //For example: _e__o _l__g_ou_d
I wrote StringRevealer struct, that handle all revealing logic for you:
/// Hide all unicode letter characters as `_` symbol.
struct StringRevealer {
/// We need mapping between index of string character and his position in state array.
/// This struct represent one such record
private struct Symbol: Hashable {
let index: String.Index
let position: Int
}
private let originalString: String
private var currentState: [Character]
private let charactersCount: Int
private var revealed: Int
var revealedPercent: Double {
return Double(revealed) / Double(charactersCount)
}
private var unrevealedSymbols: Set<Symbol>
init(_ text: String) {
originalString = text
var state: [Character] = []
var symbols: [Symbol] = []
var count = 0
var index = originalString.startIndex
var i = 0
while index != originalString.endIndex {
let char = originalString[index]
if CharacterSet.letters.contains(char.unicodeScalars.first!) {
state.append("_")
symbols.append(Symbol(index: index, position: i))
count += 1
} else {
state.append(char)
}
index = originalString.index(after: index)
i += 1
}
currentState = state
charactersCount = count
revealed = 0
unrevealedSymbols = Set(symbols)
}
/// Current state of text. O(n) conplexity
func text() -> String {
return currentState.reduce(into: "") { $0.append($1) }
}
/// Reveal one random symbol in string
mutating func reveal() {
guard let symbol = unrevealedSymbols.randomElement() else { return }
unrevealedSymbols.remove(symbol)
currentState[symbol.position] = originalString[symbol.index]
revealed += 1
}
/// Reveal random symbols on string until `revealedPercent` > `percent`
mutating func reveal(until percent: Double) {
guard percent <= 1 else { return }
while revealedPercent < percent {
reveal()
}
}
}
var revealer = StringRevealer("Hello товарищ! 👋")
print(revealer.text())
print(revealer.revealedPercent)
for percent in [0.25, 0.45, 0.8] {
revealer.reveal(until: percent)
print(revealer.text())
print(revealer.revealedPercent)
}
It use CharacterSet.letters inside, so most of languages should be supported, emoji ignored and not-alphabetic characters as well.

How can split from string to array by chunks of given size

I want to split string by chunks of given size 2
Example :
String "1234567" and output should be ["12", "34", "56","7"]
You can group your collection elements (in this case Characters) every n elements as follow:
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
sequence(state: startIndex) { start in
guard start < self.endIndex else { return nil }
let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
defer { start = end }
return self[start..<end]
}
}
func subSequences(of n: Int) -> [SubSequence] {
.init(unfoldSubSequences(limitedTo: n))
}
}
let numbers = "1234567"
let subSequences = numbers.subSequences(of: 2)
print(subSequences) // ["12", "34", "56", "7"]
edit/update:
If you would like to append the exceeding characters to the last group:
extension Collection {
func unfoldSubSequencesWithTail(lenght: Int) -> UnfoldSequence<SubSequence,Index> {
let n = count / lenght
var counter = 0
return sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: lenght, limitedBy: endIndex) ?? endIndex
counter += 1
if counter == n {
defer { start = endIndex }
return self[start...]
} else {
defer { start = end }
return self[start..<end]
}
}
}
func subSequencesWithTail(n: Int) -> [SubSequence] {
.init(unfoldSubSequencesWithTail(lenght: n))
}
}
let numbers = "1234567"
let subSequencesWithTail = numbers.subSequencesWithTail(n: 2)
print(subSequencesWithTail) // ["12", "34", "567"]
var testString = "abcdefghijklmnopqrstu"
var startingPoint: Int = 0
var substringLength: Int = 1
var substringArray = [AnyHashable]()
for i in 0..<(testString.count ?? 0) / substringLength {
var substring: String = (testString as NSString).substring(with: NSRange(location: startingPoint, length: substringLength))
substringArray.append(substring)
startingPoint += substringLength
}
print("\(substringArray)")
OutPut :
(
a,
b,
c,
d,
e,
f,
g,
h,
i,
j,
k,
l,
m,
n,
o,
p,
q,
r,
s,
t,
u
)
try this
func SplitString(stringToBeSplitted:String, By:Int) -> [String]
{
var newArray = [String]()
var newStr = String()
for char in stringToBeSplitted
{
newStr += String(char)
if newStr.count == By
{
newArray.append(newStr)
newStr = ""
}
}
return newArray
}
Swift 5
extension Array {
func chunks(size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
extension String {
func chunks(size: Int) -> [String] {
map { $0 }.chunks(size: size).compactMap { String($0) }
}
}
let s = "1234567"
print(s.chunks(size: 2)) // ["12", "34", "56", "7"]
extension String {
func split(len: Int) -> [String] {
var currentIndex = 0
var array = [String]()
let length = self.characters.count
while currentIndex < length {
let startIndex = self.startIndex.advancedBy(currentIndex)
let endIndex = startIndex.advancedBy(len, limit: self.endIndex)
let substr = self.substringWithRange(Range(start: startIndex, end: endIndex))
array.append(substr)
currentIndex += len
}
return array
}
}
"123456789".split(2)
//output: ["12", "34", "56", "78", "9"]
I have write one method in objective c as below,
-(NSMutableArray*)splitString : (NSString*)str withRange : (int)range{
NSMutableArray *arr = [[NSMutableArray alloc]init];
NSMutableString *mutableStr = [[NSMutableString alloc]initWithString:str];
int j = 0;
int counter = 0;
for (int i = 0; i < str.length; i++) {
j++;
if (range == j) {
j = 0;
if (!(i == str.length - 1)) {
[mutableStr insertString:#"$" atIndex:i+1+counter];
}
counter++;
}
}
arr = (NSMutableArray*)[mutableStr componentsSeparatedByString:#"$"];
NSLog(#"%#",arr);
return arr;
}
You can call this method like,
[self splitString:#"123456" withRange:2];
and result will be,
(
12,
34,
56
)
You can also try below code:
var arrStr: [Substring] = []
let str = "1234567"
var i = 0
while i < str.count - 1 {
let index = str.index(str.startIndex, offsetBy: i)
//Below line gets current index and advances by 2
let substring = str[index..<str.index(index, offsetBy: 2)]
arrStr.append(substring)
i += 2
}
if str.count % 2 == 1 {
arrStr.append(str.suffix(1))
}
print(arrStr)
There's a stupid way, you can think about the rules of the data model.
var strOld = "123456"
print("The original string:\(strOld)")
strOld.insert("、", at: strOld.index(before: strOld.index(strOld.startIndex, offsetBy: 3)))
strOld.insert("、", at: strOld.index(before: strOld.index(strOld.startIndex, offsetBy: 6)))
print("After inserting:\(strOld)")
let str = strOld
let splitedArray = str.components(separatedBy: "、")
print("After the split of the array:\(splitedArray)")
let splitedArrayOther = str.split{$0 == "、"}.map(String.init)
print("After break up the array (method 2):\(splitedArrayOther)")
The results:
The original string:123456
After inserting:12、34、56
After the split of the array:["12", "34", "56"]
After break up the array (method 2):["12", "34", "56"]
Here's a short (and clean) solution, thanks to recursion:
extension Collection {
func chunks(ofSize size: Int) -> [SubSequence] {
// replace this by `guard count >= size else { return [] }`
// if you want to omit incomplete chunks
guard !isEmpty else { return [] }
return [prefix(size)] + dropFirst(size).chunks(ofSize: size)
}
}
The recursion should not pose a performance problem, as Swift has support for tail call optimization.
Also if Swift arrays are really fast when it comes to prepending or appending elements (like the Objective-C ones are), then the array operations should be fast.
Thus you get both fast and readable code (assuming my array assumptions are true).

How to make a number not repeat itself more than 2 times?

everyone ! Lets say we have
let random = arc4random_uniform(6)
how do i make it not repeat the same number more then two times ? I tried doing it like this :
let previousNumber = Int()
let lastNumber = Int ()
let random = Int(arc4random_uniform(6))
if random == previousNumber {
lastNumber = previousNumber
} else {
previousNumber = random
}
if random == lastNumber {
random = Int(arc4random_uniform(6))
}
But it didn't work. I am new to swift and i didn't find a topic about this on the new swift 3 code. Thank you !
First of all lets build a class to save the recent history of the selected values
class History {
private let size: Int
private var values = [Int]()
init(size:Int) {
self.size = size
}
func add(value: Int) {
values.insert(value, at: 0)
if values.count > size {
values.removeLast()
}
}
var repeatedValueOnFullHistory: Int? {
guard Set(values).count <= 1 else { return nil }
return values.first
}
}
Next let build a Randomizer
class Randomizer {
private var allValues = [Int]()
private var history: History
init?(maxValue: Int) {
guard maxValue > 0 else { return nil }
self.allValues = Array(0...maxValue)
self.history = History(size: maxValue + 1)
}
var next: Int {
let excludedValue = history.repeatedValueOnFullHistory
let allowedValues = allValues.filter { excludedValue != $0 }
let randomIndex = Int(arc4random_uniform(UInt32(allowedValues.count)))
let nextValue = allowedValues[randomIndex]
history.add(value: nextValue)
return nextValue
}
}
And finally let test it
if let r = Randomizer(maxValue: 6) {
r.next // 6
r.next // 2
r.next // 1
r.next // 4
r.next // 6
r.next // 4
r.next // 1
}

Ignore a letter in swift which starts with a Lower Case

Here's what I am trying to do :
let courseName = "Bachelor of Tourism Administration(B.T.A)".condensedWhitespace
let upperCaseCourseName = courseName.uppercaseString
let extrctCourseName = upperCaseCourseName.componentsSeparatedByString(" ").reduce("") { $0.0 + String($0.1.characters.first!) }
let upperCasecourseFirstCharcters = extrctCourseName
print(upperCasecourseFirstCharcters) // output : "BOTA" but i want "BTA"
as you see that my outPut of "Bachelor of Tourism Administration(B.T.A)" is BOTA but the desired output is BTA because word of is starting from a lowerCase and i want to ignore that word in my this method , how am gonna do that any idea ?
let courseName = "Bachelor of Tourism Administration(B.T.A)" //.condensedWhitespace
var newString = ""
let array : NSArray = courseName.componentsSeparatedByString(" ")
for chr in array {
let str = chr as! NSString
if str.lowercaseString != str{
if newString.characters.count > 0{
newString = newString.stringByAppendingString(" "+(str as String))
continue
}
newString = newString.stringByAppendingString((str as String))
}
}
let upperCaseCourseName = newString.uppercaseString
let extrctCourseName = upperCaseCourseName.componentsSeparatedByString(" ").reduce("") { $0.0 + String($0.1.characters.first!) }
let upperCasecourseFirstCharcters = extrctCourseName
print(upperCasecourseFirstCharcters)
//This will defiantly meet to your problem/. Let me know if it works for u or not
You can paste this into a playground:
extension String {
func array() -> [String] {
return self.componentsSeparatedByString(" ")
}
func abbreviate() -> String {
var output = ""
let array = self.array()
for word in array {
let index = word.startIndex.advancedBy(0)
let str = String(word[index])
if str.lowercaseString != str {
output += str
}
}
return output
}
}
let courseName = "Bachelor of Tourism Administration(B.T.A)".abbreviate()
print(courseName) // prints BTA
A clean approach would be:
extension Character
{
public func isUpper() -> Bool
{
let characterString = String(self)
return (characterString == characterString.uppercaseString) && (characterString != characterString.lowercaseString)
}
}
let courseName = "Bachelor of Tourism Administration(B.T.A)"
let upperCaseCourseName = courseName
let extrctCourseName = upperCaseCourseName.componentsSeparatedByString(" ").reduce("") {
if($0.1.characters.first!.isUpper()) {
return $0.0 + String($0.1.characters.first!)
}else {
return $0.0
}
}

How to make a "for" loop on the condition of a number interval Xcode Swift2

Hey I'm trying to figure out how to tally up soccer goals on the condition that the goal was scored in under 45 minutes, but the func has some slight errors with swift 2. Any help? Thanks!
Code:
var barcelonavsRealMadrid1goals : [String : Int] = ["barcelonaGoal1":21,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
func Run() {
var goalCount=0
for (goal,numbers) in barcelonavsRealMadrid1goals{
for(var number in numbers) {
if(number < 45)
goalCount++
}
}
You have an extra for..in loop in there that's not needed:
for(var number in numbers) {
It also has an extraneous ( and ) around it
for var number in numbers {
Here is a working version of your code:
var barcelonavsRealMadrid1goals = ["barcelonaGoal1":21,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
func run() -> Int { // functions should start with lower case
var goalCount=0
for (_,numbers) in barcelonavsRealMadrid1goals where numbers < 45 {
goalCount++
}
return goalCount
}
let goalCount = run()
And the functional way would be something like:
let goalCount = goals.reduce(0) {
if $0.1.1 < 45 {
return $0.0 + 1
}
return $0.0
}
With explanation:
var goals = [
"barcelonaGoal1" :21,
"RealMadridGoal2":23,
"barcelonaGoal3" :24,
"RealMadridGoal4":27,
"RealMadridGoal5":45]
// For our use reduce takes an initial value of Int
// and a combine function of type
// (Int, (String, Int)) -> Int
//
// Reduce will call the closure once with
// each value in the map and the previous return value
let goalCount = goals.reduce(0, combine: {
(initial:Int, current:(key:String, value:Int)) -> Int in
var currentCount = initial
// print to show input and output of closure
print( "parameters:(\(initial), (\"\(current.key)\", \(current.value)))", terminator:", ")
defer {
print("return:\(currentCount)")
}
// end printing
if current.value < 45 {
++currentCount // add 1 to the running total
return currentCount
}
return currentCount
})
// console output:
// parameters:(0, ("barcelonaGoal1", 21)), return:1
// parameters:(1, ("RealMadridGoal4", 27)), return:2
// parameters:(2, ("RealMadridGoal5", 45)), return:2
// parameters:(2, ("RealMadridGoal2", 23)), return:3
// parameters:(3, ("barcelonaGoal3", 24)), return:4
For solving of you're problem try to use functional programing that is introduced in swift :
var barcelonavsRealMadrid1goals : [String : Int] = ["barcelonaGoal1":95,"RealMadridGoal2":23,"barcelonaGoal3":24,"RealMadridGoal4":27]
var filtered = barcelonavsRealMadrid1goals.filter { (team:String, minute:Int) -> Bool in
var state = false
if (minute > 45)
{
return true
}
return state
}
let totalCount = filtered.count
Try this method.
func Run() {
var goalCount=0
for (_, score) in barcelonavsRealMadrid1goals {
if(score < 45) {
goalCount++
}
}
print(goalCount)
}

Resources