Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review

栏目: Swift · 发布时间: 6年前

内容简介:讨论区里面,有各种具有启发性的代码。(换句话说,就是有很强的代码。看了,觉得脑洞大开,大神们把语言的语法特性发挥到了极致)里面有各种常见语言的实现

讨论区里面,有各种具有启发性的代码。

(换句话说,就是有很强的代码。看了,觉得脑洞大开,大神们把语言的语法特性发挥到了极致)

里面有各种常见语言的实现

( 这里指 Leetcode 主站的, 中文站点的同一功能弱了一点 )

进入 Leetcode 的题目,

Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review

进入讨论区,里面的讨论挺多的,这道题就有 470 个帖子。

本文推荐选择 "Most Votes",

事实就是得分高的代码,看起来爽

Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review

也可以搜索一下自己关心的, 一般是按语言来搜索。

Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review

就 Leetcode 算法题,本文认为有了 Leetcode 的讨论区,和官方题解 (有些没有,最近的题都有)

其他的资料...... ,都好像有些弱 (不喜欢英语的少年,除外)

题目描述: 36. 有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。

Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review

上图是一个部分填充的有效的数独。

数独部分空格内已填入了数字,空白格用 '.' 表示。 示例 :

输入:

Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review

输出: true

题解 ( 改进前):

下面的解法,非常直观, 根据数独的成立条件,分三次检查数字,按行,按列,按块

(先横着来,再竖着来,最后一块一块来)

因为数独有数字的唯一性,这里使用散列集合

每一次处理,通过的情况分两种,

扫描一轮,1-9 刚刚好。或者含有 ''.", 其他的数字各不相同。

class Solution {
    func isValidSudoku(_ board: [[Character]]) -> Bool {
        let count = board.count
        var set = Set<Character>()
        for i in 0..<count{
            //  横着来,按行,检查数字
            set = Set(board[i])
            var num = board[i].reduce(0 , {(result : Int, char : Character)
                in
                var cent = 0
                if String(char) == "."{
                    cent = 1
                }
                return result + cent
            })

            //   每一次处理,通过本次循环的情况分两种,
            //  扫描一轮,1-9 刚刚好。或者含有 ".", 其他的数字各不相同。
            //  这里做了一个针对处理
            if num > 0 , count - num != set.count - 1{
                return false
            }
            else if num == 0, set.count != count{
                return false
            }
            // 竖着来,按列,检查数字
            set = Set(board.reduce([Character]() , { resultArray, chars in
                return resultArray + [chars[i]]
            }))
            num = board.reduce(0 , {(result : Int, chars : [Character])
                in
                var cent = 0
                if String(chars[i]) == "."{
                    cent = 1
                }
                return result + cent
            })

            if num > 0 , count - num != set.count - 1{
                return false
            }
            else if num == 0, set.count != count{
                return false
            }
            // 一块一块来, 按块,检查数字
            let characters = board.flatMap{
                return $0
            }
          
            let fisrtMiddle = ( i/3 ) * 27 + ( i % 3 ) * 3 + 1
            let secondMiddle = fisrtMiddle + 9
            let thirdMiddle = fisrtMiddle + 18
            // 找出每一块
            let arrayThree = [characters[fisrtMiddle - 1], characters[fisrtMiddle], characters[fisrtMiddle + 1],
                            characters[secondMiddle - 1], characters[secondMiddle], characters[secondMiddle + 1],
                           characters[thirdMiddle - 1], characters[thirdMiddle], characters[thirdMiddle + 1]]
            set = Set(arrayThree)
            num = arrayThree.reduce(0 , {(result : Int, char : Character)
                in
                var cent = 0
                if String(char) == "."{
                    cent = 1
                }
                return result + cent
            })

            if num > 0 , count - num != set.count - 1{
                return false
            }
            else if num == 0, set.count != count{
                return false
            }
        }

        return true
    }
}

复制代码

Code Review :

算法上的提高

没必要计算 "." 的个数。先处理数据,把 "." 过滤掉, 再创建散列集合。

按行,按列,按块查找重复数字,就直观了很多。不需要考虑 "." 的干扰。

命名要规范,

怎么知道 set 里面包含什么?

不清晰, 不知道 num 是记录的是什么的数量。

centarrayThree 是什么鬼?

改进代码

if String(char) == "." , 可以直接写成 if char == ".”

Swift 中 "." 是字符串的字面量,也是字符的字面量。不需要把字符转化为字符串。

改进闭包

按行,计算一次循环,不包含 "." 的

var num = board[i].reduce(0 , {(result : Int, char : Character)
    in
    var cent = 0
    if String(char) == "."{
        cent = 1
    }
    return result + cent
})
复制代码

1⃣️ 简写闭包,用三目,减少临时变量

var num = board[i].reduce(0 , {(result, char) in
    char == "." ? result + 1 : result
})
复制代码

这样处理更高效

先把数据处理干净,过滤 "."

let rowDigits = board[i].filter { $0 != "." }
if rowDigits.count != Set(rowDigits).count {
       return false
 }
复制代码
set = Set(board.reduce([Character]() , { resultArray, chars in
    return resultArray + [chars[i]]
}))
复制代码

2⃣️ 科学类型转换

let column = board.map { $0[i]} // Column #i
set = Set(column)
复制代码

找出每一块

let fisrtMiddle = ( i/3 ) * 27 + ( i % 3 ) * 3 + 1
            let secondMiddle = fisrtMiddle + 9
            let thirdMiddle = fisrtMiddle + 18
            // 找出每一块
            let arrayThree = [characters[fisrtMiddle - 1], characters[fisrtMiddle], characters[fisrtMiddle + 1],
                            characters[secondMiddle - 1], characters[secondMiddle], characters[secondMiddle + 1],
                            characters[thirdMiddle - 1], characters[thirdMiddle], characters[thirdMiddle + 1]]

复制代码

3⃣️ 使用数组片段 ( slice ), 发挥高阶函数的威力

let firstRow = 3 * (i / 3)
let firstCol = 3 * (i % 3)
let block = board[firstRow..<firstRow+3].flatMap { $0[firstCol..<firstCol+3]}

复制代码

最后的代码:

class Solution {
    func isValidSudoku(_ board: [[Character]]) -> Bool {

        for i in 0..<9 {
            // 按行,检查数字
            let rowDigits = board[i].filter { $0 != "." }
            if rowDigits.count != Set(rowDigits).count {
                return false
            }

            // 按列,检查数字
            let colDigits = board.map { $0[i] }.filter { $0 != "." }
            if colDigits.count != Set(colDigits).count {
                return false
            }

            // 按块,检查数字
            let firstRow = 3 * (i / 3)
            let firstCol = 3 * (i % 3)
            let blockDigits = board[firstRow..<firstRow+3].flatMap { $0[firstCol..<firstCol+3]}
                .filter { $0 != "." }
            if blockDigits.count != Set(blockDigits).count {
                return false
            }       
        }

        return true
    }
}
复制代码

另一种解法, 更加的函数式,性能差一些

使用 27 的散列集合, 对应 9 次循环 X 3 种方式 ( 按行, 按块,按列)

排除掉 "." , 有重复的数字,就返回错误。

两层遍历顺利完成后,返回成功。

class Solution {
    func isValidSudoku(_ board: [[Character]]) -> Bool {
        var rowSets = Array(repeating: Set<Character>(), count: 9)
        var colSets = Array(repeating: Set<Character>(), count: 9)
        var blockSets = Array(repeating: Set<Character>(), count: 9)

        for (i, row) in board.enumerated() {
            for (j, char) in row.enumerated() where char != "." {
                if !rowSets[i].insert(char).inserted {
                    return false
                }
                if !colSets[j].insert(char).inserted {
                    return false
                }
                let block = (i / 3) + 3 * (j / 3)
                if !blockSets[block].insert(char).inserted {
                    return false
                }
            }
        }

        return true
    }
}

复制代码

Leetcode 链接:valid-sudoku

感谢Martin R 大神code review 我的代码

相关代码: github.com/BoxDengJZ/l…

强大的代码:Python 实现


以上所述就是小编给大家介绍的《Leetcode 的强大之处  算法题解 in Swift ( 有效的数独 , 36 ) 及其 Code Review》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Host Your Web Site In The Cloud

Host Your Web Site In The Cloud

Jeff Barr / SitePoint / 2010-9-28 / USD 39.95

Host Your Web Site On The Cloud is the OFFICIAL step-by-step guide to this revolutionary approach to hosting and managing your websites and applications, authored by Amazon's very own Jeffrey Barr. "H......一起来看看 《Host Your Web Site In The Cloud》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具