今天的内容干货满满,还烦请大家仔细观看。首先真是一个值得纪念的日子,历时5个月,终于把《Head First设计模式》这本书给二刷完成了。想起第一次看的时候,也是做了各种目标,竟然没能坚持到最后。
年后回来,下定决心要把书看完,并且输出设计模式系列文章,这次我做到了。今天终于把书看完,实践部分还需要文章输出,估计也就是这几天的事,努力成长吧。
写完今天的算法我就有点后悔,这个难度略大,完全可以用一整篇文章来描述过程,尴尬尴尬。以后我注意下,遇到类似的算法,单独写一个系列出来即可。很多号主,都有专门的力扣刷题系列,看来我也可以加一个这个系列,并把代码共享出来了,我尽快执行起来。
Algorithm LeetCode算法
解数独
(https://leetcode-cn.com/problems/sudoku-solver/
)
题目描述:编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
-
数字 1-9 在每一行只能出现一次。
-
数字 1-9 在每一列只能出现一次。
-
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用‘.’表示
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|
5 | 3 | 7 | ||||||
6 | 1 | 9 | 5 | |||||
9 | 8 | 6 | ||||||
8 | 6 | 3 | ||||||
4 | 8 | 3 | 1 | |||||
7 | 2 | 6 | ||||||
6 | 2 | 8 | ||||||
4 | 1 | 9 | 5 | |||||
8 | 7 | 9 |
注意:
解题思路: 我这里采用直接搜索的方式,写一个辅助函数检查三条规则:
private static boolean isValid(char[][] board, int i, int j, char num) {
// 先判断行,列固定不变,查看是否有冲突
for (int row = 0; row < 9; row++) {
if (board[row][j] == num) {
return false;
}
}
// 再判断列,行固定不变,查看是否有冲突
for (int col = 0; col < 9; col++) {
if (board[i][col] == num) {
return false;
}
}
// 9宫格是否有冲突
for (int row = i / 3 * 3; row < i / 3 * 3 + 3; row++) {
for (int col = j / 3 * 3; col < j / 3 * 3 + 3; col++) {
if (board[row][col] == num) {
return false;
}
}
}
return true;
}
因为是一个九宫格,我们传入的是一个二维数组,一行里面包含9个位置,总共是9行,组成的81个位置。
所以,还需要通过位置依次来填充。从(0,0)到(8,8),如果是".",说明该位置没有被填充,则可以查找数字并填充进去,否则继续查找下一个位置。
如果填充失败,那么我们需要回溯。将原来尝试填充的地方改回来。
递归直到数独被填充完成。
private static boolean searchRes(char[][] board) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (board[i][j] != '.') {
continue;
}
for (char num = '1'; num <= '9'; num++) {//尝试
if (!isValid(board, i, j, num)) {
continue;
}
board[i][j] = num;
boolean result = searchRes(board);
if (result) {
return true;
} else {
board[i][j] = '.';//回退之前的状态,本轮搜索失败,回退的时候也是递归的
}
}
return false;
}
}
return true;
}
好啦,就这样把解数独的问题完成了。可能大家还不知道如何去传入这个二维数组验证,这次我就写下main
函数吧。这里仅给出如何传入二维数组的过程,至于如何打印结果,大家自己积极发挥下噢
public static void main(String[] args) {
char[][] board = new char[][]{
{'5', '3', '.', '.', '7', '.', '.', '.', '.'},
{'6', '.', '.', '1', '9', '5', '.', '.', '.'},
{'.', '9', '8', '.', '.', '.', '.', '6', '.'},
{'8', '.', '.', '.', '6', '.', '.', '.', '3'},
{'4', '.', '.', '8', '.', '3', '.', '.', '1'},
{'7', '.', '.', '.', '2', '.', '.', '.', '6'},
{'.', '6', '.', '.', '.', '.', '2', '8', '.'},
{'.', '.', '.', '4', '1', '9', '.', '.', '5'},
{'.', '.', '.', '.', '8', '.', '.', '7', '9'}
};
searchRes(board);
}
Review 阅读并点评至少一篇英文文章
How to Implement the New In-App Update Feature to Your Android App
(https://medium.com/better-programming/add-in-app-updates-to-your-android-app-in-just-5-lines-of-code-655440abc8e8
)
《如何为Android应用程序实施新的应用程序内更新功能》看到这个标题,其实并没有引起我特别大的关注,但是摘要里面有显示,他能让Android的应用内更新,通过5行代码就能够搞定,还是让我震惊了。
现在,Android的Play核心库有一个应用内更新的功能,它引入了一个新的请求流,以提示活跃用户更新您的应用。但是,这些代码太多了,倘若将所有代码都添加进应用,那将是一个很累人的事情。
但是,这位作者就很有开源和分享的精神,他自己开发了一个应用内更新功能的库,将整个内容减少到5行代码。具体怎么做,文中有描述,这里我就不进行赘述了。
给我的感慨就是,每一位开发者,真的需要有一颗对技术充满狂热的心,这样才能更好地为软件开发做更多的事情,做更多的贡献。还记得Android 6.0权限刚出来的时候,大家都是按部就班地去执行,但是很多人就想到了用封装库的办法,把繁杂的代码简化,提高了很多开发者的工作效率,很多人因此受益。
所以,我们为什么不也去试试看呢。前段时间学习微服务,猿天地的尹吉欢大哥在书中也介绍了自己的一个开源库,用在微服务的配置里,很是好用。他也说了,技术人都需要有一颗开源分享的心,是对自己技术的肯定,也是对社区的贡献。
所以,等着Dimple的读者们的给力表现,我自己也将更加努力。按照上面说的,首先去尝试下力扣上的算法题分享。
Tip 一个技术技巧
昨天,和一位小兄die聊天,聊到Linux的tail命令,这个命令是我平时在运维机器上经常使用的,所以还是有点心得,但苦于没有很好的总结。刚好这次赶上了。
一、tail命令语法
tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]
参数解释:
-f 该参数用于监视File文件增长。
-c Number 从 Number 字节位置读取指定文件
-n Number 从 Number 行位置读取指定文件。
-m Number 从 Number 多字节字符位置读取指定文件,比方你的文件假设包括中文字,假
设指定-c参数,可能导致截断,但使用-m则会避免该问题。
-b Number 从 Number 表示的512字节块位置读取指定文件。
-k Number 从 Number 表示的1KB块位置读取指定文件。
File 指定操作的目标文件名称
上述命令中,都涉及到number,假设不指定,默认显示10行。Number前面可使用正负号,表示该偏移从顶部还是从尾部開始计算。
tail可运行文件一般在/usr/bin/以下。
二、tail命令使用方法演示例子
1、tail -f filename
说明:监视filename文件的尾部内容(默认10行,相当于增加参数 -n 10),刷新显示在屏幕上。退出,按下CTRL+C。
2、tail -n 20 filename
说明:显示filename最后20行。
Share 一篇有观点和思考的技术文章
设计模式走起来。
公众号地址:
设计模式之命令模式(三)