leetcode刷题记录day005:1和36
1、难度简单:强行让你接触哈希表
要求:时间复杂度小于 O(n2) 的算法
方法一:暴力枚举:时间复杂度O(N2),空间复杂度O(1)
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[0];
}
}
上述代码原理:枚举数组中的每一个数 x,寻找数组中是否存在 target - x。
当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x 之前的元素都已经和 x 匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在 x 后面的元素中寻找 target - x
方法二:哈希表:时间复杂度:O(N),空间复杂度O(N)
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>(); //创建哈希表,此时里面是空的
for (int i = 0; i < nums.length; ++i) { //遍历nums数组
if (hashtable.containsKey(target - nums[i])) { //若哈希表中存在数据target - nums[i]那就return结果数组
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i); //没找到答案,那就把当前遍历到的值插入到哈希表中
}
return new int[0]; //如果nums里的元素无法满足我们的要求,那就返回0个元素的数组
}
}
方法一缺陷:寻找 target - x 的时间复杂度过高。
使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N)O(N) 降低到 O(1)O(1)。
这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
36、难度中等:活用哈希表原理
数独:数独是一类经典的推理游戏,在数独当中可以经常看到有很多的数字,独表示的就是唯一不重复, 最常见的数独游戏就是九宫数独,九宫数独要求行不重复、列不重复、(小九)宫(格)不重复。
注意题给数组board的内容格式:

使用哈希表一次遍历:时间复杂度:O(1)、空间复杂度:O(1)
class Solution {
public boolean isValidSudoku(char[][] board) {
int[][] rows = new int[9][9]; //单元格的行数最大为9,元素最大为9。但代码中为 0 ~ 8
int[][] columns = new int[9][9]; //单元格的列数最大为9
int[][][] subboxes = new int[3][3][9]; //该数组表示小九宫格,行列最大为3
//题目传来的数组board的格式为二维数组,每一个元素是一个一维数组,记录数独的每一行。该一维数组的每一项是单元格的数值。
for (int i = 0; i < 9; i++) { //遍历一维数组(也就是数独的每一行)
for (int j = 0; j < 9; j++) { //遍历每一行的每一个元素
char c = board[i][j]; //存储元素内容
if (c != '.') { //如果不是字符.
//index是每个单元格的数值
//将char类型的数字转换成int型的数字:char变量 - '0'即可
//再 -1 是因为数组rows、columns等范围都是0~8,表示1~9的数值范围。
int index = c - '0' - 1;
//更新单元格出现次数
rows[i][index]++;
columns[j][index]++;
subboxes[i / 3][j / 3][index]++;
//如果不符合数独条件,那就返回false
if (rows[i][index] > 1 || columns[j][index] > 1 || subboxes[i / 3][j / 3][index] > 1) {
return false;
}
}
}
}
//若遍历时一次都未出现不符合的条件,那就返回true
return true;
}
}
图片部分是官方描述,文字部分是添加的理解:

数独由3 * 3的小九宫格组成,每个小九宫格又由3 * 3的小单元格组成。所以小九宫格的行数为02(0、1、2共三行),列数为02。所以单元格的行下表整除3就能得到它所在小九宫格的行数,同理得列数。

二维数组rows、columns中的每一项 rows[ i ] [index] 和 columns[ j ] [index] 对应的数值:表示数独的第 i 行第 j 列的单元格所在的行、列中,数字 index+1 出现的次数。其中 0 ≤ index < 9,对应的数字 index+1 满足 1 ≤ index + 1 ≤ 9。
三维数组subboxes中的每一项 subboxes [ i/3 ] [ j/3 ] [ index ] 对应的数值:表示数独的第 i 行第 j 列的单元格所在的小九宫格中,数字index +1 出现的次数。

题目传入的数组char[ ] [ ] board 中每一项元素可能为数字值,也可能为字符. 所以我们需要判断当前board [ i ] [ j ] 是否为数字(也就是是否填入了数字n)若填入了,那就把 rows[ i ] [n-1] 、columns[ j ] [n-1] 、subboxes [ i/3 ] [ j/3 ] [ n-1 ] 各加1,也就是说明当前元素出现了一次。添加完后(也就是更新完后)若计数大于1那就不符合数独条件,返回false。(这一块和哈希表原理相同,三个数组都是空的,遍历传来的数组然后把数据加载到伪哈希表三个数组中)

更多推荐


所有评论(0)