✍️ Note

Some codes are sourced from Loony Corn’s Udemy Course (https://www.udemy.com/user/janani-ravi-2/). This post is for personal notes where I summarize the original contents to grasp the key concepts

General Programming Problems

Often coding interviews involve problems which do not have complicated algorithms or data structures – These are straight programming problems

They test your ability to work through details and get the edge cases right

The bad thing about them is that they involve lots of cases which you need to work through – They tend to be frustrating

The great thing about them is that if you are organised and systematic in your thought process it is reasonably straightforward to get them right

These are problems you should nail. All they need is practice

None of them require any detailed knowledge of standard algorithms

We’ll solve 8 general programming problems here – They all use arrays or simple data structures which you create

https://www.udemy.com/course/break-away-coding-interviews-1/learn/lecture/8462914#overview

Example 1. Check whether a given string is a palindrome

Palindromes are strings which read the same when read forwards or backwards

You can reverse all the letters in a palindrome and get the original string

Examples of palindromes are

  • MADAM, REFER, LONELY TYLENOL

Note

  • the string can have spaces, ignore spaces in the palindrome check, the spaces can all be collapsed
  • The check is Case-Insenstive
public func isPalindrome(_ input: String) -> Bool {
    var firstIndex = 0
    var lastIndex = input.count - 1
    let lowerCasedInput = Array(input.lowercased())
    print(lowerCasedInput)
    while firstIndex < lastIndex {
        var first: Character? = lowerCasedInput[firstIndex]
        var last: Character? = lowerCasedInput[lastIndex]
        
        while lowerCasedInput[firstIndex] == " " {
            firstIndex += 1
            first = lowerCasedInput[firstIndex]
        }
        
        while lowerCasedInput[lastIndex] == " " {
            lastIndex -= 1
            last = lowerCasedInput[lastIndex]
        }
        
        print("First char: \(first) Last char: \(last)")
        if first != last {
            return false
        }
        firstIndex += 1
        lastIndex -= 1
        
        print("First index: \(firstIndex)")
        print("Last index: \(lastIndex)")
    }
    return true
}

isPalindrome("MaIay a Ia m") //True
isPalindrome("MADAM") //True
isPalindrome("REFER") //True
isPalindrome("LONELY TYLENOL") //True
isPalindrome("LONELY TYLENOLF") //False

Example 2. Find all points within a certain distance of another point

Find points (Given X, Y coordinates) which are within a certain distance of another point. The distance and the central point is specified as an argument to the function which computes the points in range

Example. All points within a distance 10 of (0,0) will include the point at (3, 4) but not include the point at (12, 13)

Hint: If you are using an OO Programming language set up an entity which represents a point and contains methods within it to find the distance from another point.

public struct Point {
    public let x: Double
    public let y: Double
    
    public init(x: Double, y: Double) {
        self.x = x
        self.y = y
    }
}

extension Point {
    public func getDistance(_ otherPoint: Point) -> Double {
        //Distance: sqrt(x^2 + y^2)
        return sqrt(pow(otherPoint.x - x, 2) + pow(otherPoint.y - y, 2))
    }
    
    public func isWithinDistance(_ otherPoint: Point, distance: Double) -> Bool {
        let distanceX = abs(x - otherPoint.x)
        let distanceY = abs(y - otherPoint.y)
        if distanceX > distance || distanceY > distance {
            return false
        }
        return getDistance(otherPoint) <= distance
    }
}

public func getPointsWithinDistance(points: [Point], center: Point, distance: Double) -> [Point] {
    var withinPoints = [Point]()
    for point in points {
        if point.isWithinDistance(center, distance: distance) {
            withinPoints.append(point)
        }
    }
    print("Points within \(distance) of point x: \(center.x) y: \(center.y)")
    for p in withinPoints {
        print("Point: x: \(p.x) y: \(p.y)")
    }
    return withinPoints
}

Example 3. Game of Life: Get the next generation of cell states

A cell is a block in a matrix surrounded by neighbours. A cell can be in two states, alive or dead. A cell can change its state from one generation to another under certain circumstances

Rule

  • A live cell with fewer than 2 live neighbours dies of loneliness
  • A dead cell with exactly 2 live neighbours comes alive
  • A live cell with greater than 2 live neighbours dies due to overcrowding

Given a current generation of cells in a matrix, what does the next generation look like? Which cells are alive and which are dead? Write code to get the next generation of cells given the current generation

Hint

  • Represent each generation as rows and columns in a 2D matrix. Live and Dead states can be represented by integers or boolean states
func printMatrix(_ input: [[Int]]) {
    for row in 0..<input.count {
        print("|", terminator: "")
        for col in 0..<input[0].count {
            print("\(input[row][col])", terminator: "|")
        }
        print("\n")
    }
}
public func getNextGeneration(currentGeneration: [[Int]]) -> [[Int]] {
    var nextGeneration = currentGeneration
    let rowCount = currentGeneration.count
    let colCount = currentGeneration[0].count
    for row in 0..<rowCount {
        for col in 0..<colCount {
            let nextState = getNextState(
                currentGeneration: currentGeneration,
                row: row,
                col: col
            )!
            nextGeneration[row][col] = nextState
        }
    }
    return nextGeneration
}

//0: Dead, 1: Alive
public func getNextState(currentGeneration: [[Int]], row: Int, col: Int) -> Int? {
    //Edge case
    if currentGeneration.isEmpty {
        return nil
    }
    if row > currentGeneration.count {
        return nil
    }
    if col > currentGeneration[0].count {
        return nil
    }
    var states = [Int: Int]()
    let currentState = currentGeneration[row][col]
    let rowCount = currentGeneration.count
    let colCount = currentGeneration[0].count
    //Check 8 directions
    if col - 1 >= 0 {
        if let value = states[currentGeneration[row][col - 1]]{
            states[currentGeneration[row][col - 1]] = value + 1
        }
        else {
            states[currentGeneration[row][col - 1]] = 1
        }
    }
    if col - 1 >= 0, row - 1 >= 0 {
        if let value = states[currentGeneration[row - 1][col - 1]]{
            states[currentGeneration[row - 1][col - 1]] = value + 1
        }
        else {
            states[currentGeneration[row - 1][col - 1]] = 1
        }
    }
    if col - 1 >= 0, row + 1 < rowCount {
        if let value = states[currentGeneration[row + 1][col - 1]]{
            states[currentGeneration[row + 1][col - 1]] = value + 1
        }
        else {
            states[currentGeneration[row + 1][col - 1]] = 1
        }
    }
    if col + 1 < colCount {
        if let value = states[currentGeneration[row][col + 1]]{
            states[currentGeneration[row][col + 1]] = value + 1
        }
        else {
            states[currentGeneration[row][col + 1]] = 1
        }
    }
    if col + 1 < colCount, row - 1 >= 0 {
        if let value = states[currentGeneration[row - 1][col + 1]]{
            states[currentGeneration[row - 1][col + 1]] = value + 1
        }
        else {
            states[currentGeneration[row - 1][col + 1]] = 1
        }
    }
    if col + 1 < colCount, row + 1 < rowCount {
        if let value = states[currentGeneration[row + 1][col + 1]]{
            states[currentGeneration[row + 1][col + 1]] = value + 1
        }
        else {
            states[currentGeneration[row + 1][col + 1]] = 1
        }
    }
    if row + 1 < rowCount {
        if let value = states[currentGeneration[row + 1][col]]{
            states[currentGeneration[row + 1][col]] = value + 1
        }
        else {
            states[currentGeneration[row + 1][col]] = 1
        }
    }
    if row - 1 >= 0 {
        if let value = states[currentGeneration[row - 1][col]]{
            states[currentGeneration[row - 1][col]] = value + 1
        }
        else {
            states[currentGeneration[row - 1][col]] = 1
        }
    }
    
    if currentState == 0 {
        //A dead cell with exactly 2 live neighbours comes alive
        let livedCount = states[1] ?? 0
        return livedCount == 2 ? 1 : 0
    }
    else {
        let livedCount = states[1] ?? 0
        //A live cell with fewer than 2 live neighbours dies of loneliness
        //A live cell with greater than 2 live neighbours dies due to overcrowding
        if livedCount < 2 || livedCount >= 2 {
            return 0
        }
        return currentState
    }
}

Example 4. Break A document into chunks

A document is stored in the cloud and you need to send the text of the document to the client which renders it on the screen (Think Google docs)

You do not want to send the entire document to the client at one go, you want to send it chunk by chunk. A chunk can be created subject to certain constraints

Rule

  • A chunk can be 5000 or fewer characters in length (This rule is relaxed only under one condition see below)
  • A chunk should contain only complete paragraphs – This is a hard and fast rule
  • A paragraph is represented by the ‘:’ Character in the document
  • List of chunks should be in the order in which they appear in the document (Do not set them up out of order)
  • If you encounter a paragraph > 5000 characters that should be in a separate chunk by itself
  • Get all chunks as close to 5000 characters as possible, subject to the constraints above

Given a string document return a list of chunks which some other system can use to send to the client

Hint: public func chunkify(doc: String) -> [String]

public func chunkify(doc: String, chunkSize: Int) -> [String] {
    guard !doc.isEmpty else {
        return []
    }
    var chunks = [String]()
    let paragraphs = doc.split(separator: ":")
    var start = 0
    let total = paragraphs.count
    
    while start < total {
        var chunk = paragraphs[start] + ":"
        if chunk.count <= chunkSize {
            var next = start + 1
            while next < total, paragraphs[next].count + 1 <= chunkSize - chunk.count {
                chunk += (paragraphs[next] + ":")
                next += 1
            }
            chunks.append(String(chunk))
            start = next
        }
        else {
            chunks.append(String(chunk))
            start += 1
        }
    }
    return chunks
}

Example 5. Run Length Encoding and Decoding

Write code which encodes a string using Run-Length encoding and decodes a string encoded using Run-Length encoding

Example

  • ABBCCC -> 1A2B3C
  • AABBBCCCC -> 2A3B4C
  • 1D2E1F -> DEEF

Constraints

Assume only letters are present in the string to be encode, no numbers

Remember to handle the case where we can have > 9 of the same characters in a row

Run-Length Encoding Code

public func runLengthEncoding(_ input: String) -> String {
    var result = ""
    var start = 0
    let arrayInput = Array(input)
    while start < arrayInput.count {
        var count = 1
        let currentCharacter = arrayInput[start]
        var next = start + 1
        while next < arrayInput.count, arrayInput[next] == currentCharacter {
            count += 1
            next += 1
        }
        result += "\(count)\(currentCharacter)"
        start = next
    }
    return result
}

Run-Length Decoding Code

public func runLengthDecoding(_ input: String) -> String {
    var result = ""
    var start = 0
    let arrayInput = Array(input)
    
    //Assumed that first character start with number
    while start < arrayInput.count {
        //Step 1. Get number
        var numberStr = String(arrayInput[start])
        //Edge case. Larger than 9
        var next = start + 1
        while next < arrayInput.count, Int(String(arrayInput[next])) != nil {
            numberStr += String(arrayInput[next])
            print(numberStr)
            next += 1
        }
        let repeatedCount = Int(numberStr) ?? 1
        
        //Step 2. Generate repeated characters
        result += String(repeating: arrayInput[next], count: repeatedCount)
        
        //Step 3. Important! Pointing to next number
        start = next + 1
    }
    return result
}

Example 6. Add two numbers represented by their digits

Given two numbers where the individual digits in the numbers are in an array or a list add them to get the final result in the same list or array form

Example using Arrays: [1, 2] represents the number 12. Note that the most significant digit in the 0th index of the array, with the least significant digit at the last position

Adding [1, 2] and [2, 3] should give the result [3, 5]

Requirements

  • Don’t convert the number format to a real number to add them. Add them digit by digit
  • Remember to consider the carry over per digit if there is one!
public func add(a: [Int], b: [Int]) -> [Int] {
    var result = [Int]()
    let maxLength = max(a.count, b.count)
    var carry = 0
    var currentIndexA = a.count == maxLength ? maxLength - 1 : a.count - 1
    var currentIndexB = b.count == maxLength ? maxLength - 1 : b.count - 1
    
    while currentIndexA >= 0, currentIndexB >= 0 {
        var sum = a[currentIndexA] + b[currentIndexB] + carry
        if sum > 9 {
            carry = sum / 10
            sum = sum % 10
        }
        else {
            carry = 0
        }
        result.insert(sum, at: 0)
        currentIndexA -= 1
        currentIndexB -= 1
    }
    if currentIndexA >= 0 {
        while currentIndexA >= 0 {
            var sum = a[currentIndexA] + carry
            if sum > 9 {
                carry = sum / 10
                sum = sum % 10
            }
            else {
                carry = 0
            }
            result.insert(sum, at: 0)
            currentIndexA -= 1
        }
    }
    
    if currentIndexB >= 0 {
        while currentIndexB >= 0 {
            var sum = a[currentIndexB] + carry
            if sum > 9 {
                carry = sum / 10
                sum = sum % 10
            }
            else {
                carry = 0
            }
            result.insert(sum, at: 0)
            currentIndexB -= 1
        }
    }
    
    
    if carry != 0 {
        result.insert(carry, at: 0)
    }
    
    return result
}

Example 7. Increment number by 1

Suppose that you invent your own numeral system (which is neither decimal, binary nor any of the common ones). You specify the digits and the order of the digits in that numeral system.

Given the digits and the order of digits used in that system and a number, write a function to increment that number by 1 and return the result

Solution 1

public func incrementByOne(input: String) -> String? {
    var result = [String]()
    let numeralSystem = ["A": 0, "B": 1, "C": 2, "D": 3]
    var input = Array(input).compactMap { "\($0)"}
    
    var validCount = 0
    
    for char in input {
        if numeralSystem.keys.contains(char) {
            validCount += 1
        }
    }
    if validCount != input.count {
        return nil
    }
    
    var currentIndex = input.count - 1
    
    var carry = 0
    while currentIndex >= 0 {
        var sum = numeralSystem[input[currentIndex]]! + carry
        if currentIndex == input.count - 1 {
            sum += 1
        }
        if sum > 3 {
            carry = sum / 4
            sum = sum % 4
        }
        else {
            carry = 0
        }
        if let key = numeralSystem.first (where: { $0.value == sum })?.key {
            result.insert(key, at: 0)
        }
        currentIndex -= 1
    }
    
    if carry != 0 {
        if let key = numeralSystem.first (where: { $0.value == carry })?.key {
            result.insert(key, at: 0)
        }
    }
    return result.joined()
}

Solution 2

public func incrementByOne2(input: String) -> String? {
    let numeralSystem = ["A", "B", "C", "D"]
    var input = Array(input).compactMap { "\($0)" }
    
    var validCount = 0
    for char in input {
        if numeralSystem.contains(char) {
            validCount += 1
        }
    }
    if validCount != input.count {
        return nil
    }
    
    var currentIndex = input.count - 1
    var isCompleted = false
    while !isCompleted, currentIndex >= 0 {
        let currentDigit = input[currentIndex]
        let indexOfCurrentDigit = numeralSystem.firstIndex(of: currentDigit)
        
        //Get the next digit on increment, this will wrap around to the first digit which is why we use the modulo operator
        let indexOfNextDigit = (indexOfCurrentDigit! + 1) % numeralSystem.count
        
        //Update digit
        input[currentIndex] = numeralSystem[indexOfNextDigit]
        
        if indexOfNextDigit != 0 {
            isCompleted = true
        }
        
        //If we're at the most significant digit and that wrapped around we add a new digit to the incremented number like going from 9 to 10
        if currentIndex == 0, indexOfNextDigit == 0 {
            input.insert(numeralSystem[0], at: 0)
        }
        currentIndex -= 1
    }
    return input.joined()
}

Example 8. Sudoku

Basic rules

  • Each rows and columns should have one value (1-9) -> Should not have duplicated value
  • Board size is 9×9
  • Block size is 3×3, Total 9 blocks
  • In a Block, Should have one value (1-9) -> Should not have duplicated value

Exercise 1. isValidRowsAndCols

This function is returns boolean. If all the row and column’s values are valid then It returns true. otherwise returns false.

var sudoku: [[Int]] = [
    [8, 0, 0,   4, 0, 6,   0, 0, 7],
    [0, 0, 0,   0, 0, 0,   4, 0, 0],
    [0, 1, 0,   0, 0, 0,   6, 5, 0],
    
    [5, 0, 9,   0, 3, 0,   7, 8, 0],
    [0, 0, 0,   0, 7, 0,   0, 0, 0],
    [0, 4, 8,   0, 2, 0,   1, 0, 3],
    
    [0, 5, 2,   0, 0, 0,   0, 0, 0],
    [0, 0, 1,   0, 0, 0,   0, 0, 0],
    [3, 0, 0,   9, 0, 2,   0, 0, 5]
]
//Helper
func printBoard(_ input: [[Int]]) {
    for row in 0..<9 {
        print("|", terminator: "")
        for col in 0..<9 {
            print("\(input[row][col])", terminator: "|")
        }
        print("\n")
    }
}

func isValidRowsAndCols(_ board: [[Int]]) -> Bool {
    var rowSet: [Int: Set<Int>] = [:]
    var colSet: [Int: Set<Int>] = [:]
    
    //Index starts from 0 to 8
    for i in 0...8 {
        rowSet[i] = Set()
        colSet[i] = Set()
    }
    
    for row in 0...8 {
        for col in 0...8 {
            var cellValue = board[row][col]
            //No value has assigned
            if cellValue == 0 {
                continue
            }
            
            if cellValue < 0 || cellValue > 9 {
                return false
            }
            //cellValue already seen
            if rowSet[row]?.contains(cellValue) == true {
                print("💥 Invalid: \(row):\(col) -> value: \(cellValue)")
                return false
            }
            if colSet[col]?.contains(cellValue) == true {
                print("💥 Invalid: \(row):\(col) -> value: \(cellValue)")
                return false
            }
            
            //Add current cell value to the row or column set
            rowSet[row]?.insert(cellValue)
            colSet[col]?.insert(cellValue)
        }
    }
    return true
}

isValidRowsAndCols(sudoku) //It returns true

Exercise 2. IsValidBlock -> Bool

Each block should have values between 1-9. And each cell should not have a duplicate value in a block.

func isValidBlock(_ board: [[Int]]) -> Bool {
    //Set associated with every block
    var blockSet: [Int: Set<Int>] = [:]
    for i in 0..<9 {
        blockSet[i] = Set()
    }
    
    //Row block is 3
    for rowBlock in 0...2 {
        for colBlock in 0...2 {
            //Check 3x3 Block Cell
            for miniRow in 0...2 {
                for miniCol in 0...2 {
                    let row = rowBlock * 3 + miniRow
                    let col = colBlock * 3 + miniCol
                    let cellValue = sudoku[row][col]
                    
                    if cellValue == 0 {
                        continue
                    }
                    if cellValue < 0 || cellValue > 9 {
                        return false
                    }
                    /* Total 9 block
                     row0: 0  1  2
                     row1: 3  4  5
                     row2: 6  7  8
                     */
                    let blockNumber = rowBlock * 3 + colBlock
                    
                    if blockSet[blockNumber]?.contains(cellValue) == true {
                        return false
                    }
                    blockSet[blockNumber]?.insert(cellValue)
                }
            }
        }
    }
    return true
}
isValidBlock(sudoku) // It returns true

Exercise 3. isValidSudoku -> Bool

This function checks all the cells in board and checks the sudoku rule.

func isValid(_ board: [[Int]]) -> Bool {
    if !isValidRowsAndCols(board) {
        return false
    }
    if !isValidBlock(board) {
        return false
    }
    return true
}

It is very simple. It calls two functions we made. If all the cell’s value are valid then return true.

Exercise 4. solveSudoku

This function fill the cell’s value and returns solution.

https://www.sudokuonline.io

As you can see when you select a cell (yellow), You need to check blue areas.

Step 1. Create a Sudoku Board

Generate Sudoku Board

func generateSudoku(board: inout [[Int]]) {
    //Has a 9 mini blocks. diagonal direction
    //3 means jumping to next mini block, It loops 3 blocks and fill the numbers
    for i in stride(from: 0, through: 8, by: 3) {
        var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9].shuffled()
        for miniRow in 0...2 {
            for miniCol in 0...2 {
                board[miniRow][miniCol] = numbers.removeFirst()
            }
        }
    }
    
    
    //Step 2. solve function to fill the all numbers
    _ = solve(board: &board)
    
    var numberOfEmptyCell = 50
    
    while numberOfEmptyCell > 0 {
        var random = [0, 1, 2, 3, 4, 5, 6, 7, 8].shuffled()
    
        board[random.first!][random.last!] = 0
        numberOfEmptyCell -= 1
    }
    //TODO: Step 3. set empty cells It depends on difficulty
}

Helper functions

import Foundation
//https://github.com/ShawnBaek/Table
import Table

//Check If Sudoku board has empty cell or not
func isFilledAllNumbers(board: [[Int]]) -> Bool {
    var numberOfEmptyCell = 0
    for row in 0...8 {
        for col in 0...8 {
            if board[row][col] == 0 {
                numberOfEmptyCell += 1
            }
        }
    }
    return numberOfEmptyCell == 0
}

//Get emptyCell's position
func emptyCell(board: [[Int]]) -> (row: Int, col: Int)? {
    for row in 0...8 {
        for col in 0...8 {
            //Empty cell found
            if board[row][col] == 0 {
                return (row: row, col: col)
            }
        }
    }
    return nil
}

func canPlace(_ number: Int, row: Int, col: Int, board: [[Int]]) -> Bool {
    //Sudoku rule
    
    //Rule 1. Check unique number in a row
    for r in 0...8 {
        if board[r][col] == number {
            return false
        }
    }
    
    //Rule 2. Check unique number in a col
    for c in 0...8 {
        if board[row][c] == number {
            return false
        }
    }
    
    //Rule 3. Check unique number in a mini block -> total 9
    //each block's start position will be 0,0  3,3, 6,6, and so on
    
    //If row is between 3-5, 3...5 / 3 = 1, 1 * 3 = 3
    let miniBlockStartRow = (row / 3) * 3
    let miniBlockStartCol = (col / 3) * 3
    
    for miniRow in 0...2 {
        for miniCol in 0...2 {
            let boardRow = miniBlockStartRow + miniRow
            let boardCol = miniBlockStartCol + miniCol
            if board[boardRow][boardCol] == number {
                return false
            }
        }
    }
    return true
}

Sudoku Board solve function

  • Step 1. Check isFilledAllNumber or not.
    • It assumed that generated board is a valid sudoku board. All we need to do is fill the correct number on empty cell
  • Step 2. Recursively calling a function – Get empty cell and fill the correct number
//It is a recursive function
func solve(board: inout [[Int]]) -> Bool {
    //Base case
    //If this board filled all numbers? -> yes then return true
    //func isFilledAllNumbers -> Bool
    //Game done
    if isFilledAllNumbers(board: board) {
        return true
    }
    
    //Step 1. Get the emptyCell and finding a number to place
    //one more function to get emptyCell
    if let emptyCellPosition = emptyCell(board: board) {
        //Can place 1-9 numbers
        for number in 1...9 {
            //Check can place a number at this position
            if canPlace(number, row: emptyCellPosition.row, col: emptyCellPosition.col, board: board) {
                //Place a number
                board[emptyCellPosition.row][emptyCellPosition.col] = number
                //Recursive Case
                if solve(board: &board) {
                    return true
                }
                //Reset to emptyCell
                board[emptyCellPosition.row][emptyCellPosition.col] = 0
            }
        }
    }
    return false
}

Check Validation

func isValidRowsAndCols(_ board: [[Int]]) -> Bool {
    var rowSet: [Int: Set<Int>] = [:]
    var colSet: [Int: Set<Int>] = [:]
    
    //Index starts from 0 to 8
    for i in 0...8 {
        rowSet[i] = Set()
        colSet[i] = Set()
    }
    
    for row in 0...8 {
        for col in 0...8 {
            let cellValue = board[row][col]
            //No value has assigned
            if cellValue == 0 {
                continue
            }
            
            if cellValue < 0 || cellValue > 9 {
                return false
            }
            //cellValue already seen
            if rowSet[row]?.contains(cellValue) == true {
                return false
            }
            if colSet[col]?.contains(cellValue) == true {
                return false
            }
            
            //Add current cell value to the row or column set
            rowSet[row]?.insert(cellValue)
            colSet[col]?.insert(cellValue)
        }
    }
    return true
}



func isValidBlock(_ board: [[Int]]) -> Bool {
    //Set associated with every block
    var blockSet: [Int: Set<Int>] = [:]
    for i in 0..<9 {
        blockSet[i] = Set()
    }
    
    var test = 0
    //Row block is 3
    for rowBlock in 0...2 {
        for colBlock in 0...2 {
            print("Start Block: \(test)")
            //Check 3x3 Block Cell
            for miniRow in 0...2 {
                for miniCol in 0...2 {
                    let row = rowBlock * 3 + miniRow
                    let col = colBlock * 3 + miniCol
                    let cellValue = board[row][col]
                    
                    if cellValue == 0 {
                        continue
                    }
                    if cellValue < 0 || cellValue > 9 {
                        return false
                    }
                    /* Total 9 block
                     row0: 0  1  2
                     row1: 3  4  5
                     row2: 6  7  8
                     */
                    let blockNumber = rowBlock * 3 + colBlock
                    
                    if blockSet[blockNumber]?.contains(cellValue) == true {
                        return false
                    }
                    blockSet[blockNumber]?.insert(cellValue)
                }
            }
            
            test += 1
            
        }
        
    }
    return true
}

func isValid(_ board: [[Int]]) -> Bool {
    if !isValidRowsAndCols(board) {
        return false
    }
    if !isValidBlock(board) {
        return false
    }
    return true
}

Leave a comment

Quote of the week

"People ask me what I do in the winter when there's no baseball. I'll tell you what I do. I stare out the window and wait for spring."

~ Rogers Hornsby