力扣初级算法-06-数组-有效的数独

学习目标:

本次学习目标为 力扣初级算法-数组,其中主要的LC如下:

  • 有效的数独

学习内容:

  1. 有效的数独 -----(链接
    请你判断一个 9x9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。
    数字 1-9 在每一行只能出现一次。
    数字 1-9 在每一列只能出现一次。
    数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
    数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

示例1:
在这里插入图片描述

示例2:
输入:board =
[[“8”,“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”]]
输出:false

解题思路:

  • 解法一:

  • 边界问题:

    • 未输入不分用 “.” 来代替
    • 入参是字符串,故需要转换为 数字来处理
  • 代码逻辑过程:

    • 声明三组二维数组,分别代表 行 line 、列 column 、3*3 cell 三个部分
    • 循环遍历二维数据,根据二维坐标拿到当前循环的元素对应的数值 -num
    • 判断是否重复逻辑
      • 拿当前元素的数值num,作为 line、column、cell 二维数组中的二维的index,在插入之前先判断,当前index 下是否已存在数值,
        • 如果已存在,则表明上述循环的数组元素已出现过,此时可直接 return false
        • 如果不存在,则表明上述循环的数组的元素未出现,则直接在对应的 index 下写入 元素的数值 num
    • 当所有元素都循环完,即可直接return ture
  • 关键点:

    • 将元素的数值转换数组的index,判断元素的index下是否有值来判断是否已写入。
    • 空间换空间
  • 代码实现:

public static boolean isValidSudoku(char[][] board) {
		int length = board.length;
		//二维数组line表示的是对应的行中是否有对应的数字,比如line[0][3]
		//表示的是第0行(实际上是第1行,因为数组的下标是从0开始的)是否有数字3
		int line[][] = new int[length][length];
		int column[][] = new int[length][length];
		int cell[][] = new int[length][length];
		for (int i = 0; i < length; ++i)
			for (int j = 0; j < length; ++j) {
				//如果还没有填数字,直接跳过
				if (board[i][j] == '.')
					continue;
				//num是当前格子的数字
				int num = board[i][j] - '0' - 1;
				//k是第几个单元格,9宫格数独横着和竖着都是3个单元格
				int k = i / 3 * 3 + j / 3;
				//如果当前数字对应的行和列以及单元格,只要一个由数字,说明冲突了,直接返回false。
				//举个例子,如果line[i][num]不等于0,说明第i(i从0开始)行有num这个数字。
				if (line[i][num] != 0 || column[j][num] != 0 || cell[k][num] != 0)
					return false;
				//表示第i行有num这个数字,第j列有num这个数字,对应的单元格内也有num这个数字
				line[i][num] = column[j][num] = cell[k][num] = 1;
			}
		return true;

	}
  • 测试用例:
public static void main(String[] args) {
		char[][] chars = {
				{'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'}
		};

		isValidSudoku(chars);
	}
  • 解法二: 使用hashSet解决

  • 边界问题: 无

  • 代码逻辑过程:

    • 分别先对 行liine 列 column 进行判空(等于 ‘.’),同时写入 Set 为 ture
    • 考虑 3*3 部分
      • 将行超过部分转换到列中
  • 代码实现:

	public static boolean isValidSudoku02(char[][] board) {
		for (int i =0 ; i < 9; i++){
			HashSet<Object> lineSet = new HashSet<>();
			HashSet<Object> columnSet = new HashSet<>();
			HashSet<Object> cellSet = new HashSet<>();

			for (int j = 0; j < 9; j++){

				boolean isNotEmpty = board[i][j] != '.';
				if (isNotEmpty && !lineSet.add(board[i][j])){
					return false;
				}
				if (isNotEmpty && !columnSet.add(board[i][j])){
					return false;
				}
				int a = (i/3)*3 + j/3;
				int b = (i%3)*3 + j%3;
				if (board[a][b] != '.' && cellSet.add(board[a][b])){
					return false;
				}
			}

		}
		return true;

	}

学习笔记:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
力扣一个在线编程平台,提供了大量的算法题目,可以帮助程序员提高算法能力。回溯算法是一种搜索算法,它通过不断地尝试所有可能的解来解问题。在回溯算法中,我们首先定义一个解空间,然后从解空间中搜索所有可能的解,直到找到符合要的解为止。回溯算法通常用于解组合问题、排列问题、子集问题等。 在 Java 中实现回溯算法,通常需要定义一个递归函数来搜索解空间。在递归函数中,我们首先判断当前状态是否符合要,如果符合要,则将当前状态加入到解集中;否则,我们继续搜索下一个状态。在搜索下一个状态时,我们需要对当前状态进行一些修改,然后递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。 以下是回溯算法的一般步骤: 1. 定义解空间:确定问题的解空间,并定义一个数据结构来表示解空间中的每个状态。 2. 确定约束条件:确定哪些状态是合法的,并定义一个函数来判断当前状态是否符合要。 3. 确定搜索策略:确定搜索解空间的顺序,并定义一个函数来生成下一个状态。 4. 搜索解空间:使用递归函数搜索解空间,如果当前状态符合要,则将其加入到解集中;否则,继续搜索下一个状态。 5. 回溯:当搜索完所有可能的状态后,回溯到上一个状态,继续搜索其他可能的状态。 以下是一个力扣题目的回溯算法 Java 实现示例: ``` class Solution { List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); public List<List<Integer>> subsets(int[] nums) { dfs(nums, 0); return res; } private void dfs(int[] nums, int start) { res.add(new ArrayList<>(path)); for (int i = start; i < nums.length; i++) { path.add(nums[i]); dfs(nums, i + 1); path.remove(path.size() - 1); } } } ``` 该算法用于给定数组的所有子集。在递归函数中,我们首先将当前状态加入到解集中,然后从当前位置开始搜索下一个状态。在搜索下一个状态时,我们将当前元素加入到路径中,并递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值